From 35779c6675728fa6f0fd0a21cefb904408509c23 Mon Sep 17 00:00:00 2001 From: Sebastien Bacher Date: Mon, 5 Jul 2021 20:35:03 +0200 Subject: New upstream version 1.32.2 --- src/core/NetworkManagerUtils.c | 270 +- src/core/NetworkManagerUtils.h | 36 +- src/core/devices/adsl/meson.build | 1 - src/core/devices/adsl/nm-atm-manager.c | 4 +- src/core/devices/adsl/nm-device-adsl.c | 10 +- src/core/devices/bluetooth/meson.build | 2 +- src/core/devices/bluetooth/nm-bluez-manager.c | 20 +- src/core/devices/bluetooth/nm-device-bt.c | 18 +- src/core/devices/nm-acd-manager.c | 2 +- src/core/devices/nm-device-6lowpan.c | 2 +- src/core/devices/nm-device-bond.c | 54 +- src/core/devices/nm-device-bridge.c | 18 +- src/core/devices/nm-device-dummy.c | 12 +- src/core/devices/nm-device-ethernet.c | 58 +- src/core/devices/nm-device-factory.c | 4 +- src/core/devices/nm-device-generic.c | 12 +- src/core/devices/nm-device-infiniband.c | 14 +- src/core/devices/nm-device-ip-tunnel.c | 62 +- src/core/devices/nm-device-macsec.c | 66 +- src/core/devices/nm-device-macvlan.c | 18 +- src/core/devices/nm-device-ppp.c | 7 +- src/core/devices/nm-device-private.h | 10 - src/core/devices/nm-device-tun.c | 30 +- src/core/devices/nm-device-utils.c | 356 + src/core/devices/nm-device-utils.h | 98 + src/core/devices/nm-device-veth.c | 10 +- src/core/devices/nm-device-vlan.c | 33 +- src/core/devices/nm-device-vrf.c | 4 +- src/core/devices/nm-device-vxlan.c | 62 +- src/core/devices/nm-device-wireguard.c | 22 +- src/core/devices/nm-device-wpan.c | 4 +- src/core/devices/nm-device.c | 1295 +-- src/core/devices/nm-device.h | 97 +- src/core/devices/nm-lldp-listener.c | 402 +- src/core/devices/nm-lldp-listener.h | 31 +- src/core/devices/ovs/meson.build | 1 - src/core/devices/ovs/nm-device-ovs-bridge.c | 6 +- src/core/devices/ovs/nm-device-ovs-interface.c | 15 +- src/core/devices/ovs/nm-device-ovs-port.c | 4 +- src/core/devices/ovs/nm-ovs-factory.c | 4 +- src/core/devices/ovs/nm-ovsdb.c | 6 +- src/core/devices/team/meson.build | 1 - src/core/devices/team/nm-device-team.c | 32 +- src/core/devices/team/nm-team-factory.c | 4 +- src/core/devices/tests/test-acd.c | 4 +- src/core/devices/tests/test-lldp.c | 66 +- src/core/devices/wifi/meson.build | 2 - src/core/devices/wifi/nm-device-iwd.c | 206 +- src/core/devices/wifi/nm-device-olpc-mesh.c | 32 +- src/core/devices/wifi/nm-device-wifi-p2p.c | 9 +- src/core/devices/wifi/nm-device-wifi.c | 145 +- src/core/devices/wifi/nm-device-wifi.h | 2 +- src/core/devices/wifi/nm-iwd-manager.c | 435 +- src/core/devices/wifi/nm-iwd-manager.h | 1 + src/core/devices/wifi/nm-wifi-ap.c | 153 +- src/core/devices/wifi/nm-wifi-ap.h | 3 +- src/core/devices/wifi/nm-wifi-common.c | 38 +- src/core/devices/wifi/nm-wifi-factory.c | 15 +- src/core/devices/wifi/nm-wifi-p2p-peer.c | 7 +- src/core/devices/wifi/nm-wifi-utils.c | 902 +- src/core/devices/wifi/nm-wifi-utils.h | 9 +- src/core/devices/wifi/tests/test-devices-wifi.c | 58 +- src/core/devices/wwan/meson.build | 2 - src/core/devices/wwan/nm-device-modem.c | 17 +- src/core/devices/wwan/nm-modem-broadband.c | 14 +- src/core/devices/wwan/nm-modem-manager.c | 2 +- src/core/devices/wwan/nm-modem-ofono.c | 172 +- src/core/devices/wwan/nm-modem-ofono.h | 2 + src/core/devices/wwan/nm-modem.c | 13 +- src/core/devices/wwan/nm-wwan-factory.c | 2 +- src/core/dhcp/meson.build | 7 +- src/core/dhcp/nm-dhcp-client.c | 167 +- src/core/dhcp/nm-dhcp-client.h | 31 +- src/core/dhcp/nm-dhcp-dhclient-utils.c | 13 +- src/core/dhcp/nm-dhcp-dhclient.c | 56 +- src/core/dhcp/nm-dhcp-dhcpcanon.c | 5 +- src/core/dhcp/nm-dhcp-dhcpcd.c | 49 +- src/core/dhcp/nm-dhcp-helper.c | 10 +- src/core/dhcp/nm-dhcp-listener.c | 2 +- src/core/dhcp/nm-dhcp-manager.c | 107 +- src/core/dhcp/nm-dhcp-manager.h | 7 +- src/core/dhcp/nm-dhcp-nettools.c | 60 +- src/core/dhcp/nm-dhcp-options.c | 2 +- src/core/dhcp/nm-dhcp-systemd.c | 130 +- src/core/dhcp/nm-dhcp-utils.c | 16 +- src/core/dhcp/tests/test-dhcp-dhclient.c | 4 +- src/core/dhcp/tests/test-dhcp-utils.c | 4 +- src/core/dns/nm-dns-dnsmasq.c | 6 +- src/core/dns/nm-dns-dnsmasq.h | 1 + src/core/dns/nm-dns-manager.c | 168 +- src/core/dns/nm-dns-manager.h | 3 +- src/core/dns/nm-dns-plugin.c | 2 +- src/core/dns/nm-dns-plugin.h | 3 +- src/core/dns/nm-dns-systemd-resolved.c | 465 +- src/core/dns/nm-dns-systemd-resolved.h | 31 + src/core/dnsmasq/nm-dnsmasq-manager.c | 2 +- src/core/dnsmasq/nm-dnsmasq-utils.c | 5 +- src/core/dnsmasq/nm-dnsmasq-utils.h | 2 +- src/core/initrd/meson.build | 31 - src/core/initrd/nm-initrd-generator.c | 226 - src/core/initrd/nm-initrd-generator.h | 45 - src/core/initrd/nmi-cmdline-reader.c | 1269 --- src/core/initrd/nmi-dt-reader.c | 371 - src/core/initrd/nmi-ibft-reader.c | 463 - src/core/initrd/tests/meson.build | 24 - .../tests/sysfs-bad-dns1/class/net/eth0/address | 1 - .../sysfs-bad-dns1/firmware/ibft/ethernet0/gateway | 1 - .../sysfs-bad-dns1/firmware/ibft/ethernet0/index | 1 - .../sysfs-bad-dns1/firmware/ibft/ethernet0/ip-addr | 1 - .../sysfs-bad-dns1/firmware/ibft/ethernet0/mac | 1 - .../sysfs-bad-dns1/firmware/ibft/ethernet0/origin | 1 - .../firmware/ibft/ethernet0/prefix-len | 1 - .../firmware/ibft/ethernet0/primary-dns | 1 - .../firmware/ibft/ethernet0/secondary-dns | 1 - .../firmware/ibft/ethernet0/subnet-mask | 1 - .../sysfs-bad-dns1/firmware/ibft/ethernet0/vlan | 1 - .../firmware/ibft/initiator/initiator-name | 1 - .../sysfs-bad-dns1/firmware/ibft/target0/index | 1 - .../sysfs-bad-dns1/firmware/ibft/target0/ip-addr | 1 - .../tests/sysfs-bad-dns1/firmware/ibft/target0/lun | 1 - .../sysfs-bad-dns1/firmware/ibft/target0/port | 1 - .../firmware/ibft/target0/target-name | 1 - .../tests/sysfs-bad-dns2/class/net/eth0/address | 1 - .../sysfs-bad-dns2/firmware/ibft/ethernet0/gateway | 1 - .../sysfs-bad-dns2/firmware/ibft/ethernet0/index | 1 - .../sysfs-bad-dns2/firmware/ibft/ethernet0/ip-addr | 1 - .../sysfs-bad-dns2/firmware/ibft/ethernet0/mac | 1 - .../sysfs-bad-dns2/firmware/ibft/ethernet0/origin | 1 - .../firmware/ibft/ethernet0/prefix-len | 1 - .../firmware/ibft/ethernet0/primary-dns | 1 - .../firmware/ibft/ethernet0/secondary-dns | 1 - .../firmware/ibft/ethernet0/subnet-mask | 1 - .../sysfs-bad-dns2/firmware/ibft/ethernet0/vlan | 1 - .../firmware/ibft/initiator/initiator-name | 1 - .../sysfs-bad-dns2/firmware/ibft/target0/index | 1 - .../sysfs-bad-dns2/firmware/ibft/target0/ip-addr | 1 - .../tests/sysfs-bad-dns2/firmware/ibft/target0/lun | 1 - .../sysfs-bad-dns2/firmware/ibft/target0/port | 1 - .../firmware/ibft/target0/target-name | 1 - .../tests/sysfs-bad-gateway/class/net/eth0/address | 1 - .../firmware/ibft/ethernet0/gateway | 1 - .../firmware/ibft/ethernet0/index | 1 - .../firmware/ibft/ethernet0/ip-addr | 1 - .../sysfs-bad-gateway/firmware/ibft/ethernet0/mac | 1 - .../firmware/ibft/ethernet0/origin | 1 - .../firmware/ibft/ethernet0/prefix-len | 1 - .../firmware/ibft/ethernet0/primary-dns | 1 - .../firmware/ibft/ethernet0/secondary-dns | 1 - .../firmware/ibft/ethernet0/subnet-mask | 1 - .../sysfs-bad-gateway/firmware/ibft/ethernet0/vlan | 1 - .../firmware/ibft/initiator/initiator-name | 1 - .../sysfs-bad-gateway/firmware/ibft/target0/index | 1 - .../firmware/ibft/target0/ip-addr | 1 - .../sysfs-bad-gateway/firmware/ibft/target0/lun | 1 - .../sysfs-bad-gateway/firmware/ibft/target0/port | 1 - .../firmware/ibft/target0/target-name | 1 - .../tests/sysfs-bad-ipaddr/class/net/eth0/address | 1 - .../firmware/ibft/ethernet0/gateway | 1 - .../sysfs-bad-ipaddr/firmware/ibft/ethernet0/index | 1 - .../firmware/ibft/ethernet0/ip-addr | 1 - .../sysfs-bad-ipaddr/firmware/ibft/ethernet0/mac | 1 - .../firmware/ibft/ethernet0/origin | 1 - .../firmware/ibft/ethernet0/prefix-len | 1 - .../firmware/ibft/ethernet0/primary-dns | 1 - .../firmware/ibft/ethernet0/secondary-dns | 1 - .../firmware/ibft/ethernet0/subnet-mask | 1 - .../sysfs-bad-ipaddr/firmware/ibft/ethernet0/vlan | 1 - .../firmware/ibft/initiator/initiator-name | 1 - .../sysfs-bad-ipaddr/firmware/ibft/target0/index | 1 - .../sysfs-bad-ipaddr/firmware/ibft/target0/ip-addr | 1 - .../sysfs-bad-ipaddr/firmware/ibft/target0/lun | 1 - .../sysfs-bad-ipaddr/firmware/ibft/target0/port | 1 - .../firmware/ibft/target0/target-name | 1 - .../initrd/tests/sysfs-dhcp/class/net/eth0/address | 1 - .../initrd/tests/sysfs-dhcp/class/net/eth1/address | 1 - .../sysfs-dhcp/firmware/ibft/ethernet0/gateway | 1 - .../tests/sysfs-dhcp/firmware/ibft/ethernet0/index | 1 - .../tests/sysfs-dhcp/firmware/ibft/ethernet0/mac | 1 - .../sysfs-dhcp/firmware/ibft/ethernet0/origin | 1 - .../sysfs-dhcp/firmware/ibft/ethernet0/primary-dns | 1 - .../firmware/ibft/ethernet0/secondary-dns | 1 - .../tests/sysfs-dhcp/firmware/ibft/ethernet0/vlan | 1 - .../sysfs-dhcp/firmware/ibft/ethernet1/gateway | 1 - .../tests/sysfs-dhcp/firmware/ibft/ethernet1/index | 1 - .../tests/sysfs-dhcp/firmware/ibft/ethernet1/mac | 1 - .../sysfs-dhcp/firmware/ibft/ethernet1/origin | 1 - .../sysfs-dhcp/firmware/ibft/ethernet1/primary-dns | 1 - .../firmware/ibft/ethernet1/secondary-dns | 1 - .../tests/sysfs-dhcp/firmware/ibft/ethernet1/vlan | 1 - .../firmware/ibft/initiator/initiator-name | 1 - .../tests/sysfs-dhcp/firmware/ibft/target0/index | 1 - .../tests/sysfs-dhcp/firmware/ibft/target0/ip-addr | 1 - .../tests/sysfs-dhcp/firmware/ibft/target0/lun | 1 - .../tests/sysfs-dhcp/firmware/ibft/target0/port | 1 - .../sysfs-dhcp/firmware/ibft/target0/target-name | 1 - .../tests/sysfs-dhcp/firmware/ibft/target1/index | 1 - .../tests/sysfs-dhcp/firmware/ibft/target1/ip-addr | 1 - .../tests/sysfs-dhcp/firmware/ibft/target1/lun | 1 - .../tests/sysfs-dhcp/firmware/ibft/target1/port | 1 - .../sysfs-dhcp/firmware/ibft/target1/target-name | 1 - .../firmware/devicetree/base/chosen/bootpath | Bin 108 -> 0 bytes .../firmware/devicetree/base/chosen/bootp-request | Bin 273 -> 0 bytes .../firmware/devicetree/base/chosen/bootp-response | Bin 300 -> 0 bytes .../firmware/devicetree/base/chosen/bootpath | Bin 37 -> 0 bytes .../firmware/devicetree/base/chosen/broadcast-ip | 1 - .../firmware/devicetree/base/chosen/client-ip | 2 - .../firmware/devicetree/base/chosen/client-name | Bin 9 -> 0 bytes .../firmware/devicetree/base/chosen/domain-name | Bin 15 -> 0 bytes .../firmware/devicetree/base/chosen/gateway-ip | 2 - .../sysfs-dt/firmware/devicetree/base/chosen/name | Bin 7 -> 0 bytes .../firmware/devicetree/base/chosen/netmask-ip | Bin 4 -> 0 bytes .../firmware/devicetree/base/chosen/root-path | Bin 1 -> 0 bytes .../firmware/devicetree/base/chosen/server-ip | 2 - .../firmware/devicetree/base/chosen/tftp-file | Bin 11 -> 0 bytes .../firmware/devicetree/base/chosen/vendor-options | Bin 1 -> 0 bytes .../firmware/devicetree/base/ethernet/device_type | Bin 8 -> 0 bytes .../devicetree/base/ethernet/local-mac-address | 1 - .../firmware/devicetree/base/ethernet/mac-address | 1 - .../firmware/devicetree/base/ethernet/name | Bin 9 -> 0 bytes .../tests/sysfs-static/class/net/eth0/address | 1 - .../tests/sysfs-static/class/net/eth1/address | 1 - .../sysfs-static/firmware/ibft/ethernet0/gateway | 1 - .../sysfs-static/firmware/ibft/ethernet0/index | 1 - .../sysfs-static/firmware/ibft/ethernet0/ip-addr | 1 - .../tests/sysfs-static/firmware/ibft/ethernet0/mac | 1 - .../sysfs-static/firmware/ibft/ethernet0/origin | 1 - .../firmware/ibft/ethernet0/prefix-len | 1 - .../firmware/ibft/ethernet0/primary-dns | 1 - .../firmware/ibft/ethernet0/secondary-dns | 1 - .../firmware/ibft/ethernet0/subnet-mask | 1 - .../sysfs-static/firmware/ibft/ethernet0/vlan | 1 - .../sysfs-static/firmware/ibft/ethernet1/gateway | 1 - .../sysfs-static/firmware/ibft/ethernet1/index | 1 - .../tests/sysfs-static/firmware/ibft/ethernet1/mac | 1 - .../sysfs-static/firmware/ibft/ethernet1/origin | 1 - .../firmware/ibft/ethernet1/primary-dns | 1 - .../firmware/ibft/ethernet1/secondary-dns | 1 - .../sysfs-static/firmware/ibft/ethernet1/vlan | 1 - .../firmware/ibft/initiator/initiator-name | 1 - .../tests/sysfs-static/firmware/ibft/target0/index | 1 - .../sysfs-static/firmware/ibft/target0/ip-addr | 1 - .../tests/sysfs-static/firmware/ibft/target0/lun | 1 - .../tests/sysfs-static/firmware/ibft/target0/port | 1 - .../sysfs-static/firmware/ibft/target0/target-name | 1 - .../tests/sysfs-static/firmware/ibft/target1/index | 1 - .../sysfs-static/firmware/ibft/target1/ip-addr | 1 - .../tests/sysfs-static/firmware/ibft/target1/lun | 1 - .../tests/sysfs-static/firmware/ibft/target1/port | 1 - .../sysfs-static/firmware/ibft/target1/target-name | 1 - .../initrd/tests/sysfs-vlan/class/net/eth0/address | 1 - .../tests/sysfs-vlan/firmware/ibft/ethernet0/index | 1 - .../sysfs-vlan/firmware/ibft/ethernet0/ip-addr | 1 - .../tests/sysfs-vlan/firmware/ibft/ethernet0/mac | 1 - .../sysfs-vlan/firmware/ibft/ethernet0/origin | 1 - .../sysfs-vlan/firmware/ibft/ethernet0/prefix-len | 1 - .../sysfs-vlan/firmware/ibft/ethernet0/subnet-mask | 1 - .../tests/sysfs-vlan/firmware/ibft/ethernet0/vlan | 1 - .../firmware/ibft/initiator/initiator-name | 1 - .../tests/sysfs-vlan/firmware/ibft/target0/index | 1 - .../tests/sysfs-vlan/firmware/ibft/target0/ip-addr | 1 - .../tests/sysfs-vlan/firmware/ibft/target0/lun | 1 - .../tests/sysfs-vlan/firmware/ibft/target0/port | 1 - .../sysfs-vlan/firmware/ibft/target0/target-name | 1 - src/core/initrd/tests/sysfs/class/net/eth0/address | 1 - src/core/initrd/tests/sysfs/class/net/eth2/address | 1 - .../tests/sysfs/firmware/ibft/acpi_header/oem_id | 1 - .../sysfs/firmware/ibft/acpi_header/oem_table_id | 1 - .../sysfs/firmware/ibft/acpi_header/signature | 1 - .../tests/sysfs/firmware/ibft/ethernet0/dhcp | 1 - .../tests/sysfs/firmware/ibft/ethernet0/flags | 1 - .../tests/sysfs/firmware/ibft/ethernet0/gateway | 1 - .../tests/sysfs/firmware/ibft/ethernet0/hostname | 1 - .../tests/sysfs/firmware/ibft/ethernet0/index | 1 - .../tests/sysfs/firmware/ibft/ethernet0/ip-addr | 1 - .../initrd/tests/sysfs/firmware/ibft/ethernet0/mac | 1 - .../tests/sysfs/firmware/ibft/ethernet0/origin | 1 - .../tests/sysfs/firmware/ibft/ethernet0/prefix-len | 1 - .../sysfs/firmware/ibft/ethernet0/primary-dns | 1 - .../sysfs/firmware/ibft/ethernet0/secondary-dns | 1 - .../sysfs/firmware/ibft/ethernet0/subnet-mask | 1 - .../tests/sysfs/firmware/ibft/ethernet0/vlan | 1 - .../tests/sysfs/firmware/ibft/ethernet2/dhcp | 1 - .../tests/sysfs/firmware/ibft/ethernet2/flags | 1 - .../tests/sysfs/firmware/ibft/ethernet2/gateway | 1 - .../tests/sysfs/firmware/ibft/ethernet2/hostname | 1 - .../tests/sysfs/firmware/ibft/ethernet2/index | 1 - .../tests/sysfs/firmware/ibft/ethernet2/ip-addr | 1 - .../initrd/tests/sysfs/firmware/ibft/ethernet2/mac | 1 - .../tests/sysfs/firmware/ibft/ethernet2/origin | 1 - .../tests/sysfs/firmware/ibft/ethernet2/prefix-len | 1 - .../sysfs/firmware/ibft/ethernet2/primary-dns | 1 - .../sysfs/firmware/ibft/ethernet2/secondary-dns | 1 - .../sysfs/firmware/ibft/ethernet2/subnet-mask | 1 - .../tests/sysfs/firmware/ibft/ethernet2/vlan | 1 - .../tests/sysfs/firmware/ibft/initiator/flags | 1 - .../tests/sysfs/firmware/ibft/initiator/index | 1 - .../sysfs/firmware/ibft/initiator/initiator-name | 1 - .../sysfs/firmware/ibft/initiator/isns-server | 1 - .../firmware/ibft/initiator/pri-radius-server | 1 - .../firmware/ibft/initiator/sec-radius-server | 1 - .../tests/sysfs/firmware/ibft/initiator/slp-server | 1 - .../tests/sysfs/firmware/ibft/target0/chap-type | 1 - .../initrd/tests/sysfs/firmware/ibft/target0/flags | 1 - .../initrd/tests/sysfs/firmware/ibft/target0/index | 1 - .../tests/sysfs/firmware/ibft/target0/ip-addr | 1 - .../initrd/tests/sysfs/firmware/ibft/target0/lun | 1 - .../tests/sysfs/firmware/ibft/target0/nic-assoc | 1 - .../initrd/tests/sysfs/firmware/ibft/target0/port | 1 - .../tests/sysfs/firmware/ibft/target2/chap-type | 1 - .../initrd/tests/sysfs/firmware/ibft/target2/flags | 1 - .../initrd/tests/sysfs/firmware/ibft/target2/index | 1 - .../tests/sysfs/firmware/ibft/target2/ip-addr | 1 - .../initrd/tests/sysfs/firmware/ibft/target2/lun | 1 - .../tests/sysfs/firmware/ibft/target2/nic-assoc | 1 - .../initrd/tests/sysfs/firmware/ibft/target2/port | 1 - .../tests/sysfs/firmware/ibft/target2/target-name | 1 - src/core/initrd/tests/test-cmdline-reader.c | 2182 ----- src/core/initrd/tests/test-dt-reader.c | 144 - src/core/initrd/tests/test-ibft-reader.c | 303 - src/core/main.c | 9 +- src/core/meson.build | 138 +- src/core/ndisc/nm-lndp-ndisc.c | 24 +- src/core/ndisc/nm-ndisc.c | 8 +- src/core/ndisc/nm-ndisc.h | 14 +- src/core/ndisc/tests/test-ndisc-linux.c | 2 +- src/core/nm-act-request.c | 34 +- src/core/nm-act-request.h | 6 +- src/core/nm-active-connection.c | 99 +- src/core/nm-audit-manager.c | 155 +- src/core/nm-auth-manager.c | 4 +- src/core/nm-auth-manager.h | 2 +- src/core/nm-auth-utils.c | 4 +- src/core/nm-checkpoint.c | 34 +- src/core/nm-config-data.c | 220 +- src/core/nm-config-data.h | 118 +- src/core/nm-config.c | 20 +- src/core/nm-config.h | 80 +- src/core/nm-connectivity.c | 8 +- src/core/nm-connectivity.h | 1 + src/core/nm-core-utils.c | 845 +- src/core/nm-core-utils.h | 185 +- src/core/nm-dbus-manager.c | 91 +- src/core/nm-dbus-object.c | 10 +- src/core/nm-dbus-object.h | 15 +- src/core/nm-dbus-utils.c | 4 - src/core/nm-dbus-utils.h | 118 +- src/core/nm-dcb.c | 2 +- src/core/nm-default-daemon.h | 4 +- src/core/nm-dhcp-config.c | 34 +- src/core/nm-dispatcher.c | 24 +- src/core/nm-firewall-manager.c | 623 -- src/core/nm-firewall-manager.h | 54 - src/core/nm-firewall-utils.c | 816 ++ src/core/nm-firewall-utils.h | 29 + src/core/nm-firewalld-manager.c | 623 ++ src/core/nm-firewalld-manager.h | 54 + src/core/nm-hostname-manager.c | 6 +- src/core/nm-iface-helper.c | 11 +- src/core/nm-ip4-config.c | 119 +- src/core/nm-ip4-config.h | 7 +- src/core/nm-ip6-config.c | 125 +- src/core/nm-ip6-config.h | 6 +- src/core/nm-keep-alive.c | 2 +- src/core/nm-l3-config-data.c | 342 +- src/core/nm-l3-config-data.h | 73 +- src/core/nm-l3cfg.c | 75 +- src/core/nm-l3cfg.h | 25 +- src/core/nm-manager.c | 416 +- src/core/nm-netns.c | 16 +- src/core/nm-netns.h | 10 +- src/core/nm-pacrunner-manager.c | 5 +- src/core/nm-policy.c | 38 +- src/core/nm-proxy-config.c | 2 +- src/core/nm-proxy-config.h | 3 +- src/core/nm-rfkill-manager.c | 2 +- src/core/nm-sleep-monitor.c | 4 +- src/core/nm-test-utils-core.h | 38 +- src/core/nm-types.h | 163 - src/core/platform/linux/nl802154.h | 450 - src/core/platform/nm-fake-platform.c | 116 +- src/core/platform/nm-fake-platform.h | 2 +- src/core/platform/nm-linux-platform.c | 9696 -------------------- src/core/platform/nm-linux-platform.h | 30 - src/core/platform/nm-platform-private.h | 29 - src/core/platform/nm-platform.c | 8966 ------------------ src/core/platform/nm-platform.h | 2372 ----- src/core/platform/nmp-object.c | 3457 ------- src/core/platform/nmp-object.h | 1144 --- src/core/platform/nmp-rules-manager.c | 808 -- src/core/platform/nmp-rules-manager.h | 53 - src/core/platform/tests/monitor.c | 2 +- src/core/platform/tests/test-address.c | 6 +- src/core/platform/tests/test-cleanup.c | 9 +- src/core/platform/tests/test-common.c | 47 +- src/core/platform/tests/test-common.h | 31 +- src/core/platform/tests/test-link.c | 114 +- src/core/platform/tests/test-nmp-object.c | 4 +- src/core/platform/tests/test-platform-general.c | 10 +- src/core/platform/tests/test-route.c | 4 +- src/core/platform/tests/test-tc.c | 6 +- src/core/platform/wifi/nm-wifi-utils-nl80211.c | 909 -- src/core/platform/wifi/nm-wifi-utils-nl80211.h | 29 - src/core/platform/wifi/nm-wifi-utils-private.h | 66 - src/core/platform/wifi/nm-wifi-utils-wext.c | 836 -- src/core/platform/wifi/nm-wifi-utils-wext.h | 28 - src/core/platform/wifi/nm-wifi-utils.c | 211 - src/core/platform/wifi/nm-wifi-utils.h | 74 - src/core/platform/wpan/nm-wpan-utils.c | 286 - src/core/platform/wpan/nm-wpan-utils.h | 37 - src/core/ppp/meson.build | 17 +- src/core/ppp/nm-ppp-manager-call.c | 47 +- src/core/ppp/nm-ppp-manager.c | 13 +- src/core/ppp/nm-pppd-plugin.c | 20 +- src/core/settings/nm-agent-manager.c | 4 +- src/core/settings/nm-secret-agent.c | 10 +- src/core/settings/nm-settings-connection.c | 325 +- src/core/settings/nm-settings-connection.h | 10 +- src/core/settings/nm-settings-plugin.c | 2 +- src/core/settings/nm-settings-storage.c | 5 +- src/core/settings/nm-settings-storage.h | 15 +- src/core/settings/nm-settings.c | 187 +- src/core/settings/nm-settings.h | 5 + src/core/settings/plugins/ifcfg-rh/meson.build | 2 - .../plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c | 10 +- .../plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 65 +- .../plugins/ifcfg-rh/nms-ifcfg-rh-storage.c | 5 +- .../settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c | 19 +- .../settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h | 4 +- .../plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 218 +- src/core/settings/plugins/ifcfg-rh/shvar.c | 127 +- .../ifcfg-System_test-bridge-component-a.cexpected | 2 +- .../ifcfg-System_test-bridge-component-b.cexpected | 2 +- ...System_test-wired-802-1X-subj-matches.cexpected | 2 +- .../ifcfg-Test_Write_Bridge_Component.cexpected | 2 +- .../ifcfg-Test_Write_Wired_Static_Routes.cexpected | 2 +- .../ifcfg-test-static-routes-legacy.cexpected | 2 +- .../ifcfg-test-tc-write-empty.cexpected | 15 + .../network-scripts/ifcfg-test-vlan-vlanid-use | 4 + .../ifcfg-test-vlan-vlanid-use.cexpected | 15 + .../ifcfg-test_roundtrip_ethtool-1.cexpected | 14 + .../ifcfg-test_roundtrip_ethtool-2.cexpected | 15 + .../ifcfg-test_roundtrip_ethtool-3.cexpected | 15 + .../ifcfg-test_roundtrip_ethtool-4.cexpected | 15 + .../ifcfg-test_roundtrip_ethtool-5.cexpected | 15 + .../plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 354 +- src/core/settings/plugins/ifupdown/meson.build | 2 - .../plugins/ifupdown/nms-ifupdown-parser.c | 26 +- .../plugins/ifupdown/nms-ifupdown-plugin.c | 2 +- .../plugins/ifupdown/tests/test-ifupdown.c | 2 +- .../settings/plugins/keyfile/nms-keyfile-plugin.c | 28 +- .../settings/plugins/keyfile/nms-keyfile-reader.c | 2 +- .../settings/plugins/keyfile/nms-keyfile-storage.c | 7 +- .../settings/plugins/keyfile/nms-keyfile-utils.c | 38 +- .../settings/plugins/keyfile/nms-keyfile-writer.c | 9 +- .../plugins/keyfile/tests/test-keyfile-settings.c | 5 +- src/core/supplicant/nm-supplicant-config.c | 174 +- src/core/supplicant/nm-supplicant-interface.c | 200 +- src/core/supplicant/nm-supplicant-manager.c | 41 +- .../supplicant/nm-supplicant-settings-verify.c | 1 + src/core/supplicant/nm-supplicant-types.h | 26 +- src/core/supplicant/tests/test-supplicant-config.c | 39 +- src/core/systemd/meson.build | 62 - src/core/systemd/nm-default-systemd.h | 18 - src/core/systemd/nm-sd-utils-core.c | 27 - src/core/systemd/nm-sd-utils-core.h | 17 - src/core/systemd/nm-sd-utils-dhcp.c | 41 - src/core/systemd/nm-sd-utils-dhcp.h | 19 - src/core/systemd/nm-sd.c | 113 - src/core/systemd/nm-sd.h | 29 - src/core/systemd/sd-adapt-core/condition.h | 5 - src/core/systemd/sd-adapt-core/conf-parser.h | 3 - src/core/systemd/sd-adapt-core/device-util.h | 3 - src/core/systemd/sd-adapt-core/khash.h | 3 - src/core/systemd/sd-adapt-core/network-util.h | 3 - src/core/systemd/sd-adapt-core/nm-sd-adapt-core.c | 21 - src/core/systemd/sd-adapt-core/nm-sd-adapt-core.h | 88 - src/core/systemd/sd-adapt-core/sd-daemon.h | 3 - src/core/systemd/sd-adapt-core/sd-device.h | 3 - src/core/systemd/sd-adapt-core/udev-util.h | 3 - src/core/systemd/src/libsystemd-network/arp-util.c | 140 - src/core/systemd/src/libsystemd-network/arp-util.h | 18 - .../src/libsystemd-network/dhcp-identifier.c | 228 - .../src/libsystemd-network/dhcp-identifier.h | 62 - .../systemd/src/libsystemd-network/dhcp-internal.h | 69 - .../src/libsystemd-network/dhcp-lease-internal.h | 84 - .../systemd/src/libsystemd-network/dhcp-network.c | 246 - .../systemd/src/libsystemd-network/dhcp-option.c | 358 - .../systemd/src/libsystemd-network/dhcp-packet.c | 173 - .../systemd/src/libsystemd-network/dhcp-protocol.h | 99 - .../src/libsystemd-network/dhcp6-internal.h | 123 - .../src/libsystemd-network/dhcp6-lease-internal.h | 63 - .../systemd/src/libsystemd-network/dhcp6-network.c | 76 - .../systemd/src/libsystemd-network/dhcp6-option.c | 795 -- .../src/libsystemd-network/dhcp6-protocol.h | 120 - .../systemd/src/libsystemd-network/lldp-internal.h | 39 - .../systemd/src/libsystemd-network/lldp-neighbor.c | 794 -- .../systemd/src/libsystemd-network/lldp-neighbor.h | 92 - .../systemd/src/libsystemd-network/lldp-network.c | 80 - .../systemd/src/libsystemd-network/lldp-network.h | 6 - .../src/libsystemd-network/network-internal.c | 245 - .../src/libsystemd-network/network-internal.h | 31 - .../src/libsystemd-network/sd-dhcp-client.c | 2258 ----- .../systemd/src/libsystemd-network/sd-dhcp-lease.c | 1401 --- .../src/libsystemd-network/sd-dhcp6-client.c | 1857 ---- .../src/libsystemd-network/sd-dhcp6-lease.c | 435 - .../systemd/src/libsystemd-network/sd-ipv4acd.c | 543 -- .../systemd/src/libsystemd-network/sd-ipv4ll.c | 342 - src/core/systemd/src/libsystemd-network/sd-lldp.c | 500 - .../systemd/src/libsystemd/sd-event/event-source.h | 220 - .../systemd/src/libsystemd/sd-event/event-util.c | 101 - .../systemd/src/libsystemd/sd-event/event-util.h | 13 - .../systemd/src/libsystemd/sd-event/sd-event.c | 4329 --------- .../systemd/src/libsystemd/sd-id128/id128-util.c | 218 - .../systemd/src/libsystemd/sd-id128/id128-util.h | 38 - .../systemd/src/libsystemd/sd-id128/sd-id128.c | 330 - src/core/systemd/src/systemd/_sd-common.h | 102 - src/core/systemd/src/systemd/sd-dhcp-client.h | 224 - src/core/systemd/src/systemd/sd-dhcp-lease.h | 82 - src/core/systemd/src/systemd/sd-dhcp-option.h | 38 - src/core/systemd/src/systemd/sd-dhcp6-client.h | 180 - src/core/systemd/src/systemd/sd-dhcp6-lease.h | 55 - src/core/systemd/src/systemd/sd-dhcp6-option.h | 37 - src/core/systemd/src/systemd/sd-event.h | 176 - src/core/systemd/src/systemd/sd-id128.h | 124 - src/core/systemd/src/systemd/sd-ipv4acd.h | 60 - src/core/systemd/src/systemd/sd-ipv4ll.h | 62 - src/core/systemd/src/systemd/sd-lldp.h | 194 - src/core/systemd/src/systemd/sd-ndisc.h | 131 - src/core/tests/config/test-config.c | 100 +- src/core/tests/meson.build | 12 +- src/core/tests/test-core-with-expect.c | 7 +- src/core/tests/test-core.c | 30 +- src/core/tests/test-ip4-config.c | 2 +- src/core/tests/test-ip6-config.c | 2 +- src/core/tests/test-l3cfg.c | 12 +- src/core/tests/test-systemd.c | 140 +- src/core/vpn/nm-vpn-connection.c | 78 +- src/core/vpn/nm-vpn-connection.h | 2 +- src/core/vpn/nm-vpn-manager.c | 2 +- 539 files changed, 9562 insertions(+), 59439 deletions(-) create mode 100644 src/core/devices/nm-device-utils.c create mode 100644 src/core/devices/nm-device-utils.h delete mode 100644 src/core/initrd/meson.build delete mode 100644 src/core/initrd/nm-initrd-generator.c delete mode 100644 src/core/initrd/nm-initrd-generator.h delete mode 100644 src/core/initrd/nmi-cmdline-reader.c delete mode 100644 src/core/initrd/nmi-dt-reader.c delete mode 100644 src/core/initrd/nmi-ibft-reader.c delete mode 100644 src/core/initrd/tests/meson.build delete mode 100644 src/core/initrd/tests/sysfs-bad-dns1/class/net/eth0/address delete mode 100644 src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/gateway delete mode 100644 src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/index delete mode 100644 src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/ip-addr delete mode 100644 src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/mac delete mode 100644 src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/origin delete mode 100644 src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/prefix-len delete mode 100644 src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/primary-dns delete mode 100644 src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/secondary-dns delete mode 100644 src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/subnet-mask delete mode 100644 src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/vlan delete mode 100644 src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/initiator/initiator-name delete mode 100644 src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/index delete mode 100644 src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/ip-addr delete mode 100644 src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/lun delete mode 100644 src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/port delete mode 100644 src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/target-name delete mode 100644 src/core/initrd/tests/sysfs-bad-dns2/class/net/eth0/address delete mode 100644 src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/gateway delete mode 100644 src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/index delete mode 100644 src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/ip-addr delete mode 100644 src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/mac delete mode 100644 src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/origin delete mode 100644 src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/prefix-len delete mode 100644 src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/primary-dns delete mode 100644 src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/secondary-dns delete mode 100644 src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/subnet-mask delete mode 100644 src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/vlan delete mode 100644 src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/initiator/initiator-name delete mode 100644 src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/index delete mode 100644 src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/ip-addr delete mode 100644 src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/lun delete mode 100644 src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/port delete mode 100644 src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/target-name delete mode 100644 src/core/initrd/tests/sysfs-bad-gateway/class/net/eth0/address delete mode 100644 src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/gateway delete mode 100644 src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/index delete mode 100644 src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/ip-addr delete mode 100644 src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/mac delete mode 100644 src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/origin delete mode 100644 src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/prefix-len delete mode 100644 src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/primary-dns delete mode 100644 src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/secondary-dns delete mode 100644 src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/subnet-mask delete mode 100644 src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/vlan delete mode 100644 src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/initiator/initiator-name delete mode 100644 src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/index delete mode 100644 src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/ip-addr delete mode 100644 src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/lun delete mode 100644 src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/port delete mode 100644 src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/target-name delete mode 100644 src/core/initrd/tests/sysfs-bad-ipaddr/class/net/eth0/address delete mode 100644 src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/gateway delete mode 100644 src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/index delete mode 100644 src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/ip-addr delete mode 100644 src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/mac delete mode 100644 src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/origin delete mode 100644 src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/prefix-len delete mode 100644 src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/primary-dns delete mode 100644 src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/secondary-dns delete mode 100644 src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/subnet-mask delete mode 100644 src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/vlan delete mode 100644 src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/initiator/initiator-name delete mode 100644 src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/index delete mode 100644 src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/ip-addr delete mode 100644 src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/lun delete mode 100644 src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/port delete mode 100644 src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/target-name delete mode 100644 src/core/initrd/tests/sysfs-dhcp/class/net/eth0/address delete mode 100644 src/core/initrd/tests/sysfs-dhcp/class/net/eth1/address delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/gateway delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/index delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/mac delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/origin delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/primary-dns delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/secondary-dns delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/vlan delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/gateway delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/index delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/mac delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/origin delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/primary-dns delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/secondary-dns delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/vlan delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/initiator/initiator-name delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target0/index delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target0/ip-addr delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target0/lun delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target0/port delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target0/target-name delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target1/index delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target1/ip-addr delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target1/lun delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target1/port delete mode 100644 src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target1/target-name delete mode 100644 src/core/initrd/tests/sysfs-dt-tftp/firmware/devicetree/base/chosen/bootpath delete mode 100644 src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/bootp-request delete mode 100644 src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/bootp-response delete mode 100644 src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/bootpath delete mode 100644 src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/broadcast-ip delete mode 100644 src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/client-ip delete mode 100644 src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/client-name delete mode 100644 src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/domain-name delete mode 100644 src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/gateway-ip delete mode 100644 src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/name delete mode 100644 src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/netmask-ip delete mode 100644 src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/root-path delete mode 100644 src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/server-ip delete mode 100644 src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/tftp-file delete mode 100644 src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/vendor-options delete mode 100644 src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/ethernet/device_type delete mode 100644 src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/ethernet/local-mac-address delete mode 100644 src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/ethernet/mac-address delete mode 100644 src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/ethernet/name delete mode 100644 src/core/initrd/tests/sysfs-static/class/net/eth0/address delete mode 100644 src/core/initrd/tests/sysfs-static/class/net/eth1/address delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/gateway delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/index delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/ip-addr delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/mac delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/origin delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/prefix-len delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/primary-dns delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/secondary-dns delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/subnet-mask delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/vlan delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/gateway delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/index delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/mac delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/origin delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/primary-dns delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/secondary-dns delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/vlan delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/initiator/initiator-name delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/target0/index delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/target0/ip-addr delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/target0/lun delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/target0/port delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/target0/target-name delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/target1/index delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/target1/ip-addr delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/target1/lun delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/target1/port delete mode 100644 src/core/initrd/tests/sysfs-static/firmware/ibft/target1/target-name delete mode 100644 src/core/initrd/tests/sysfs-vlan/class/net/eth0/address delete mode 100644 src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/index delete mode 100644 src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/ip-addr delete mode 100644 src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/mac delete mode 100644 src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/origin delete mode 100644 src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/prefix-len delete mode 100644 src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/subnet-mask delete mode 100644 src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/vlan delete mode 100644 src/core/initrd/tests/sysfs-vlan/firmware/ibft/initiator/initiator-name delete mode 100644 src/core/initrd/tests/sysfs-vlan/firmware/ibft/target0/index delete mode 100644 src/core/initrd/tests/sysfs-vlan/firmware/ibft/target0/ip-addr delete mode 100644 src/core/initrd/tests/sysfs-vlan/firmware/ibft/target0/lun delete mode 100644 src/core/initrd/tests/sysfs-vlan/firmware/ibft/target0/port delete mode 100644 src/core/initrd/tests/sysfs-vlan/firmware/ibft/target0/target-name delete mode 100644 src/core/initrd/tests/sysfs/class/net/eth0/address delete mode 100644 src/core/initrd/tests/sysfs/class/net/eth2/address delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/acpi_header/oem_id delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/acpi_header/oem_table_id delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/acpi_header/signature delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/dhcp delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/flags delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/gateway delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/hostname delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/index delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/ip-addr delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/mac delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/origin delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/prefix-len delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/primary-dns delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/secondary-dns delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/subnet-mask delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/vlan delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/dhcp delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/flags delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/gateway delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/hostname delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/index delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/ip-addr delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/mac delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/origin delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/prefix-len delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/primary-dns delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/secondary-dns delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/subnet-mask delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/vlan delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/initiator/flags delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/initiator/index delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/initiator/initiator-name delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/initiator/isns-server delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/initiator/pri-radius-server delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/initiator/sec-radius-server delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/initiator/slp-server delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/target0/chap-type delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/target0/flags delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/target0/index delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/target0/ip-addr delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/target0/lun delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/target0/nic-assoc delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/target0/port delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/target2/chap-type delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/target2/flags delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/target2/index delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/target2/ip-addr delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/target2/lun delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/target2/nic-assoc delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/target2/port delete mode 100644 src/core/initrd/tests/sysfs/firmware/ibft/target2/target-name delete mode 100644 src/core/initrd/tests/test-cmdline-reader.c delete mode 100644 src/core/initrd/tests/test-dt-reader.c delete mode 100644 src/core/initrd/tests/test-ibft-reader.c delete mode 100644 src/core/nm-firewall-manager.c delete mode 100644 src/core/nm-firewall-manager.h create mode 100644 src/core/nm-firewall-utils.c create mode 100644 src/core/nm-firewall-utils.h create mode 100644 src/core/nm-firewalld-manager.c create mode 100644 src/core/nm-firewalld-manager.h delete mode 100644 src/core/platform/linux/nl802154.h delete mode 100644 src/core/platform/nm-linux-platform.c delete mode 100644 src/core/platform/nm-linux-platform.h delete mode 100644 src/core/platform/nm-platform-private.h delete mode 100644 src/core/platform/nm-platform.c delete mode 100644 src/core/platform/nm-platform.h delete mode 100644 src/core/platform/nmp-object.c delete mode 100644 src/core/platform/nmp-object.h delete mode 100644 src/core/platform/nmp-rules-manager.c delete mode 100644 src/core/platform/nmp-rules-manager.h delete mode 100644 src/core/platform/wifi/nm-wifi-utils-nl80211.c delete mode 100644 src/core/platform/wifi/nm-wifi-utils-nl80211.h delete mode 100644 src/core/platform/wifi/nm-wifi-utils-private.h delete mode 100644 src/core/platform/wifi/nm-wifi-utils-wext.c delete mode 100644 src/core/platform/wifi/nm-wifi-utils-wext.h delete mode 100644 src/core/platform/wifi/nm-wifi-utils.c delete mode 100644 src/core/platform/wifi/nm-wifi-utils.h delete mode 100644 src/core/platform/wpan/nm-wpan-utils.c delete mode 100644 src/core/platform/wpan/nm-wpan-utils.h create mode 100644 src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write-empty.cexpected create mode 100644 src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-vlanid-use create mode 100644 src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-vlanid-use.cexpected create mode 100644 src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-1.cexpected create mode 100644 src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-2.cexpected create mode 100644 src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-3.cexpected create mode 100644 src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-4.cexpected create mode 100644 src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-5.cexpected delete mode 100644 src/core/systemd/meson.build delete mode 100644 src/core/systemd/nm-default-systemd.h delete mode 100644 src/core/systemd/nm-sd-utils-core.c delete mode 100644 src/core/systemd/nm-sd-utils-core.h delete mode 100644 src/core/systemd/nm-sd-utils-dhcp.c delete mode 100644 src/core/systemd/nm-sd-utils-dhcp.h delete mode 100644 src/core/systemd/nm-sd.c delete mode 100644 src/core/systemd/nm-sd.h delete mode 100644 src/core/systemd/sd-adapt-core/condition.h delete mode 100644 src/core/systemd/sd-adapt-core/conf-parser.h delete mode 100644 src/core/systemd/sd-adapt-core/device-util.h delete mode 100644 src/core/systemd/sd-adapt-core/khash.h delete mode 100644 src/core/systemd/sd-adapt-core/network-util.h delete mode 100644 src/core/systemd/sd-adapt-core/nm-sd-adapt-core.c delete mode 100644 src/core/systemd/sd-adapt-core/nm-sd-adapt-core.h delete mode 100644 src/core/systemd/sd-adapt-core/sd-daemon.h delete mode 100644 src/core/systemd/sd-adapt-core/sd-device.h delete mode 100644 src/core/systemd/sd-adapt-core/udev-util.h delete mode 100644 src/core/systemd/src/libsystemd-network/arp-util.c delete mode 100644 src/core/systemd/src/libsystemd-network/arp-util.h delete mode 100644 src/core/systemd/src/libsystemd-network/dhcp-identifier.c delete mode 100644 src/core/systemd/src/libsystemd-network/dhcp-identifier.h delete mode 100644 src/core/systemd/src/libsystemd-network/dhcp-internal.h delete mode 100644 src/core/systemd/src/libsystemd-network/dhcp-lease-internal.h delete mode 100644 src/core/systemd/src/libsystemd-network/dhcp-network.c delete mode 100644 src/core/systemd/src/libsystemd-network/dhcp-option.c delete mode 100644 src/core/systemd/src/libsystemd-network/dhcp-packet.c delete mode 100644 src/core/systemd/src/libsystemd-network/dhcp-protocol.h delete mode 100644 src/core/systemd/src/libsystemd-network/dhcp6-internal.h delete mode 100644 src/core/systemd/src/libsystemd-network/dhcp6-lease-internal.h delete mode 100644 src/core/systemd/src/libsystemd-network/dhcp6-network.c delete mode 100644 src/core/systemd/src/libsystemd-network/dhcp6-option.c delete mode 100644 src/core/systemd/src/libsystemd-network/dhcp6-protocol.h delete mode 100644 src/core/systemd/src/libsystemd-network/lldp-internal.h delete mode 100644 src/core/systemd/src/libsystemd-network/lldp-neighbor.c delete mode 100644 src/core/systemd/src/libsystemd-network/lldp-neighbor.h delete mode 100644 src/core/systemd/src/libsystemd-network/lldp-network.c delete mode 100644 src/core/systemd/src/libsystemd-network/lldp-network.h delete mode 100644 src/core/systemd/src/libsystemd-network/network-internal.c delete mode 100644 src/core/systemd/src/libsystemd-network/network-internal.h delete mode 100644 src/core/systemd/src/libsystemd-network/sd-dhcp-client.c delete mode 100644 src/core/systemd/src/libsystemd-network/sd-dhcp-lease.c delete mode 100644 src/core/systemd/src/libsystemd-network/sd-dhcp6-client.c delete mode 100644 src/core/systemd/src/libsystemd-network/sd-dhcp6-lease.c delete mode 100644 src/core/systemd/src/libsystemd-network/sd-ipv4acd.c delete mode 100644 src/core/systemd/src/libsystemd-network/sd-ipv4ll.c delete mode 100644 src/core/systemd/src/libsystemd-network/sd-lldp.c delete mode 100644 src/core/systemd/src/libsystemd/sd-event/event-source.h delete mode 100644 src/core/systemd/src/libsystemd/sd-event/event-util.c delete mode 100644 src/core/systemd/src/libsystemd/sd-event/event-util.h delete mode 100644 src/core/systemd/src/libsystemd/sd-event/sd-event.c delete mode 100644 src/core/systemd/src/libsystemd/sd-id128/id128-util.c delete mode 100644 src/core/systemd/src/libsystemd/sd-id128/id128-util.h delete mode 100644 src/core/systemd/src/libsystemd/sd-id128/sd-id128.c delete mode 100644 src/core/systemd/src/systemd/_sd-common.h delete mode 100644 src/core/systemd/src/systemd/sd-dhcp-client.h delete mode 100644 src/core/systemd/src/systemd/sd-dhcp-lease.h delete mode 100644 src/core/systemd/src/systemd/sd-dhcp-option.h delete mode 100644 src/core/systemd/src/systemd/sd-dhcp6-client.h delete mode 100644 src/core/systemd/src/systemd/sd-dhcp6-lease.h delete mode 100644 src/core/systemd/src/systemd/sd-dhcp6-option.h delete mode 100644 src/core/systemd/src/systemd/sd-event.h delete mode 100644 src/core/systemd/src/systemd/sd-id128.h delete mode 100644 src/core/systemd/src/systemd/sd-ipv4acd.h delete mode 100644 src/core/systemd/src/systemd/sd-ipv4ll.h delete mode 100644 src/core/systemd/src/systemd/sd-lldp.h delete mode 100644 src/core/systemd/src/systemd/sd-ndisc.h (limited to 'src/core') diff --git a/src/core/NetworkManagerUtils.c b/src/core/NetworkManagerUtils.c index 54072210..7d3e80be 100644 --- a/src/core/NetworkManagerUtils.c +++ b/src/core/NetworkManagerUtils.c @@ -12,19 +12,23 @@ #include #include -#include "nm-glib-aux/nm-c-list.h" +#include "libnm-glib-aux/nm-c-list.h" -#include "nm-libnm-core-intern/nm-common-macros.h" +#include "libnm-glib-aux/nm-uuid.h" +#include "libnm-glib-aux/nm-str-buf.h" +#include "libnm-base/nm-net-aux.h" +#include "libnm-core-aux-intern/nm-common-macros.h" #include "nm-utils.h" #include "nm-setting-connection.h" #include "nm-setting-ip4-config.h" #include "nm-setting-ip6-config.h" -#include "nm-core-internal.h" -#include "platform/nmp-object.h" +#include "libnm-core-intern/nm-core-internal.h" +#include "libnm-platform/nmp-object.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-platform/nm-linux-platform.h" #include "nm-auth-utils.h" -#include "systemd/nm-sd-utils-shared.h" +#include "libnm-systemd-shared/nm-sd-utils-shared.h" /*****************************************************************************/ @@ -252,7 +256,7 @@ nm_utils_complete_generic(NMPlatform * platform, g_object_set(G_OBJECT(s_con), NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_buf(uuid), + nm_uuid_generate_random_str_arr(uuid), NULL); } @@ -902,10 +906,16 @@ nm_match_spec_device_by_pllink(const NMPlatformLink *pllink, NMPlatformRoutingRule * nm_ip_routing_rule_to_platform(const NMIPRoutingRule *rule, NMPlatformRoutingRule *out_pl) { + gboolean uid_range_has; + guint32 uid_range_start = 0; + guint32 uid_range_end = 0; + nm_assert(rule); nm_assert(nm_ip_routing_rule_validate(rule, NULL)); nm_assert(out_pl); + uid_range_has = nm_ip_routing_rule_get_uid_range(rule, &uid_range_start, &uid_range_end); + *out_pl = (NMPlatformRoutingRule){ .addr_family = nm_ip_routing_rule_get_addr_family(rule), .flags = (nm_ip_routing_rule_get_invert(rule) ? FIB_RULE_INVERT : 0), @@ -932,6 +942,12 @@ nm_ip_routing_rule_to_platform(const NMIPRoutingRule *rule, NMPlatformRoutingRul .table = nm_ip_routing_rule_get_table(rule), .suppress_prefixlen_inverse = ~((guint32) nm_ip_routing_rule_get_suppress_prefixlength(rule)), + .uid_range_has = uid_range_has, + .uid_range = + { + .start = uid_range_start, + .end = uid_range_end, + }, }; nm_ip_routing_rule_get_xifname_bin(rule, TRUE, out_pl->iifname); @@ -1293,9 +1309,9 @@ nm_utils_ip_route_attribute_to_platform(int addr_family, if ((variant = nm_ip_route_get_attribute(s_route, NM_IP_ROUTE_ATTRIBUTE_TYPE)) && g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING)) { - guint8 type; + int type; - type = nm_utils_route_type_by_name(g_variant_get_string(variant, NULL)); + type = nm_net_aux_rtnl_rtntype_a2n(g_variant_get_string(variant, NULL)); nm_assert(NM_IN_SET(type, RTN_UNICAST, RTN_LOCAL)); r->type_coerced = nm_platform_route_type_coerce(type); @@ -1482,12 +1498,7 @@ nm_utils_ip_addresses_to_dbus(int addr_family, : (guint32) 0, }; - g_variant_builder_add(&builder_legacy, - "@au", - g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, - dbus_addr, - 3, - sizeof(guint32))); + g_variant_builder_add(&builder_legacy, "@au", nm_g_variant_new_au(dbus_addr, 3)); } else { g_variant_builder_add( &builder_legacy, @@ -1609,12 +1620,7 @@ nm_utils_ip_routes_to_dbus(int addr_family, r->r4.metric, }; - g_variant_builder_add(&builder_legacy, - "@au", - g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, - dbus_route, - 4, - sizeof(guint32))); + g_variant_builder_add(&builder_legacy, "@au", nm_g_variant_new_au(dbus_route, 4)); } else { g_variant_builder_add(&builder_legacy, "(@ayu@ayu)", @@ -1632,200 +1638,60 @@ nm_utils_ip_routes_to_dbus(int addr_family, /*****************************************************************************/ -typedef struct { - char *table; - char *rule; -} ShareRule; +/* Singleton NMPlatform subclass instance and cached class object */ +NM_DEFINE_SINGLETON_INSTANCE(NMPlatform); -struct _NMUtilsShareRules { - GArray *rules; -}; - -static void -_share_rule_clear(gpointer data) -{ - ShareRule *rule = data; - - g_free(rule->table); - g_free(rule->rule); -} - -NMUtilsShareRules * -nm_utils_share_rules_new(void) -{ - NMUtilsShareRules *self; - - self = g_slice_new(NMUtilsShareRules); - *self = (NMUtilsShareRules){ - .rules = g_array_sized_new(FALSE, FALSE, sizeof(ShareRule), 10), - }; - - g_array_set_clear_func(self->rules, _share_rule_clear); - return self; -} +NM_DEFINE_SINGLETON_REGISTER(NMPlatform); +/** + * nm_platform_setup: + * @instance: the #NMPlatform instance + * + * Failing to set up #NMPlatform singleton results in a fatal error, + * as well as trying to initialize it multiple times without freeing + * it. + * + * NetworkManager will typically use only one platform object during + * its run. Test programs might want to switch platform implementations, + * though. + */ void -nm_utils_share_rules_free(NMUtilsShareRules *self) +nm_platform_setup(NMPlatform *instance) { - if (!self) - return; + g_return_if_fail(NM_IS_PLATFORM(instance)); + g_return_if_fail(!singleton_instance); - g_array_unref(self->rules); - nm_g_slice_free(self); -} - -void -nm_utils_share_rules_add_rule_take(NMUtilsShareRules *self, const char *table, char *rule_take) -{ - ShareRule *rule; + singleton_instance = instance; - g_return_if_fail(self); - g_return_if_fail(table); - g_return_if_fail(rule_take); + nm_singleton_instance_register(); - rule = nm_g_array_append_new(self->rules, ShareRule); - *rule = (ShareRule){ - .table = g_strdup(table), - .rule = g_steal_pointer(&rule_take), - }; + nm_log_dbg(LOGD_CORE, + "setup %s singleton (" NM_HASH_OBFUSCATE_PTR_FMT ")", + "NMPlatform", + NM_HASH_OBFUSCATE_PTR(instance)); } -void -nm_utils_share_rules_apply(NMUtilsShareRules *self, gboolean shared) +/** + * nm_platform_get: + * @self: platform instance + * + * Retrieve #NMPlatform singleton. Use this whenever you want to connect to + * #NMPlatform signals. It is an error to call it before nm_platform_setup(). + * + * Returns: (transfer none): The #NMPlatform singleton reference. + */ +NMPlatform * +nm_platform_get() { - guint i; - - g_return_if_fail(self); + g_assert(singleton_instance); - if (self->rules->len == 0) - return; - - /* depending on whether we share or unshare, we add/remote the rules - * in opposite order. */ - if (shared) - i = self->rules->len - 1; - else - i = 0; - - for (;;) { - gs_free_error GError *error = NULL; - ShareRule * rule; - gs_free const char ** argv = NULL; - gs_free char * cmd = NULL; - int status; - - rule = &g_array_index(self->rules, ShareRule, i); - - cmd = g_strdup_printf("%s --table %s %s %s", - IPTABLES_PATH, - rule->table, - shared ? "--insert" : "--delete", - rule->rule); - argv = nm_utils_strsplit_set(cmd, " "); - - nm_log_info(LOGD_SHARING, "Executing: %s", cmd); - if (!g_spawn_sync("/", - (char **) argv, - (char **) NM_PTRARRAY_EMPTY(const char *), - G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, - NULL, - NULL, - NULL, - NULL, - &status, - &error)) { - nm_log_warn(LOGD_SHARING, "Error executing command: %s", error->message); - goto next; - } - if (WEXITSTATUS(status)) { - nm_log_warn(LOGD_SHARING, "** Command returned exit status %d.", WEXITSTATUS(status)); - } - -next: - if (shared) { - if (i == 0) - break; - i--; - } else { - i++; - if (i >= self->rules->len) - break; - } - } + return singleton_instance; } +/*****************************************************************************/ + void -nm_utils_share_rules_add_all_rules(NMUtilsShareRules *self, - const char * ip_iface, - in_addr_t addr, - guint plen) +nm_linux_platform_setup(void) { - in_addr_t netmask; - in_addr_t network; - char str_mask[NM_UTILS_INET_ADDRSTRLEN]; - char str_addr[NM_UTILS_INET_ADDRSTRLEN]; - - nm_assert(self); - - netmask = _nm_utils_ip4_prefix_to_netmask(plen); - _nm_utils_inet4_ntop(netmask, str_mask); - - network = addr & netmask; - _nm_utils_inet4_ntop(network, str_addr); - - nm_utils_share_rules_add_rule_v( - self, - "nat", - "POSTROUTING --source %s/%s ! --destination %s/%s --jump MASQUERADE", - str_addr, - str_mask, - str_addr, - str_mask); - nm_utils_share_rules_add_rule_v( - self, - "filter", - "FORWARD --destination %s/%s --out-interface %s --match state --state " - "ESTABLISHED,RELATED --jump ACCEPT", - str_addr, - str_mask, - ip_iface); - nm_utils_share_rules_add_rule_v(self, - "filter", - "FORWARD --source %s/%s --in-interface %s --jump ACCEPT", - str_addr, - str_mask, - ip_iface); - nm_utils_share_rules_add_rule_v(self, - "filter", - "FORWARD --in-interface %s --out-interface %s --jump ACCEPT", - ip_iface, - ip_iface); - nm_utils_share_rules_add_rule_v(self, - "filter", - "FORWARD --out-interface %s --jump REJECT", - ip_iface); - nm_utils_share_rules_add_rule_v(self, - "filter", - "FORWARD --in-interface %s --jump REJECT", - ip_iface); - nm_utils_share_rules_add_rule_v( - self, - "filter", - "INPUT --in-interface %s --protocol udp --destination-port 67 --jump ACCEPT", - ip_iface); - nm_utils_share_rules_add_rule_v( - self, - "filter", - "INPUT --in-interface %s --protocol tcp --destination-port 67 --jump ACCEPT", - ip_iface); - nm_utils_share_rules_add_rule_v( - self, - "filter", - "INPUT --in-interface %s --protocol udp --destination-port 53 --jump ACCEPT", - ip_iface); - nm_utils_share_rules_add_rule_v( - self, - "filter", - "INPUT --in-interface %s --protocol tcp --destination-port 53 --jump ACCEPT", - ip_iface); + nm_platform_setup(nm_linux_platform_new(FALSE, FALSE)); } diff --git a/src/core/NetworkManagerUtils.h b/src/core/NetworkManagerUtils.h index 2afb5a3e..1c86387c 100644 --- a/src/core/NetworkManagerUtils.h +++ b/src/core/NetworkManagerUtils.h @@ -8,10 +8,10 @@ #define __NETWORKMANAGER_UTILS_H__ #include "nm-core-utils.h" -#include "nm-glib-aux/nm-dedup-multi.h" +#include "libnm-glib-aux/nm-dedup-multi.h" #include "nm-setting-ip-config.h" #include "nm-setting-ip6-config.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" /*****************************************************************************/ @@ -197,18 +197,20 @@ nm_dhcp_lease_get_options(NMDhcpLease *lease) return (GHashTable *) lease; } -static inline void +static inline NMDhcpLease * nm_dhcp_lease_ref(NMDhcpLease *lease) { if (lease) g_hash_table_ref((GHashTable *) lease); + return lease; } -static inline void +static inline NMDhcpLease * nm_dhcp_lease_unref(NMDhcpLease *lease) { if (lease) g_hash_table_unref((GHashTable *) lease); + return NULL; } static inline const char * @@ -224,30 +226,12 @@ NM_AUTO_DEFINE_FCN(NMDhcpLease *, _nm_auto_unref_dhcplease, nm_dhcp_lease_unref) /*****************************************************************************/ -typedef struct _NMUtilsShareRules NMUtilsShareRules; - -NMUtilsShareRules *nm_utils_share_rules_new(void); - -void nm_utils_share_rules_free(NMUtilsShareRules *self); - -void -nm_utils_share_rules_add_rule_take(NMUtilsShareRules *self, const char *table, char *rule_take); - -static inline void -nm_utils_share_rules_add_rule(NMUtilsShareRules *self, const char *table, const char *rule) -{ - nm_utils_share_rules_add_rule_take(self, table, g_strdup(rule)); -} - -#define nm_utils_share_rules_add_rule_v(self, table, ...) \ - nm_utils_share_rules_add_rule_take((self), (table), g_strdup_printf(__VA_ARGS__)) +void nm_platform_setup(NMPlatform *instance); +NMPlatform *nm_platform_get(void); -void nm_utils_share_rules_add_all_rules(NMUtilsShareRules *self, - const char * ip_iface, - in_addr_t addr, - guint plen); +#define NM_PLATFORM_GET (nm_platform_get()) -void nm_utils_share_rules_apply(NMUtilsShareRules *self, gboolean shared); +void nm_linux_platform_setup(void); /*****************************************************************************/ diff --git a/src/core/devices/adsl/meson.build b/src/core/devices/adsl/meson.build index 95f61d95..ef87c6e8 100644 --- a/src/core/devices/adsl/meson.build +++ b/src/core/devices/adsl/meson.build @@ -7,7 +7,6 @@ libnm_device_plugin_adsl = shared_module( 'nm-device-adsl.c', ), dependencies: core_plugin_dep, - c_args: daemon_c_flags, link_args: ldflags_linker_script_devices, link_depends: linker_script_devices, install: true, diff --git a/src/core/devices/adsl/nm-atm-manager.c b/src/core/devices/adsl/nm-atm-manager.c index 9be9b5ce..bd9ed8cc 100644 --- a/src/core/devices/adsl/nm-atm-manager.c +++ b/src/core/devices/adsl/nm-atm-manager.c @@ -11,8 +11,8 @@ #include "nm-setting-adsl.h" #include "nm-device-adsl.h" #include "devices/nm-device-factory.h" -#include "platform/nm-platform.h" -#include "nm-udev-aux/nm-udev-utils.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-udev-aux/nm-udev-utils.h" /*****************************************************************************/ diff --git a/src/core/devices/adsl/nm-device-adsl.c b/src/core/devices/adsl/nm-device-adsl.c index 34c062a8..4e4c9dcc 100644 --- a/src/core/devices/adsl/nm-device-adsl.c +++ b/src/core/devices/adsl/nm-device-adsl.c @@ -17,7 +17,7 @@ #include "nm-ip4-config.h" #include "devices/nm-device-private.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "ppp/nm-ppp-manager-call.h" #include "ppp/nm-ppp-status.h" #include "nm-setting-adsl.h" @@ -265,7 +265,7 @@ pppoe_vcc_config(NMDeviceAdsl *self) _LOGD(LOGD_ADSL, "ATM setup successful"); /* otherwise we're good for stage3 */ - nm_platform_link_set_up(nm_device_get_platform(device), priv->nas_ifindex, NULL); + nm_platform_link_change_flags(nm_device_get_platform(device), priv->nas_ifindex, IFF_UP, TRUE); return TRUE; } @@ -674,12 +674,8 @@ dispose(GObject *object) static const NMDBusInterfaceInfoExtended interface_info_device_adsl = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_ADSL, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Carrier", - "b", - NM_DEVICE_CARRIER), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Carrier", "b", NM_DEVICE_CARRIER), ), ), }; static void diff --git a/src/core/devices/bluetooth/meson.build b/src/core/devices/bluetooth/meson.build index d5f26068..5b196d08 100644 --- a/src/core/devices/bluetooth/meson.build +++ b/src/core/devices/bluetooth/meson.build @@ -8,11 +8,11 @@ libnm_device_plugin_bluetooth_static = static_library( 'nm-device-bt.c', ) + (enable_bluez5_dun ? files('nm-bluez5-dun.c') : files()), dependencies: [ + libnm_core_public_dep, core_default_dep, libnm_wwan_dep, bluez5_dep, ], - c_args: daemon_c_flags, ) libnm_device_plugin_bluetooth_static_dep = declare_dependency( diff --git a/src/core/devices/bluetooth/nm-bluez-manager.c b/src/core/devices/bluetooth/nm-bluez-manager.c index dd998d29..fc081580 100644 --- a/src/core/devices/bluetooth/nm-bluez-manager.c +++ b/src/core/devices/bluetooth/nm-bluez-manager.c @@ -12,8 +12,9 @@ #include #include -#include "nm-glib-aux/nm-dbus-aux.h" -#include "nm-glib-aux/nm-c-list.h" +#include "libnm-glib-aux/nm-uuid.h" +#include "libnm-glib-aux/nm-dbus-aux.h" +#include "libnm-glib-aux/nm-c-list.h" #include "nm-dbus-manager.h" #include "devices/nm-device-factory.h" #include "devices/nm-device-bridge.h" @@ -23,9 +24,9 @@ #include "nm-device-bt.h" #include "nm-manager.h" #include "nm-bluez5-dun.h" -#include "nm-core-internal.h" -#include "platform/nm-platform.h" -#include "nm-std-aux/nm-dbus-compat.h" +#include "libnm-core-intern/nm-core-internal.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-std-aux/nm-dbus-compat.h" /*****************************************************************************/ @@ -574,11 +575,12 @@ _bzobj_to_string(const BzDBusObj *bzobj, char *buf, gsize len) #define _LOG_bzobj(bzobj, context) \ G_STMT_START \ { \ - const BzDBusObj *const _bzobj = (bzobj); \ + const BzDBusObj *const _bzobj = (bzobj); \ + const char *const _context = (context); \ char _buf[500]; \ \ _LOGT("change %-21s %s : { %s }", \ - (context), \ + _context, \ _bzobj->object_path, \ _bzobj_to_string(_bzobj, _buf, sizeof(_buf))); \ } \ @@ -1321,7 +1323,7 @@ _conn_create_panu_connection(NMBluezManager *self, BzDBusObj *bzobj) char uuid[37]; gs_free_error GError *error = NULL; - nm_utils_uuid_generate_buf(uuid); + nm_uuid_generate_random_str_arr(uuid); id = g_strdup_printf(_("%s Network"), bzobj->d_device.name); connection = nm_simple_connection_new(); @@ -2879,6 +2881,8 @@ dispose(GObject *object) g_clear_object(&priv->dbus_connection); nm_clear_pointer(&priv->bzobjs, g_hash_table_destroy); + nm_clear_pointer(&priv->conn_data_heads, g_hash_table_destroy); + nm_clear_pointer(&priv->conn_data_elems, g_hash_table_destroy); } static void diff --git a/src/core/devices/bluetooth/nm-device-bt.c b/src/core/devices/bluetooth/nm-device-bt.c index c07be2d3..8f4ceba7 100644 --- a/src/core/devices/bluetooth/nm-device-bt.c +++ b/src/core/devices/bluetooth/nm-device-bt.c @@ -10,7 +10,7 @@ #include #include -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-bluez-common.h" #include "nm-bluez-manager.h" #include "devices/nm-device-private.h" @@ -26,7 +26,7 @@ #include "nm-utils.h" #include "nm-bt-error.h" #include "nm-ip4-config.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "devices/wwan/nm-modem-manager.h" #include "devices/wwan/nm-modem.h" @@ -1317,16 +1317,12 @@ finalize(GObject *object) static const NMDBusInterfaceInfoExtended interface_info_device_bluetooth = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_BLUETOOTH, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Name", "s", NM_DEVICE_BT_NAME), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("BtCapabilities", - "u", - NM_DEVICE_BT_CAPABILITIES), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Name", "s", NM_DEVICE_BT_NAME), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("BtCapabilities", + "u", + NM_DEVICE_BT_CAPABILITIES), ), ), }; static void diff --git a/src/core/devices/nm-acd-manager.c b/src/core/devices/nm-acd-manager.c index b95f90fd..995abacd 100644 --- a/src/core/devices/nm-acd-manager.c +++ b/src/core/devices/nm-acd-manager.c @@ -12,7 +12,7 @@ #include #include -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-utils.h" #include "NetworkManagerUtils.h" #include "n-acd/src/n-acd.h" diff --git a/src/core/devices/nm-device-6lowpan.c b/src/core/devices/nm-device-6lowpan.c index fe116dd4..96218658 100644 --- a/src/core/devices/nm-device-6lowpan.c +++ b/src/core/devices/nm-device-6lowpan.c @@ -9,7 +9,7 @@ #include "nm-device-private.h" #include "settings/nm-settings.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-device-factory.h" #include "nm-setting-6lowpan.h" #include "nm-utils.h" diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c index f68c080b..3b3b8fcd 100644 --- a/src/core/devices/nm-device-bond.c +++ b/src/core/devices/nm-device-bond.c @@ -12,9 +12,9 @@ #include "NetworkManagerUtils.h" #include "nm-device-private.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-device-factory.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-ip4-config.h" #define _NMLOG_DEVICE_TYPE NMDeviceBond @@ -109,6 +109,24 @@ _set_bond_attr(NMDevice *device, const char *attr, const char *value) int ifindex = nm_device_get_ifindex(device); gboolean ret; + nm_assert(attr && attr[0]); + nm_assert(value); + + if (nm_streq(value, NM_BOND_AD_ACTOR_SYSTEM_DEFAULT) + && nm_streq(attr, NM_SETTING_BOND_OPTION_AD_ACTOR_SYSTEM)) { + gs_free char *cur_val = NULL; + + /* kernel does not allow setting ad_actor_system to "00:00:00:00:00:00". We would thus + * log an EINVAL error. Avoid that... at least, if the value is already "00:00:00:00:00:00". */ + cur_val = + nm_platform_sysctl_master_get_option(nm_device_get_platform(device), ifindex, attr); + if (nm_streq0(cur_val, NM_BOND_AD_ACTOR_SYSTEM_DEFAULT)) + return TRUE; + + /* OK, the current value is different, and we will proceed setting "00:00:00:00:00:00". + * That will fail, and we will log a warning. There is nothing else to do. */ + } + ret = nm_platform_sysctl_master_set_option(nm_device_get_platform(device), ifindex, attr, value); if (!ret) @@ -426,9 +444,10 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure) _LOGD(LOGD_BOND, "bond slave %s is already released", nm_device_get_ip_iface(slave)); if (configure) { - /* When the last slave is released the bond MAC will be set to a random - * value by kernel; remember the current one and restore it afterwards. - */ + NMConnection * applied; + NMSettingWired *s_wired; + const char * cloned_mac; + address = g_strdup(nm_device_get_hw_address(device)); if (ifindex_slave > 0) { @@ -443,9 +462,16 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure) } } - nm_platform_process_events(nm_device_get_platform(device)); - if (nm_device_update_hw_address(device)) - nm_device_hw_addr_set(device, address, "restore", FALSE); + if ((applied = nm_device_get_applied_connection(device)) + && ((s_wired = nm_connection_get_setting_wired(applied))) + && ((cloned_mac = nm_setting_wired_get_cloned_mac_address(s_wired)))) { + /* When the last slave is released the bond MAC will be set to a random + * value by kernel; if we have set a cloned-mac-address, we need to + * restore it to the previous value. */ + nm_platform_process_events(nm_device_get_platform(device)); + if (nm_device_update_hw_address(device)) + nm_device_hw_addr_set(device, address, "restore", FALSE); + } /* 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 @@ -575,16 +601,10 @@ nm_device_bond_init(NMDeviceBond *self) static const NMDBusInterfaceInfoExtended interface_info_device_bond = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_BOND, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Carrier", "b", NM_DEVICE_CARRIER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Slaves", - "ao", - NM_DEVICE_SLAVES), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Carrier", "b", NM_DEVICE_CARRIER), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Slaves", "ao", NM_DEVICE_SLAVES), ), ), }; static void diff --git a/src/core/devices/nm-device-bridge.c b/src/core/devices/nm-device-bridge.c index c919d85d..a095dc3e 100644 --- a/src/core/devices/nm-device-bridge.c +++ b/src/core/devices/nm-device-bridge.c @@ -12,9 +12,9 @@ #include "NetworkManagerUtils.h" #include "nm-device-private.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-device-factory.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #define _NMLOG_DEVICE_TYPE NMDeviceBridge #include "nm-device-logging.h" @@ -1033,7 +1033,7 @@ create_and_realize(NMDevice * device, const char * iface = nm_device_get_iface(device); const char * hwaddr; gs_free char * hwaddr_cloned = NULL; - guint8 mac_address[NM_UTILS_HWADDR_LEN_MAX]; + guint8 mac_address[_NM_UTILS_HWADDR_LEN_MAX]; NMPlatformLnkBridge props; int r; guint32 mtu = 0; @@ -1142,16 +1142,10 @@ nm_device_bridge_init(NMDeviceBridge *self) static const NMDBusInterfaceInfoExtended interface_info_device_bridge = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_BRIDGE, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Carrier", "b", NM_DEVICE_CARRIER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Slaves", - "ao", - NM_DEVICE_SLAVES), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Carrier", "b", NM_DEVICE_CARRIER), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Slaves", "ao", NM_DEVICE_SLAVES), ), ), }; static void diff --git a/src/core/devices/nm-device-dummy.c b/src/core/devices/nm-device-dummy.c index 13cfd3b0..488f0ba0 100644 --- a/src/core/devices/nm-device-dummy.c +++ b/src/core/devices/nm-device-dummy.c @@ -13,10 +13,10 @@ #include "nm-act-request.h" #include "nm-device-private.h" #include "nm-ip4-config.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-device-factory.h" #include "nm-setting-dummy.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #define _NMLOG_DEVICE_TYPE NMDeviceDummy #include "nm-device-logging.h" @@ -121,12 +121,10 @@ nm_device_dummy_init(NMDeviceDummy *self) static const NMDBusInterfaceInfoExtended interface_info_device_dummy = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_DUMMY, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", + "s", + NM_DEVICE_HW_ADDRESS), ), ), }; static void diff --git a/src/core/devices/nm-device-ethernet.c b/src/core/devices/nm-device-ethernet.c index 44428869..305552f0 100644 --- a/src/core/devices/nm-device-ethernet.c +++ b/src/core/devices/nm-device-ethernet.c @@ -14,6 +14,7 @@ #include #include +#include "libnm-glib-aux/nm-uuid.h" #include "nm-device-private.h" #include "nm-act-request.h" #include "nm-ip4-config.h" @@ -24,17 +25,17 @@ #include "ppp/nm-ppp-manager.h" #include "ppp/nm-ppp-manager-call.h" #include "ppp/nm-ppp-status.h" -#include "platform/nm-platform.h" -#include "nm-platform/nm-platform-utils.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-platform/nm-platform-utils.h" #include "nm-dcb.h" #include "settings/nm-settings-connection.h" #include "nm-config.h" #include "nm-device-ethernet-utils.h" #include "settings/nm-settings.h" #include "nm-device-factory.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "NetworkManagerUtils.h" -#include "nm-udev-aux/nm-udev-utils.h" +#include "libnm-udev-aux/nm-udev-utils.h" #include "nm-device-veth.h" #define _NMLOG_DEVICE_TYPE NMDeviceEthernet @@ -730,7 +731,9 @@ supplicant_iface_state_cb(NMSupplicantInterface *iface, if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) { supplicant_interface_release(self); - wired_auth_cond_fail(self, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); + nm_device_state_changed(NM_DEVICE(self), + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); return; } @@ -1716,11 +1719,11 @@ new_default_connection(NMDevice *self) /* Create a stable UUID. The UUID is also the Network_ID for stable-privacy addr-gen-mode, * thus when it changes we will also generate different IPv6 addresses. */ - uuid = _nm_utils_uuid_generate_from_strings("default-wired", - nm_utils_machine_id_str(), - defname, - perm_hw_addr ?: iface, - NULL); + uuid = nm_uuid_generate_from_strings("default-wired", + nm_utils_machine_id_str(), + defname, + perm_hw_addr ?: iface, + NULL); g_object_set(setting, NM_SETTING_CONNECTION_ID, @@ -1745,7 +1748,7 @@ new_default_connection(NMDevice *self) if (dev) uprop = udev_device_get_property_value(dev, "NM_AUTO_DEFAULT_LINK_LOCAL_ONLY"); - if (nm_udev_utils_property_as_boolean(uprop)) { + if (_nm_utils_ascii_str_to_bool(uprop, FALSE)) { setting = nm_setting_ip4_config_new(); g_object_set(setting, NM_SETTING_IP_CONFIG_METHOD, @@ -1784,7 +1787,8 @@ update_connection(NMDevice *device, NMConnection *connection) const char * mac = nm_device_get_hw_address(device); const char * mac_prop = NM_SETTING_WIRED_MAC_ADDRESS; GHashTableIter iter; - gpointer key, value; + const char * key; + const char * value; if (!s_wired) { s_wired = (NMSettingWired *) nm_setting_wired_new(); @@ -1822,8 +1826,8 @@ update_connection(NMDevice *device, NMConnection *connection) _nm_setting_wired_clear_s390_options(s_wired); g_hash_table_iter_init(&iter, priv->s390_options); - while (g_hash_table_iter_next(&iter, &key, &value)) - nm_setting_wired_add_s390_option(s_wired, (const char *) key, (const char *) value); + while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &value)) + nm_setting_wired_add_s390_option(s_wired, key, value); } static void @@ -1998,24 +2002,16 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps static const NMDBusInterfaceInfoExtended interface_info_device_wired = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_WIRED, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("PermHwAddress", - "s", - NM_DEVICE_PERM_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Speed", - "u", - NM_DEVICE_ETHERNET_SPEED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("S390Subchannels", - "as", - NM_DEVICE_ETHERNET_S390_SUBCHANNELS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Carrier", - "b", - NM_DEVICE_CARRIER), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("PermHwAddress", + "s", + NM_DEVICE_PERM_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Speed", "u", NM_DEVICE_ETHERNET_SPEED), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("S390Subchannels", + "as", + NM_DEVICE_ETHERNET_S390_SUBCHANNELS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Carrier", "b", NM_DEVICE_CARRIER), ), ), }; static void diff --git a/src/core/devices/nm-device-factory.c b/src/core/devices/nm-device-factory.c index 81124a8d..bdc64135 100644 --- a/src/core/devices/nm-device-factory.c +++ b/src/core/devices/nm-device-factory.c @@ -11,9 +11,9 @@ #include #include -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-utils.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-setting-bluetooth.h" #define PLUGIN_PREFIX "libnm-device-plugin-" diff --git a/src/core/devices/nm-device-generic.c b/src/core/devices/nm-device-generic.c index a319666a..08ea5ac5 100644 --- a/src/core/devices/nm-device-generic.c +++ b/src/core/devices/nm-device-generic.c @@ -8,8 +8,8 @@ #include "nm-device-generic.h" #include "nm-device-private.h" -#include "platform/nm-platform.h" -#include "nm-core-internal.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-core-intern/nm-core-internal.h" /*****************************************************************************/ @@ -191,16 +191,12 @@ dispose(GObject *object) static const NMDBusInterfaceInfoExtended interface_info_device_generic = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_GENERIC, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L( + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( "TypeDescription", "s", NM_DEVICE_GENERIC_TYPE_DESCRIPTION), ), ), - .legacy_property_changed = TRUE, }; static void diff --git a/src/core/devices/nm-device-infiniband.c b/src/core/devices/nm-device-infiniband.c index f54ffcf0..37065bc8 100644 --- a/src/core/devices/nm-device-infiniband.c +++ b/src/core/devices/nm-device-infiniband.c @@ -14,9 +14,9 @@ #include "nm-device-private.h" #include "nm-act-request.h" #include "nm-ip4-config.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-device-factory.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #define NM_DEVICE_INFINIBAND_IS_PARTITION "is-partition" @@ -366,15 +366,9 @@ nm_device_infiniband_init(NMDeviceInfiniband *self) static const NMDBusInterfaceInfoExtended interface_info_device_infiniband = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_INFINIBAND, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Carrier", - "b", - NM_DEVICE_CARRIER), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Carrier", "b", NM_DEVICE_CARRIER), ), ), }; static void diff --git a/src/core/devices/nm-device-ip-tunnel.c b/src/core/devices/nm-device-ip-tunnel.c index da6afb3b..c55dd9f6 100644 --- a/src/core/devices/nm-device-ip-tunnel.c +++ b/src/core/devices/nm-device-ip-tunnel.c @@ -16,9 +16,9 @@ #include "nm-device-private.h" #include "nm-manager.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-device-factory.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "settings/nm-settings.h" #include "nm-act-request.h" #include "nm-ip4-config.h" @@ -1050,39 +1050,33 @@ dispose(GObject *object) static const NMDBusInterfaceInfoExtended interface_info_device_ip_tunnel = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_IP_TUNNEL, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Mode", "u", NM_DEVICE_IP_TUNNEL_MODE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Parent", "o", NM_DEVICE_PARENT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Local", - "s", - NM_DEVICE_IP_TUNNEL_LOCAL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Remote", - "s", - NM_DEVICE_IP_TUNNEL_REMOTE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Ttl", "y", NM_DEVICE_IP_TUNNEL_TTL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Tos", "y", NM_DEVICE_IP_TUNNEL_TOS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L( - "PathMtuDiscovery", - "b", - NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("InputKey", - "s", - NM_DEVICE_IP_TUNNEL_INPUT_KEY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("OutputKey", - "s", - NM_DEVICE_IP_TUNNEL_OUTPUT_KEY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L( - "EncapsulationLimit", - "y", - NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("FlowLabel", - "u", - NM_DEVICE_IP_TUNNEL_FLOW_LABEL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Flags", - "u", - NM_DEVICE_IP_TUNNEL_FLAGS), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Mode", "u", NM_DEVICE_IP_TUNNEL_MODE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Parent", "o", NM_DEVICE_PARENT), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Local", "s", NM_DEVICE_IP_TUNNEL_LOCAL), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Remote", + "s", + NM_DEVICE_IP_TUNNEL_REMOTE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Ttl", "y", NM_DEVICE_IP_TUNNEL_TTL), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Tos", "y", NM_DEVICE_IP_TUNNEL_TOS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("PathMtuDiscovery", + "b", + NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("InputKey", + "s", + NM_DEVICE_IP_TUNNEL_INPUT_KEY), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("OutputKey", + "s", + NM_DEVICE_IP_TUNNEL_OUTPUT_KEY), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("EncapsulationLimit", + "y", + NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("FlowLabel", + "u", + NM_DEVICE_IP_TUNNEL_FLOW_LABEL), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Flags", + "u", + NM_DEVICE_IP_TUNNEL_FLAGS), ), ), }; static void diff --git a/src/core/devices/nm-device-macsec.c b/src/core/devices/nm-device-macsec.c index 51b820a1..51b7225b 100644 --- a/src/core/devices/nm-device-macsec.c +++ b/src/core/devices/nm-device-macsec.c @@ -11,11 +11,11 @@ #include "nm-act-request.h" #include "nm-device-private.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-device-factory.h" #include "nm-manager.h" #include "nm-setting-macsec.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "supplicant/nm-supplicant-manager.h" #include "supplicant/nm-supplicant-interface.h" #include "supplicant/nm-supplicant-config.h" @@ -870,40 +870,36 @@ dispose(GObject *object) static const NMDBusInterfaceInfoExtended interface_info_device_macsec = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_MACSEC, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Parent", "o", NM_DEVICE_PARENT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Sci", "t", NM_DEVICE_MACSEC_SCI), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("IcvLength", - "y", - NM_DEVICE_MACSEC_ICV_LENGTH), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("CipherSuite", - "t", - NM_DEVICE_MACSEC_CIPHER_SUITE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Window", - "u", - NM_DEVICE_MACSEC_WINDOW), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("EncodingSa", - "y", - NM_DEVICE_MACSEC_ENCODING_SA), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Validation", - "s", - NM_DEVICE_MACSEC_VALIDATION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Encrypt", - "b", - NM_DEVICE_MACSEC_ENCRYPT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Protect", - "b", - NM_DEVICE_MACSEC_PROTECT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("IncludeSci", - "b", - NM_DEVICE_MACSEC_INCLUDE_SCI), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Es", "b", NM_DEVICE_MACSEC_ES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Scb", "b", NM_DEVICE_MACSEC_SCB), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("ReplayProtect", - "b", - NM_DEVICE_MACSEC_REPLAY_PROTECT), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Parent", "o", NM_DEVICE_PARENT), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Sci", "t", NM_DEVICE_MACSEC_SCI), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("IcvLength", + "y", + NM_DEVICE_MACSEC_ICV_LENGTH), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("CipherSuite", + "t", + NM_DEVICE_MACSEC_CIPHER_SUITE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Window", "u", NM_DEVICE_MACSEC_WINDOW), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("EncodingSa", + "y", + NM_DEVICE_MACSEC_ENCODING_SA), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Validation", + "s", + NM_DEVICE_MACSEC_VALIDATION), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Encrypt", + "b", + NM_DEVICE_MACSEC_ENCRYPT), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Protect", + "b", + NM_DEVICE_MACSEC_PROTECT), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("IncludeSci", + "b", + NM_DEVICE_MACSEC_INCLUDE_SCI), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Es", "b", NM_DEVICE_MACSEC_ES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Scb", "b", NM_DEVICE_MACSEC_SCB), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("ReplayProtect", + "b", + NM_DEVICE_MACSEC_REPLAY_PROTECT), ), ), }; static void diff --git a/src/core/devices/nm-device-macvlan.c b/src/core/devices/nm-device-macvlan.c index e8b39ed6..7302ecdf 100644 --- a/src/core/devices/nm-device-macvlan.c +++ b/src/core/devices/nm-device-macvlan.c @@ -13,7 +13,7 @@ #include "settings/nm-settings.h" #include "nm-act-request.h" #include "nm-manager.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-device-factory.h" #include "nm-setting-macvlan.h" #include "nm-setting-wired.h" @@ -502,17 +502,13 @@ dispose(GObject *object) static const NMDBusInterfaceInfoExtended interface_info_device_macvlan = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_MACVLAN, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Parent", "o", NM_DEVICE_PARENT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Mode", "s", NM_DEVICE_MACVLAN_MODE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("NoPromisc", - "b", - NM_DEVICE_MACVLAN_NO_PROMISC), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Tab", - "b", - NM_DEVICE_MACVLAN_TAP), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Parent", "o", NM_DEVICE_PARENT), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Mode", "s", NM_DEVICE_MACVLAN_MODE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("NoPromisc", + "b", + NM_DEVICE_MACVLAN_NO_PROMISC), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Tab", "b", NM_DEVICE_MACVLAN_TAP), ), ), }; static void diff --git a/src/core/devices/nm-device-ppp.c b/src/core/devices/nm-device-ppp.c index 4040f2d3..8df245bb 100644 --- a/src/core/devices/nm-device-ppp.c +++ b/src/core/devices/nm-device-ppp.c @@ -13,7 +13,7 @@ #include "nm-device-private.h" #include "nm-manager.h" #include "nm-setting-pppoe.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "ppp/nm-ppp-manager.h" #include "ppp/nm-ppp-manager-call.h" #include "ppp/nm-ppp-status.h" @@ -274,10 +274,7 @@ dispose(GObject *object) } static const NMDBusInterfaceInfoExtended interface_info_device_ppp = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_PPP, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), ), - .legacy_property_changed = TRUE, + .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT(NM_DBUS_INTERFACE_DEVICE_PPP, ), }; static void diff --git a/src/core/devices/nm-device-private.h b/src/core/devices/nm-device-private.h index 8675a699..eb37b14f 100644 --- a/src/core/devices/nm-device-private.h +++ b/src/core/devices/nm-device-private.h @@ -17,14 +17,6 @@ typedef enum { NM_DEVICE_STAGE_STATE_COMPLETED = 2, } NMDeviceStageState; -typedef enum { - NM_DEVICE_IP_STATE_NONE, - NM_DEVICE_IP_STATE_WAIT, - NM_DEVICE_IP_STATE_CONF, - NM_DEVICE_IP_STATE_DONE, - NM_DEVICE_IP_STATE_FAIL, -} NMDeviceIPState; - enum NMActStageReturn { NM_ACT_STAGE_RETURN_FAILURE = 0, /* Hard failure of activation */ NM_ACT_STAGE_RETURN_SUCCESS, /* Activation stage done */ @@ -117,8 +109,6 @@ nm_device_activate_ip6_state_done(NMDevice *self) return nm_device_activate_get_ip_state(self, AF_INET6) == NM_DEVICE_IP_STATE_DONE; } -void nm_device_set_dhcp_anycast_address(NMDevice *device, const char *addr); - gboolean nm_device_dhcp4_renew(NMDevice *device, gboolean release); gboolean nm_device_dhcp6_renew(NMDevice *device, gboolean release); diff --git a/src/core/devices/nm-device-tun.c b/src/core/devices/nm-device-tun.c index edca69e9..ebccddfc 100644 --- a/src/core/devices/nm-device-tun.c +++ b/src/core/devices/nm-device-tun.c @@ -14,10 +14,10 @@ #include "nm-act-request.h" #include "nm-device-private.h" #include "nm-ip4-config.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-device-factory.h" #include "nm-setting-tun.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #define _NMLOG_DEVICE_TYPE NMDeviceTun #include "nm-device-logging.h" @@ -444,22 +444,18 @@ nm_device_tun_init(NMDeviceTun *self) static const NMDBusInterfaceInfoExtended interface_info_device_tun = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_TUN, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Owner", "x", NM_DEVICE_TUN_OWNER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Group", "x", NM_DEVICE_TUN_GROUP), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Mode", "s", NM_DEVICE_TUN_MODE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("NoPi", "b", NM_DEVICE_TUN_NO_PI), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("VnetHdr", - "b", - NM_DEVICE_TUN_VNET_HDR), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("MultiQueue", - "b", - NM_DEVICE_TUN_MULTI_QUEUE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Owner", "x", NM_DEVICE_TUN_OWNER), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Group", "x", NM_DEVICE_TUN_GROUP), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Mode", "s", NM_DEVICE_TUN_MODE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("NoPi", "b", NM_DEVICE_TUN_NO_PI), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("VnetHdr", "b", NM_DEVICE_TUN_VNET_HDR), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("MultiQueue", + "b", + NM_DEVICE_TUN_MULTI_QUEUE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", + "s", + NM_DEVICE_HW_ADDRESS), ), ), }; static void diff --git a/src/core/devices/nm-device-utils.c b/src/core/devices/nm-device-utils.c new file mode 100644 index 00000000..f40ca570 --- /dev/null +++ b/src/core/devices/nm-device-utils.c @@ -0,0 +1,356 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "src/core/nm-default-daemon.h" +#include "src/core/dns/nm-dns-manager.h" +#include "src/core/dns/nm-dns-systemd-resolved.h" + +#include "nm-device-utils.h" +#include "nm-core-utils.h" + +/*****************************************************************************/ + +NM_UTILS_LOOKUP_STR_DEFINE( + nm_device_state_queued_state_to_str, + NMDeviceState, + NM_UTILS_LOOKUP_DEFAULT(NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "???"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_UNKNOWN, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "unknown"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_UNMANAGED, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "unmanaged"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_UNAVAILABLE, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "unavailable"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_DISCONNECTED, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "disconnected"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_PREPARE, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "prepare"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_CONFIG, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "config"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_NEED_AUTH, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "need-auth"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_IP_CONFIG, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "ip-config"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_IP_CHECK, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "ip-check"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_SECONDARIES, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "secondaries"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_ACTIVATED, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "activated"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_DEACTIVATING, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "deactivating"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_FAILED, + NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "failed"), ); + +const char * +nm_device_state_to_str(NMDeviceState state) +{ + return nm_device_state_queued_state_to_str(state) + + NM_STRLEN(NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE); +} + +NM_UTILS_LOOKUP_STR_DEFINE( + nm_device_state_reason_to_str, + NMDeviceStateReason, + NM_UTILS_LOOKUP_DEFAULT(NULL), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNKNOWN, "unknown"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_NONE, "none"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_NOW_MANAGED, "managed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_NOW_UNMANAGED, "unmanaged"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_CONFIG_FAILED, "config-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE, "ip-config-unavailable"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED, "ip-config-expired"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_NO_SECRETS, "no-secrets"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT, "supplicant-disconnect"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED, + "supplicant-config-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED, "supplicant-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT, "supplicant-timeout"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PPP_START_FAILED, "ppp-start-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PPP_DISCONNECT, "ppp-disconnect"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PPP_FAILED, "ppp-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_DHCP_START_FAILED, "dhcp-start-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_DHCP_ERROR, "dhcp-error"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_DHCP_FAILED, "dhcp-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SHARED_START_FAILED, "sharing-start-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SHARED_FAILED, "sharing-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED, "autoip-start-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_AUTOIP_ERROR, "autoip-error"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_AUTOIP_FAILED, "autoip-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_BUSY, "modem-busy"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE, "modem-no-dialtone"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER, "modem-no-carrier"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT, "modem-dial-timeout"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_DIAL_FAILED, "modem-dial-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED, "modem-init-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_APN_FAILED, "gsm-apn-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_REGISTRATION_NOT_SEARCHING, + "gsm-registration-idle"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED, + "gsm-registration-denied"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT, + "gsm-registration-timeout"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_REGISTRATION_FAILED, + "gsm-registration-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_PIN_CHECK_FAILED, "gsm-pin-check-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_FIRMWARE_MISSING, "firmware-missing"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_REMOVED, "removed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SLEEPING, "sleeping"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_CONNECTION_REMOVED, "connection-removed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_USER_REQUESTED, "user-requested"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_CARRIER, "carrier-changed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED, "connection-assumed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, "supplicant-available"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_NOT_FOUND, "modem-not-found"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_BT_FAILED, "bluetooth-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_SIM_NOT_INSERTED, "gsm-sim-not-inserted"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED, "gsm-sim-pin-required"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_SIM_PUK_REQUIRED, "gsm-sim-puk-required"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_SIM_WRONG, "gsm-sim-wrong"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_INFINIBAND_MODE, "infiniband-mode"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED, "dependency-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_BR2684_FAILED, "br2684-bridge-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_MANAGER_UNAVAILABLE, + "modem-manager-unavailable"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SSID_NOT_FOUND, "ssid-not-found"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SECONDARY_CONNECTION_FAILED, + "secondary-connection-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_DCB_FCOE_FAILED, "dcb-fcoe-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED, "teamd-control-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_FAILED, "modem-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_AVAILABLE, "modem-available"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT, "sim-pin-incorrect"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_NEW_ACTIVATION, "new-activation"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PARENT_CHANGED, "parent-changed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED, + "parent-managed-changed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_OVSDB_FAILED, "ovsdb-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE, "ip-address-duplicate"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_IP_METHOD_UNSUPPORTED, "ip-method-unsupported"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED, + "sriov-configuration-failed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PEER_NOT_FOUND, "peer-not-found"), ); + +NM_UTILS_LOOKUP_STR_DEFINE(nm_device_mtu_source_to_str, + NMDeviceMtuSource, + NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT("unknown"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_MTU_SOURCE_NONE, "none"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_MTU_SOURCE_PARENT, "parent"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_MTU_SOURCE_IP_CONFIG, "ip-config"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_MTU_SOURCE_CONNECTION, + "connection"), ); + +NM_UTILS_LOOKUP_STR_DEFINE(nm_device_sys_iface_state_to_str, + NMDeviceSysIfaceState, + NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT("unknown"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, "external"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_SYS_IFACE_STATE_ASSUME, "assume"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_SYS_IFACE_STATE_MANAGED, "managed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_SYS_IFACE_STATE_REMOVED, + "removed"), ); + +NM_UTILS_LOOKUP_STR_DEFINE(nm_device_ip_state_to_str, + NMDeviceIPState, + NM_UTILS_LOOKUP_DEFAULT_WARN("unknown"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_IP_STATE_NONE, "none"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_IP_STATE_WAIT, "wait"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_IP_STATE_CONF, "conf"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_IP_STATE_DONE, "done"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_IP_STATE_FAIL, "fail"), ); + +/*****************************************************************************/ + +#define SD_RESOLVED_DNS (1UL << 0) +/* Don't answer request from locally synthesized records (which includes /etc/hosts) */ +#define SD_RESOLVED_NO_SYNTHESIZE (1UL << 11) + +typedef struct { + int addr_family; + NMIPAddr address; + gulong cancellable_id; + GTask * task; + NMDnsSystemdResolvedResolveHandle *resolved_handle; +} ResolveAddrInfo; + +#define _NMLOG_PREFIX_NAME "resolve-addr" +#define _NMLOG_DOMAIN LOGD_CORE +#define _NMLOG2(level, info, ...) \ + G_STMT_START \ + { \ + if (nm_logging_enabled((level), (_NMLOG_DOMAIN))) { \ + ResolveAddrInfo *_info = (info); \ + char _addr_str[NM_UTILS_INET_ADDRSTRLEN]; \ + \ + _nm_log((level), \ + (_NMLOG_DOMAIN), \ + 0, \ + NULL, \ + NULL, \ + _NMLOG_PREFIX_NAME "[" NM_HASH_OBFUSCATE_PTR_FMT \ + ",%s]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + NM_HASH_OBFUSCATE_PTR(_info), \ + nm_utils_inet_ntop(_info->addr_family, &_info->address, _addr_str) \ + _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } \ + G_STMT_END + +static void +resolve_addr_info_free(ResolveAddrInfo *info) +{ + nm_assert(info->cancellable_id == 0); + nm_assert(!info->resolved_handle); + g_object_unref(info->task); + g_free(info); +} + +static void +resolve_addr_complete(ResolveAddrInfo *info, char *hostname_take, GError *error_take) +{ + nm_assert(!!hostname_take != !!error_take); + + nm_clear_g_cancellable_disconnect(g_task_get_cancellable(info->task), &info->cancellable_id); + if (error_take) + g_task_return_error(info->task, error_take); + else + g_task_return_pointer(info->task, hostname_take, g_free); + + resolve_addr_info_free(info); +} + +static void +resolve_addr_helper_cb(GObject *source, GAsyncResult *result, gpointer user_data) +{ + ResolveAddrInfo *info = user_data; + gs_free_error GError *error = NULL; + gs_free char * output = NULL; + + output = nm_utils_spawn_helper_finish(result, &error); + if (nm_utils_error_is_cancelled(error)) + return; + + _LOG2D(info, "helper returned hostname '%s'", output); + + resolve_addr_complete(info, g_steal_pointer(&output), g_steal_pointer(&error)); +} + +static void +resolve_addr_spawn_helper(ResolveAddrInfo *info) +{ + char addr_str[NM_UTILS_INET_ADDRSTRLEN]; + + nm_utils_inet_ntop(info->addr_family, &info->address, addr_str); + _LOG2D(info, "start lookup via nm-daemon-helper"); + nm_utils_spawn_helper(NM_MAKE_STRV("resolve-address", addr_str), + g_task_get_cancellable(info->task), + resolve_addr_helper_cb, + info); +} + +static void +resolve_addr_resolved_cb(NMDnsSystemdResolved * resolved, + NMDnsSystemdResolvedResolveHandle * handle, + const NMDnsSystemdResolvedAddressResult *names, + guint names_len, + guint64 flags, + GError * error, + gpointer user_data) +{ + ResolveAddrInfo *info = user_data; + + info->resolved_handle = NULL; + + if (nm_utils_error_is_cancelled(error)) + return; + + if (error) { + gs_free char *dbus_error = NULL; + + _LOG2D(info, "error resolving via systemd-resolved: %s", error->message); + + dbus_error = g_dbus_error_get_remote_error(error); + if (nm_streq0(dbus_error, "org.freedesktop.resolve1.DnsError.NXDOMAIN")) { + resolve_addr_complete(info, NULL, g_error_copy(error)); + return; + } + + resolve_addr_spawn_helper(info); + return; + } + + if (names_len == 0) { + _LOG2D(info, "systemd-resolved returned no result"); + resolve_addr_complete(info, g_strdup(""), NULL); + return; + } + + _LOG2D(info, "systemd-resolved returned hostname '%s'", names[0].name); + resolve_addr_complete(info, g_strdup(names[0].name), NULL); +} + +static void +resolve_addr_cancelled(GObject *object, gpointer user_data) +{ + ResolveAddrInfo *info = user_data; + GError * error = NULL; + + nm_clear_g_signal_handler(g_task_get_cancellable(info->task), &info->cancellable_id); + nm_clear_pointer(&info->resolved_handle, nm_dns_systemd_resolved_resolve_cancel); + nm_utils_error_set_cancelled(&error, FALSE, NULL); + resolve_addr_complete(info, NULL, error); +} + +void +nm_device_resolve_address(int addr_family, + gconstpointer address, + GCancellable * cancellable, + GAsyncReadyCallback callback, + gpointer cb_data) +{ + ResolveAddrInfo * info; + NMDnsSystemdResolved *resolved; + + info = g_new(ResolveAddrInfo, 1); + *info = (ResolveAddrInfo){ + .task = nm_g_task_new(NULL, cancellable, nm_device_resolve_address, callback, cb_data), + .addr_family = addr_family, + .address = nm_ip_addr_init(addr_family, address), + }; + + if (cancellable) { + gulong signal_id; + + signal_id = + g_cancellable_connect(cancellable, G_CALLBACK(resolve_addr_cancelled), info, NULL); + if (signal_id == 0) { + /* the request is already cancelled. Return. */ + return; + } + info->cancellable_id = signal_id; + } + + resolved = (NMDnsSystemdResolved *) nm_dns_manager_get_systemd_resolved(nm_dns_manager_get()); + if (resolved) { + _LOG2D(info, "start lookup via systemd-resolved"); + info->resolved_handle = + nm_dns_systemd_resolved_resolve_address(resolved, + 0, + addr_family, + address, + SD_RESOLVED_DNS | SD_RESOLVED_NO_SYNTHESIZE, + 20000, + resolve_addr_resolved_cb, + info); + return; + } + + resolve_addr_spawn_helper(info); +} + +char * +nm_device_resolve_address_finish(GAsyncResult *result, GError **error) +{ + GTask *task = G_TASK(result); + + nm_assert(nm_g_task_is_valid(result, NULL, nm_device_resolve_address)); + + return g_task_propagate_pointer(task, error); +} diff --git a/src/core/devices/nm-device-utils.h b/src/core/devices/nm-device-utils.h new file mode 100644 index 00000000..8bc957a4 --- /dev/null +++ b/src/core/devices/nm-device-utils.h @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef __DEVICES_NM_DEVICE_UTILS_H__ +#define __DEVICES_NM_DEVICE_UTILS_H__ + +/*****************************************************************************/ + +const char *nm_device_state_to_str(NMDeviceState state); +const char *nm_device_state_reason_to_str(NMDeviceStateReason reason); + +#define nm_device_state_reason_to_str_a(reason) \ + NM_UTILS_LOOKUP_STR_A(nm_device_state_reason_to_str, reason) + +static inline NMDeviceStateReason +nm_device_state_reason_check(NMDeviceStateReason reason) +{ + /* the device-state-reason serves mostly informational purpose during a state + * change. In some cases however, decisions are made based on the reason. + * I tend to think that interpreting the state reason to derive some behaviors + * is confusing, because the cause and effect are so far apart. + * + * This function is here to mark source that inspects the reason to make + * a decision -- contrary to places that set the reason. Thus, by grepping + * for nm_device_state_reason_check() you can find the "effect" to a certain + * reason. + */ + return reason; +} + +/*****************************************************************************/ + +#define NM_PENDING_ACTION_AUTOACTIVATE "autoactivate" +#define NM_PENDING_ACTION_IN_STATE_CHANGE "in-state-change" +#define NM_PENDING_ACTION_RECHECK_AVAILABLE "recheck-available" +#define NM_PENDING_ACTION_CARRIER_WAIT "carrier-wait" +#define NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT "waiting-for-supplicant" +#define NM_PENDING_ACTION_WIFI_SCAN "wifi-scan" +#define NM_PENDING_ACTION_WAITING_FOR_COMPANION "waiting-for-companion" +#define NM_PENDING_ACTION_LINK_INIT "link-init" + +#define NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "queued-state-change-" +#define NM_PENDING_ACTIONPREFIX_ACTIVATION "activation-" + +const char *nm_device_state_queued_state_to_str(NMDeviceState state); + +/*****************************************************************************/ + +typedef enum { + NM_DEVICE_MTU_SOURCE_NONE, + NM_DEVICE_MTU_SOURCE_PARENT, + NM_DEVICE_MTU_SOURCE_IP_CONFIG, + NM_DEVICE_MTU_SOURCE_CONNECTION, +} NMDeviceMtuSource; + +const char *nm_device_mtu_source_to_str(NMDeviceMtuSource mtu_source); + +/*****************************************************************************/ + +typedef enum _nm_packed { + NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, + NM_DEVICE_SYS_IFACE_STATE_ASSUME, + NM_DEVICE_SYS_IFACE_STATE_MANAGED, + + /* the REMOVED state applies when the device is manually set to unmanaged + * or the link was externally removed. In both cases, we move the device + * to UNMANAGED state, without touching the link -- be it, because the link + * is already gone or because we want to release it (give it up). + */ + NM_DEVICE_SYS_IFACE_STATE_REMOVED, +} NMDeviceSysIfaceState; + +const char *nm_device_sys_iface_state_to_str(NMDeviceSysIfaceState sys_iface_state); + +/*****************************************************************************/ + +typedef enum { + NM_DEVICE_IP_STATE_NONE, + NM_DEVICE_IP_STATE_WAIT, + NM_DEVICE_IP_STATE_CONF, + NM_DEVICE_IP_STATE_DONE, + NM_DEVICE_IP_STATE_FAIL, +} NMDeviceIPState; + +const char *nm_device_ip_state_to_str(NMDeviceIPState ip_state); + +/*****************************************************************************/ + +/*****************************************************************************/ + +void nm_device_resolve_address(int addr_family, + gconstpointer address, + GCancellable * cancellable, + GAsyncReadyCallback callback, + gpointer cb_data); + +char *nm_device_resolve_address_finish(GAsyncResult *result, GError **error); + +#endif /* __DEVICES_NM_DEVICE_UTILS_H__ */ diff --git a/src/core/devices/nm-device-veth.c b/src/core/devices/nm-device-veth.c index e0ba843d..28831b75 100644 --- a/src/core/devices/nm-device-veth.c +++ b/src/core/devices/nm-device-veth.c @@ -7,11 +7,11 @@ #include -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-device-veth.h" #include "nm-device-private.h" #include "nm-manager.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-device-factory.h" #include "nm-setting-veth.h" @@ -161,12 +161,8 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) static const NMDBusInterfaceInfoExtended interface_info_device_veth = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_VETH, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Peer", - "o", - NM_DEVICE_VETH_PEER), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Peer", "o", NM_DEVICE_VETH_PEER), ), ), }; static void diff --git a/src/core/devices/nm-device-vlan.c b/src/core/devices/nm-device-vlan.c index bfde60ef..548245f8 100644 --- a/src/core/devices/nm-device-vlan.c +++ b/src/core/devices/nm-device-vlan.c @@ -16,11 +16,12 @@ #include "settings/nm-settings.h" #include "nm-act-request.h" #include "nm-ip4-config.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-device-factory.h" #include "nm-manager.h" -#include "nm-core-internal.h" -#include "platform/nmp-object.h" +#include "libnm-core-intern/nm-core-internal.h" +#include "libnm-platform/nmp-object.h" +#include "libnm-platform/nm-platform-utils.h" #define _NMLOG_DEVICE_TYPE NMDeviceVlan #include "nm-device-logging.h" @@ -436,7 +437,7 @@ update_connection(NMDevice *device, NMConnection *connection) const NMPlatformLink *plink; const NMPObject * polnk; guint vlan_id; - guint vlan_flags; + _NMVlanFlags vlan_flags; if (!s_vlan) { s_vlan = (NMSettingVlan *) nm_setting_vlan_new(); @@ -463,9 +464,9 @@ update_connection(NMDevice *device, NMConnection *connection) 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); + vlan_flags = _NM_VLAN_FLAG_REORDER_HEADERS; + if (NM_VLAN_FLAGS_CAST(vlan_flags) != nm_setting_vlan_get_flags(s_vlan)) + g_object_set(s_vlan, NM_SETTING_VLAN_FLAGS, NM_VLAN_FLAGS_CAST(vlan_flags), NULL); if (polnk) { _nm_setting_vlan_set_priorities(s_vlan, @@ -507,7 +508,7 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) nm_platform_link_vlan_change(nm_device_get_platform(device), nm_device_get_ifindex(device), - NM_VLAN_FLAGS_ALL, + _NM_VLAN_FLAGS_ALL, nm_setting_vlan_get_flags(s_vlan), TRUE, ingress_map, @@ -546,17 +547,11 @@ nm_device_vlan_init(NMDeviceVlan *self) static const NMDBusInterfaceInfoExtended interface_info_device_vlan = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_VLAN, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Carrier", "b", NM_DEVICE_CARRIER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Parent", "o", NM_DEVICE_PARENT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("VlanId", - "u", - NM_DEVICE_VLAN_ID), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Carrier", "b", NM_DEVICE_CARRIER), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Parent", "o", NM_DEVICE_PARENT), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("VlanId", "u", NM_DEVICE_VLAN_ID), ), ), }; static void @@ -674,7 +669,7 @@ get_connection_iface(NMDeviceFactory *factory, NMConnection *connection, const c * device, we create one for it using the VLAN ID and the parent * interface's name. */ - return nm_utils_new_vlan_name(parent_iface, nm_setting_vlan_get_id(s_vlan)); + return nmp_utils_new_vlan_name(parent_iface, nm_setting_vlan_get_id(s_vlan)); } NM_DEVICE_FACTORY_DEFINE_INTERNAL( diff --git a/src/core/devices/nm-device-vrf.c b/src/core/devices/nm-device-vrf.c index 4fec59ba..2a1f42c6 100644 --- a/src/core/devices/nm-device-vrf.c +++ b/src/core/devices/nm-device-vrf.c @@ -4,12 +4,12 @@ #include "nm-device-vrf.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-device-factory.h" #include "nm-device-private.h" #include "nm-manager.h" #include "nm-setting-vrf.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "settings/nm-settings.h" #define _NMLOG_DEVICE_TYPE NMDeviceVrf diff --git a/src/core/devices/nm-device-vxlan.c b/src/core/devices/nm-device-vxlan.c index f16a52c4..f9dfad2a 100644 --- a/src/core/devices/nm-device-vxlan.c +++ b/src/core/devices/nm-device-vxlan.c @@ -9,7 +9,7 @@ #include "nm-device-private.h" #include "nm-manager.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-utils.h" #include "nm-device-factory.h" #include "nm-setting-vxlan.h" @@ -17,7 +17,7 @@ #include "settings/nm-settings.h" #include "nm-act-request.h" #include "nm-ip4-config.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #define _NMLOG_DEVICE_TYPE NMDeviceVxlan #include "nm-device-logging.h" @@ -576,38 +576,34 @@ nm_device_vxlan_init(NMDeviceVxlan *self) static const NMDBusInterfaceInfoExtended interface_info_device_vxlan = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_VXLAN, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Parent", "o", NM_DEVICE_PARENT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Id", "u", NM_DEVICE_VXLAN_ID), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Group", "s", NM_DEVICE_VXLAN_GROUP), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Local", "s", NM_DEVICE_VXLAN_LOCAL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Tos", "y", NM_DEVICE_VXLAN_TOS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Ttl", "y", NM_DEVICE_VXLAN_TTL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Learning", - "b", - NM_DEVICE_VXLAN_LEARNING), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Ageing", "u", NM_DEVICE_VXLAN_AGEING), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Limit", "u", NM_DEVICE_VXLAN_LIMIT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("DstPort", - "q", - NM_DEVICE_VXLAN_DST_PORT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("SrcPortMin", - "q", - NM_DEVICE_VXLAN_SRC_PORT_MIN), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("SrcPortMax", - "q", - NM_DEVICE_VXLAN_SRC_PORT_MAX), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Proxy", "b", NM_DEVICE_VXLAN_PROXY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Rsc", "b", NM_DEVICE_VXLAN_RSC), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("L2miss", "b", NM_DEVICE_VXLAN_L2MISS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("L3miss", - "b", - NM_DEVICE_VXLAN_L3MISS), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Parent", "o", NM_DEVICE_PARENT), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Id", "u", NM_DEVICE_VXLAN_ID), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Group", "s", NM_DEVICE_VXLAN_GROUP), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Local", "s", NM_DEVICE_VXLAN_LOCAL), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Tos", "y", NM_DEVICE_VXLAN_TOS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Ttl", "y", NM_DEVICE_VXLAN_TTL), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Learning", + "b", + NM_DEVICE_VXLAN_LEARNING), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Ageing", "u", NM_DEVICE_VXLAN_AGEING), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Limit", "u", NM_DEVICE_VXLAN_LIMIT), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("DstPort", + "q", + NM_DEVICE_VXLAN_DST_PORT), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("SrcPortMin", + "q", + NM_DEVICE_VXLAN_SRC_PORT_MIN), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("SrcPortMax", + "q", + NM_DEVICE_VXLAN_SRC_PORT_MAX), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Proxy", "b", NM_DEVICE_VXLAN_PROXY), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Rsc", "b", NM_DEVICE_VXLAN_RSC), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("L2miss", "b", NM_DEVICE_VXLAN_L2MISS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("L3miss", + "b", + NM_DEVICE_VXLAN_L3MISS), ), ), }; static void diff --git a/src/core/devices/nm-device-wireguard.c b/src/core/devices/nm-device-wireguard.c index 5bee09e6..aa9c46eb 100644 --- a/src/core/devices/nm-device-wireguard.c +++ b/src/core/devices/nm-device-wireguard.c @@ -11,12 +11,12 @@ #include #include "nm-setting-wireguard.h" -#include "nm-core-internal.h" -#include "nm-glib-aux/nm-secret-utils.h" +#include "libnm-core-intern/nm-core-internal.h" +#include "libnm-glib-aux/nm-secret-utils.h" #include "nm-device-private.h" -#include "platform/nm-platform.h" -#include "platform/nmp-object.h" -#include "platform/nmp-rules-manager.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-platform/nmp-object.h" +#include "libnm-platform/nmp-rules-manager.h" #include "nm-device-factory.h" #include "nm-active-connection.h" #include "nm-act-request.h" @@ -66,7 +66,7 @@ G_STATIC_ASSERT(NM_WIREGUARD_SYMMETRIC_KEY_LEN == NMP_WIREGUARD_SYMMETRIC_KEY_LE * timestamp. */ #define RETRY_IN_MSEC_ASAP ((gint64) G_MAXINT64) -#define RETRY_IN_MSEC_MAX ((gint64)(30 * 60 * 1000)) +#define RETRY_IN_MSEC_MAX ((gint64) (30 * 60 * 1000)) typedef enum { LINK_CONFIG_MODE_FULL, @@ -669,7 +669,7 @@ _peers_resolve_retry_reschedule(NMDeviceWireGuard *self, gint64 new_next_try_at_ * than expected. Also, rate-limit to 500 msec. */ interval_ms = NM_CLAMP((new_next_try_at_nsec - now) / NM_UTILS_NSEC_PER_MSEC, (gint64) 500, - (gint64)(24 * 60 * 60 * 1000)); + (gint64) (24 * 60 * 60 * 1000)); _LOGT(LOGD_DEVICE, "wireguard-peers: schedule rechecking peer endpoints in %u msec", @@ -1939,11 +1939,9 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) switch (prop_id) { case PROP_PUBLIC_KEY: - g_value_take_variant(value, - g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, - priv->lnk_curr.public_key, - sizeof(priv->lnk_curr.public_key), - 1)); + g_value_take_variant( + value, + nm_g_variant_new_ay(priv->lnk_curr.public_key, sizeof(priv->lnk_curr.public_key))); break; case PROP_LISTEN_PORT: g_value_set_uint(value, priv->lnk_curr.listen_port); diff --git a/src/core/devices/nm-device-wpan.c b/src/core/devices/nm-device-wpan.c index 2f3b16ff..73d79410 100644 --- a/src/core/devices/nm-device-wpan.c +++ b/src/core/devices/nm-device-wpan.c @@ -15,10 +15,10 @@ #include "nm-act-request.h" #include "nm-device-private.h" #include "nm-ip4-config.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-device-factory.h" #include "nm-setting-wpan.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #define _NMLOG_DEVICE_TYPE NMDeviceWpan #include "nm-device-logging.h" diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index 040dd0b4..1c70ecb3 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -23,22 +23,23 @@ #include #include -#include "nm-std-aux/unaligned.h" -#include "nm-glib-aux/nm-dedup-multi.h" -#include "nm-glib-aux/nm-random-utils.h" -#include "systemd/nm-sd-utils-shared.h" - -#include "nm-base/nm-ethtool-base.h" -#include "nm-libnm-core-intern/nm-common-macros.h" +#include "libnm-std-aux/unaligned.h" +#include "libnm-glib-aux/nm-uuid.h" +#include "libnm-glib-aux/nm-dedup-multi.h" +#include "libnm-glib-aux/nm-random-utils.h" +#include "libnm-systemd-shared/nm-sd-utils-shared.h" + +#include "libnm-base/nm-ethtool-base.h" +#include "libnm-core-aux-intern/nm-common-macros.h" #include "nm-device-private.h" #include "nm-l3cfg.h" #include "nm-l3-config-data.h" #include "NetworkManagerUtils.h" #include "nm-manager.h" -#include "platform/nm-platform.h" -#include "nm-platform/nm-platform-utils.h" -#include "platform/nmp-object.h" -#include "platform/nmp-rules-manager.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-platform/nm-platform-utils.h" +#include "libnm-platform/nmp-object.h" +#include "libnm-platform/nmp-rules-manager.h" #include "ndisc/nm-ndisc.h" #include "ndisc/nm-lndp-ndisc.h" #include "dhcp/nm-dhcp-manager.h" @@ -51,7 +52,8 @@ #include "dnsmasq/nm-dnsmasq-manager.h" #include "nm-dhcp-config.h" #include "nm-rfkill-manager.h" -#include "nm-firewall-manager.h" +#include "nm-firewall-utils.h" +#include "nm-firewalld-manager.h" #include "settings/nm-settings-connection.h" #include "settings/nm-settings.h" #include "nm-setting-ethtool.h" @@ -65,12 +67,13 @@ #include "c-list/src/c-list.h" #include "dns/nm-dns-manager.h" #include "nm-acd-manager.h" -#include "nm-core-internal.h" -#include "systemd/nm-sd.h" +#include "libnm-core-intern/nm-core-internal.h" +#include "libnm-systemd-core/nm-sd.h" #include "nm-lldp-listener.h" #include "nm-audit-manager.h" #include "nm-connectivity.h" #include "nm-dbus-interface.h" +#include "nm-hostname-manager.h" #include "nm-device-generic.h" #include "nm-device-vlan.h" @@ -125,7 +128,6 @@ typedef struct { typedef struct { NMDevice *device; guint idle_add_id; - int ifindex; } DeleteOnDeactivateData; typedef struct { @@ -208,6 +210,7 @@ typedef struct { NMOptionBool requested[_NM_ETHTOOL_ID_FEATURE_NUM]; NMEthtoolCoalesceState *coalesce; NMEthtoolRingState * ring; + NMEthtoolPauseState * pause; } EthtoolState; typedef enum { @@ -218,7 +221,6 @@ typedef enum { typedef struct { ResolverState state; - GResolver * resolver; GInetAddress *address; GCancellable *cancellable; char * hostname; @@ -497,9 +499,6 @@ typedef struct _NMDevicePrivate { NMDeviceStageState stage1_sriov_state : 3; - /* Generic DHCP stuff */ - char *dhcp_anycast_address; - char *current_stable_id; /* Proxy Configuration */ @@ -593,9 +592,9 @@ typedef struct _NMDevicePrivate { gulong dnsmasq_state_id; /* Firewall */ - FirewallState fw_state : 4; - NMFirewallManager * fw_mgr; - NMFirewallManagerCallId *fw_call; + FirewallState fw_state : 4; + NMFirewalldManager * fw_mgr; + NMFirewalldManagerCallId *fw_call; /* IPv4LL stuff */ sd_ipv4ll *ipv4ll; @@ -694,6 +693,8 @@ typedef struct _NMDevicePrivate { } stats; bool mtu_force_set_done : 1; + + NMOptionBool promisc_reset; } NMDevicePrivate; G_DEFINE_ABSTRACT_TYPE(NMDevice, nm_device, NM_TYPE_DBUS_OBJECT) @@ -768,139 +769,6 @@ static gboolean device_link_changed(NMDevice *self); /*****************************************************************************/ -static NM_UTILS_LOOKUP_STR_DEFINE( - queued_state_to_string, - NMDeviceState, - NM_UTILS_LOOKUP_DEFAULT(NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "???"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_UNKNOWN, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "unknown"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_UNMANAGED, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "unmanaged"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_UNAVAILABLE, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "unavailable"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_DISCONNECTED, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "disconnected"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_PREPARE, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "prepare"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_CONFIG, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "config"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_NEED_AUTH, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "need-auth"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_IP_CONFIG, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "ip-config"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_IP_CHECK, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "ip-check"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_SECONDARIES, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "secondaries"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_ACTIVATED, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "activated"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_DEACTIVATING, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "deactivating"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_FAILED, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "failed"), ); - -const char * -nm_device_state_to_str(NMDeviceState state) -{ - return queued_state_to_string(state) + NM_STRLEN(NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE); -} - -NM_UTILS_LOOKUP_STR_DEFINE( - nm_device_state_reason_to_str, - NMDeviceStateReason, - NM_UTILS_LOOKUP_DEFAULT(NULL), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNKNOWN, "unknown"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_NONE, "none"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_NOW_MANAGED, "managed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_NOW_UNMANAGED, "unmanaged"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_CONFIG_FAILED, "config-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE, "ip-config-unavailable"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED, "ip-config-expired"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_NO_SECRETS, "no-secrets"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT, "supplicant-disconnect"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED, - "supplicant-config-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED, "supplicant-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT, "supplicant-timeout"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PPP_START_FAILED, "ppp-start-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PPP_DISCONNECT, "ppp-disconnect"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PPP_FAILED, "ppp-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_DHCP_START_FAILED, "dhcp-start-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_DHCP_ERROR, "dhcp-error"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_DHCP_FAILED, "dhcp-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SHARED_START_FAILED, "sharing-start-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SHARED_FAILED, "sharing-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED, "autoip-start-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_AUTOIP_ERROR, "autoip-error"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_AUTOIP_FAILED, "autoip-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_BUSY, "modem-busy"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE, "modem-no-dialtone"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER, "modem-no-carrier"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT, "modem-dial-timeout"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_DIAL_FAILED, "modem-dial-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED, "modem-init-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_APN_FAILED, "gsm-apn-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_REGISTRATION_NOT_SEARCHING, - "gsm-registration-idle"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED, - "gsm-registration-denied"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT, - "gsm-registration-timeout"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_REGISTRATION_FAILED, - "gsm-registration-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_PIN_CHECK_FAILED, "gsm-pin-check-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_FIRMWARE_MISSING, "firmware-missing"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_REMOVED, "removed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SLEEPING, "sleeping"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_CONNECTION_REMOVED, "connection-removed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_USER_REQUESTED, "user-requested"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_CARRIER, "carrier-changed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED, "connection-assumed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, "supplicant-available"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_NOT_FOUND, "modem-not-found"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_BT_FAILED, "bluetooth-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_SIM_NOT_INSERTED, "gsm-sim-not-inserted"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED, "gsm-sim-pin-required"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_SIM_PUK_REQUIRED, "gsm-sim-puk-required"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_SIM_WRONG, "gsm-sim-wrong"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_INFINIBAND_MODE, "infiniband-mode"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED, "dependency-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_BR2684_FAILED, "br2684-bridge-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_MANAGER_UNAVAILABLE, - "modem-manager-unavailable"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SSID_NOT_FOUND, "ssid-not-found"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SECONDARY_CONNECTION_FAILED, - "secondary-connection-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_DCB_FCOE_FAILED, "dcb-fcoe-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED, "teamd-control-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_FAILED, "modem-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_AVAILABLE, "modem-available"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT, "sim-pin-incorrect"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_NEW_ACTIVATION, "new-activation"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PARENT_CHANGED, "parent-changed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED, - "parent-managed-changed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_OVSDB_FAILED, "ovsdb-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE, "ip-address-duplicate"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_IP_METHOD_UNSUPPORTED, "ip-method-unsupported"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED, - "sriov-configuration-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PEER_NOT_FOUND, "peer-not-found"), ); - -#define reason_to_string_a(reason) NM_UTILS_LOOKUP_STR_A(nm_device_state_reason_to_str, reason) - -static NM_UTILS_LOOKUP_STR_DEFINE(mtu_source_to_str, - NMDeviceMtuSource, - NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT("unknown"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_MTU_SOURCE_NONE, "none"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_MTU_SOURCE_PARENT, "parent"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_MTU_SOURCE_IP_CONFIG, - "ip-config"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_MTU_SOURCE_CONNECTION, - "connection"), ); - -/*****************************************************************************/ - static void _hostname_resolver_free(HostnameResolver *resolver) { @@ -909,7 +777,6 @@ _hostname_resolver_free(HostnameResolver *resolver) nm_clear_g_source(&resolver->timeout_id); nm_clear_g_cancellable(&resolver->cancellable); - nm_g_object_unref(resolver->resolver); nm_g_object_unref(resolver->address); g_free(resolver->hostname); nm_g_slice_free(resolver); @@ -953,8 +820,7 @@ _prop_get_connection_stable_id(NMDevice * self, * Especially with ${RANDOM} stable-id we want to generate *one* configuration * for each activation. */ if (G_UNLIKELY(!priv->current_stable_id)) { - gs_free char * default_id = NULL; - gs_free char * generated = NULL; + gs_free char * generated = NULL; NMUtilsStableType stable_type; NMSettingConnection *s_con; gboolean hwaddr_is_fake; @@ -967,11 +833,10 @@ _prop_get_connection_stable_id(NMDevice * self, stable_id = nm_setting_connection_get_stable_id(s_con); if (!stable_id) { - default_id = + stable_id = nm_config_data_get_connection_default(NM_CONFIG_GET_DATA, NM_CON_DEFAULT("connection.stable-id"), self); - stable_id = default_id; } uuid = nm_connection_get_uuid(connection); @@ -1030,7 +895,6 @@ _prop_get_ipv6_dhcp_duid(NMDevice * self, { NMSettingIPConfig *s_ip6; const char * duid; - gs_free char * duid_default = NULL; const char * duid_error; GBytes * duid_out; gboolean duid_enforce = TRUE; @@ -1043,10 +907,9 @@ _prop_get_ipv6_dhcp_duid(NMDevice * self, duid = nm_setting_ip6_config_get_dhcp_duid(NM_SETTING_IP6_CONFIG(s_ip6)); if (!duid) { - duid_default = nm_config_data_get_connection_default(NM_CONFIG_GET_DATA, - NM_CON_DEFAULT("ipv6.dhcp-duid"), - self); - duid = duid_default; + duid = nm_config_data_get_connection_default(NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("ipv6.dhcp-duid"), + self); if (!duid) duid = "lease"; } @@ -1397,7 +1260,7 @@ _prop_get_ipvx_route_table(NMDevice *self, int addr_family) _LOGT(LOGD_DEVICE, "ipv%c.route-table = %u%s", nm_utils_addr_family_to_char(addr_family), - (guint)(route_table ?: RT_TABLE_MAIN), + (guint) (route_table ?: RT_TABLE_MAIN), route_table != 0u ? "" : " (policy routing not enabled)"); return route_table; @@ -1523,7 +1386,6 @@ _prop_get_ipvx_dhcp_iaid(NMDevice * self, const int IS_IPv4 = NM_IS_IPv4(addr_family); NMSettingIPConfig *s_ip; const char * iaid_str; - gs_free char * iaid_str_free = NULL; guint32 iaid; const char * iface; const char * fail_reason; @@ -1532,11 +1394,10 @@ _prop_get_ipvx_dhcp_iaid(NMDevice * self, s_ip = nm_connection_get_setting_ip_config(connection, addr_family); iaid_str = nm_setting_ip_config_get_dhcp_iaid(s_ip); if (!iaid_str) { - iaid_str_free = nm_config_data_get_connection_default( - NM_CONFIG_GET_DATA, - IS_IPv4 ? NM_CON_DEFAULT("ipv4.dhcp-iaid") : NM_CON_DEFAULT("ipv6.dhcp-iaid"), - self); - iaid_str = iaid_str_free; + iaid_str = nm_config_data_get_connection_default(NM_CONFIG_GET_DATA, + IS_IPv4 ? NM_CON_DEFAULT("ipv4.dhcp-iaid") + : NM_CON_DEFAULT("ipv6.dhcp-iaid"), + self); if (!iaid_str) { iaid_str = NM_IAID_IFNAME; is_explicit = FALSE; @@ -1567,7 +1428,7 @@ _prop_get_ipvx_dhcp_iaid(NMDevice * self, iaid = unaligned_read_be32(&pllink->l_address.data[pllink->l_address.len - 4]); goto out_good; } else if (nm_streq0(iaid_str, NM_IAID_PERM_MAC)) { - guint8 hwaddr_buf[NM_UTILS_HWADDR_LEN_MAX]; + guint8 hwaddr_buf[_NM_UTILS_HWADDR_LEN_MAX]; const char *hwaddr_str; gsize hwaddr_len; @@ -1693,12 +1554,10 @@ _prop_get_ipvx_dhcp_hostname_flags(NMDevice *self, int addr_family) } static const char * -_prop_get_connection_mud_url(NMDevice *self, NMSettingConnection *s_con, char **out_mud_url) +_prop_get_connection_mud_url(NMDevice *self, NMSettingConnection *s_con) { - const char * mud_url; - gs_free char *s = NULL; - - nm_assert(out_mud_url && !*out_mud_url); + const char *mud_url; + const char *s; mud_url = nm_setting_connection_get_mud_url(s_con); @@ -1715,7 +1574,7 @@ _prop_get_connection_mud_url(NMDevice *self, NMSettingConnection *s_con, char ** if (nm_streq(s, NM_CONNECTION_MUD_URL_NONE)) return NULL; if (nm_sd_http_url_is_valid_https(s)) - return (*out_mud_url = g_steal_pointer(&s)); + return s; } return NULL; @@ -1726,10 +1585,9 @@ _prop_get_ipv4_dhcp_client_id(NMDevice *self, NMConnection *connection, GBytes * { NMSettingIPConfig *s_ip4; const char * client_id; - gs_free char * client_id_default = NULL; guint8 * client_id_buf; const char * fail_reason; - guint8 hwaddr_bin_buf[NM_UTILS_HWADDR_LEN_MAX]; + guint8 hwaddr_bin_buf[_NM_UTILS_HWADDR_LEN_MAX]; const guint8 * hwaddr_bin; int arp_type; gsize hwaddr_len; @@ -1740,13 +1598,12 @@ _prop_get_ipv4_dhcp_client_id(NMDevice *self, NMConnection *connection, GBytes * client_id = nm_setting_ip4_config_get_dhcp_client_id(NM_SETTING_IP4_CONFIG(s_ip4)); if (!client_id) { - client_id_default = - nm_config_data_get_connection_default(NM_CONFIG_GET_DATA, - NM_CON_DEFAULT("ipv4.dhcp-client-id"), - self); - if (client_id_default && client_id_default[0]) { + client_id = nm_config_data_get_connection_default(NM_CONFIG_GET_DATA, + NM_CON_DEFAULT("ipv4.dhcp-client-id"), + self); + if (client_id && !client_id[0]) { /* a non-empty client-id is always valid, see nm_dhcp_utils_client_id_string_to_bytes(). */ - client_id = client_id_default; + client_id = NULL; } } @@ -1878,8 +1735,7 @@ out_good: static GBytes * _prop_get_ipv4_dhcp_vendor_class_identifier(NMDevice *self, NMSettingIP4Config *s_ip4) { - gs_free char *config_data_prop = NULL; - gs_free char *to_free = NULL; + gs_free char *to_free = NULL; const char * conn_prop; GBytes * bytes = NULL; const char * bin; @@ -1889,13 +1745,13 @@ _prop_get_ipv4_dhcp_vendor_class_identifier(NMDevice *self, NMSettingIP4Config * if (!conn_prop) { /* set in NetworkManager.conf ? */ - config_data_prop = nm_config_data_get_connection_default( + conn_prop = nm_config_data_get_connection_default( NM_CONFIG_GET_DATA, NM_CON_DEFAULT("ipv4.dhcp-vendor-class-identifier"), self); - if (config_data_prop && nm_utils_validate_dhcp4_vendor_class_id(config_data_prop, NULL)) - conn_prop = config_data_prop; + if (conn_prop && !nm_utils_validate_dhcp4_vendor_class_id(conn_prop, NULL)) + conn_prop = NULL; } if (conn_prop) { @@ -1961,16 +1817,11 @@ _prop_get_ipv6_ip6_privacy(NMDevice *self) } static const char * -_prop_get_x_cloned_mac_address(NMDevice * self, - NMConnection *connection, - gboolean is_wifi, - char ** out_addr) +_prop_get_x_cloned_mac_address(NMDevice *self, NMConnection *connection, gboolean is_wifi) { NMSetting * setting; const char *addr = NULL; - nm_assert(out_addr && !*out_addr); - setting = nm_connection_get_setting(connection, is_wifi ? NM_TYPE_SETTING_WIRELESS : NM_TYPE_SETTING_WIRED); if (setting) { @@ -1979,7 +1830,7 @@ _prop_get_x_cloned_mac_address(NMDevice * self, } if (!addr) { - gs_free char *a = NULL; + const char *a; a = nm_config_data_get_connection_default( NM_CONFIG_GET_DATA, @@ -1994,36 +1845,28 @@ _prop_get_x_cloned_mac_address(NMDevice * self, NMSettingMacRandomization v; /* for backward compatibility, read the deprecated wifi.mac-address-randomization setting. */ - a = nm_config_data_get_connection_default( + v = nm_config_data_get_connection_default_int64( NM_CONFIG_GET_DATA, NM_CON_DEFAULT("wifi.mac-address-randomization"), - self); - v = _nm_utils_ascii_str_to_int64(a, - 10, - NM_SETTING_MAC_RANDOMIZATION_DEFAULT, - NM_SETTING_MAC_RANDOMIZATION_ALWAYS, - NM_SETTING_MAC_RANDOMIZATION_DEFAULT); + self, + NM_SETTING_MAC_RANDOMIZATION_DEFAULT, + NM_SETTING_MAC_RANDOMIZATION_ALWAYS, + NM_SETTING_MAC_RANDOMIZATION_DEFAULT); if (v == NM_SETTING_MAC_RANDOMIZATION_ALWAYS) addr = NM_CLONED_MAC_RANDOM; } } else if (NM_CLONED_MAC_IS_SPECIAL(a) || nm_utils_hwaddr_valid(a, ETH_ALEN)) - addr = *out_addr = g_steal_pointer(&a); + addr = a; } return addr; } static const char * -_prop_get_x_generate_mac_address_mask(NMDevice * self, - NMConnection *connection, - gboolean is_wifi, - char ** out_value) +_prop_get_x_generate_mac_address_mask(NMDevice *self, NMConnection *connection, gboolean is_wifi) { NMSetting * setting; - const char *value = NULL; - char * a; - - nm_assert(out_value && !*out_value); + const char *value; setting = nm_connection_get_setting(connection, is_wifi ? NM_TYPE_SETTING_WIRELESS : NM_TYPE_SETTING_WIRED); @@ -2036,15 +1879,11 @@ _prop_get_x_generate_mac_address_mask(NMDevice * self, return value; } - a = nm_config_data_get_connection_default( + return nm_config_data_get_connection_default( NM_CONFIG_GET_DATA, is_wifi ? NM_CON_DEFAULT("wifi.generate-mac-address-mask") : NM_CON_DEFAULT("ethernet.generate-mac-address-mask"), self); - if (!a) - return NULL; - *out_value = a; - return a; } /*****************************************************************************/ @@ -2272,6 +2111,113 @@ _ethtool_ring_set(NMDevice * self, _LOGD(LOGD_DEVICE, "ethtool: ring settings successfully set"); } +static void +_ethtool_pause_reset(NMDevice *self, NMPlatform *platform, EthtoolState *ethtool_state) +{ + gs_free NMEthtoolPauseState *pause = NULL; + + nm_assert(NM_IS_DEVICE(self)); + nm_assert(NM_IS_PLATFORM(platform)); + nm_assert(ethtool_state); + + pause = g_steal_pointer(ðtool_state->pause); + if (!pause) + return; + + if (!nm_platform_ethtool_set_pause(platform, ethtool_state->ifindex, pause)) + _LOGW(LOGD_DEVICE, "ethtool: failure resetting one or more pause settings"); + else + _LOGD(LOGD_DEVICE, "ethtool: pause settings successfully reset"); +} + +static void +_ethtool_pause_set(NMDevice * self, + NMPlatform * platform, + EthtoolState * ethtool_state, + NMSettingEthtool *s_ethtool) +{ + NMEthtoolPauseState pause_old; + NMEthtoolPauseState pause_new; + GHashTable * hash; + GHashTableIter iter; + const char * name; + GVariant * variant; + gboolean has_old = FALSE; + NMTernary pause_autoneg = NM_TERNARY_DEFAULT; + NMTernary pause_rx = NM_TERNARY_DEFAULT; + NMTernary pause_tx = NM_TERNARY_DEFAULT; + + nm_assert(NM_IS_DEVICE(self)); + nm_assert(NM_IS_PLATFORM(platform)); + nm_assert(NM_IS_SETTING_ETHTOOL(s_ethtool)); + nm_assert(ethtool_state); + nm_assert(!ethtool_state->pause); + + hash = _nm_setting_option_hash(NM_SETTING(s_ethtool), FALSE); + if (!hash) + return; + + g_hash_table_iter_init(&iter, hash); + while (g_hash_table_iter_next(&iter, (gpointer *) &name, (gpointer *) &variant)) { + NMEthtoolID ethtool_id = nm_ethtool_id_get_by_name(name); + + if (!nm_ethtool_id_is_pause(ethtool_id)) + continue; + + nm_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_BOOLEAN)); + + if (!has_old) { + if (!nm_platform_ethtool_get_link_pause(platform, ethtool_state->ifindex, &pause_old)) { + _LOGW(LOGD_DEVICE, + "ethtool: failure setting pause options (cannot read " + "existing setting)"); + return; + } + has_old = TRUE; + } + + switch (ethtool_id) { + case NM_ETHTOOL_ID_PAUSE_AUTONEG: + pause_autoneg = g_variant_get_boolean(variant); + break; + case NM_ETHTOOL_ID_PAUSE_RX: + pause_rx = g_variant_get_boolean(variant); + break; + case NM_ETHTOOL_ID_PAUSE_TX: + pause_tx = g_variant_get_boolean(variant); + break; + default: + nm_assert_not_reached(); + } + } + + if (!has_old) + return; + + if (pause_rx != NM_TERNARY_DEFAULT || pause_tx != NM_TERNARY_DEFAULT) { + /* this implies to explicitly disable autoneg. */ + nm_assert(pause_autoneg != NM_TERNARY_TRUE); + pause_autoneg = NM_TERNARY_FALSE; + } + + pause_new = pause_old; + if (pause_autoneg != NM_TERNARY_DEFAULT) + pause_new.autoneg = !!pause_autoneg; + if (pause_rx != NM_TERNARY_DEFAULT) + pause_new.rx = !!pause_rx; + if (pause_tx != NM_TERNARY_DEFAULT) + pause_new.tx = !!pause_tx; + + ethtool_state->pause = nm_memdup(&pause_old, sizeof(pause_old)); + + if (!nm_platform_ethtool_set_pause(platform, ethtool_state->ifindex, &pause_new)) { + _LOGW(LOGD_DEVICE, "ethtool: failure setting pause settings"); + return; + } + + _LOGD(LOGD_DEVICE, "ethtool: pause settings successfully set"); +} + static void _ethtool_state_reset(NMDevice *self) { @@ -2288,6 +2234,8 @@ _ethtool_state_reset(NMDevice *self) _ethtool_coalesce_reset(self, platform, ethtool_state); if (ethtool_state->ring) _ethtool_ring_reset(self, platform, ethtool_state); + if (ethtool_state->pause) + _ethtool_pause_reset(self, platform, ethtool_state); } static void @@ -2321,8 +2269,10 @@ _ethtool_state_set(NMDevice *self) _ethtool_features_set(self, platform, ethtool_state, s_ethtool); _ethtool_coalesce_set(self, platform, ethtool_state, s_ethtool); _ethtool_ring_set(self, platform, ethtool_state, s_ethtool); + _ethtool_pause_set(self, platform, ethtool_state, s_ethtool); - if (ethtool_state->features || ethtool_state->coalesce || ethtool_state->ring) + if (ethtool_state->features || ethtool_state->coalesce || ethtool_state->ring + || ethtool_state->pause) priv->ethtool_state = g_steal_pointer(ðtool_state); } @@ -2521,15 +2471,6 @@ applied_config_reset_nameservers(AppliedConfig *config) /*****************************************************************************/ -static NM_UTILS_LOOKUP_STR_DEFINE( - _sys_iface_state_to_str, - NMDeviceSysIfaceState, - NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT("unknown"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, "external"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_SYS_IFACE_STATE_ASSUME, "assume"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_SYS_IFACE_STATE_MANAGED, "managed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_SYS_IFACE_STATE_REMOVED, "removed"), ); - NMDeviceSysIfaceState nm_device_sys_iface_state_get(NMDevice *self) { @@ -2568,8 +2509,8 @@ nm_device_sys_iface_state_set(NMDevice *self, NMDeviceSysIfaceState sys_iface_st if (priv->sys_iface_state != sys_iface_state) { _LOGT(LOGD_DEVICE, "sys-iface-state: %s -> %s", - _sys_iface_state_to_str(priv->sys_iface_state), - _sys_iface_state_to_str(sys_iface_state)); + nm_device_sys_iface_state_to_str(priv->sys_iface_state), + nm_device_sys_iface_state_to_str(sys_iface_state)); priv->sys_iface_state_ = sys_iface_state; } @@ -2600,6 +2541,42 @@ _active_connection_set_state_flags(NMDevice *self, NMActivationStateFlags flags) /*****************************************************************************/ +static gboolean +set_interface_flags_full(NMDevice * self, + NMDeviceInterfaceFlags mask, + NMDeviceInterfaceFlags interface_flags, + gboolean notify) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMDeviceInterfaceFlags f; + + nm_assert(!!mask); + nm_assert(!NM_FLAGS_ANY(mask, ~_NM_DEVICE_INTERFACE_FLAG_ALL)); + nm_assert(!NM_FLAGS_ANY(interface_flags, ~mask)); + + f = (priv->interface_flags & ~mask) | (interface_flags & mask); + + if (f == priv->interface_flags) + return FALSE; + + priv->interface_flags = f; + if (notify) + _notify(self, PROP_INTERFACE_FLAGS); + return TRUE; +} + +static gboolean +set_interface_flags(NMDevice * self, + NMDeviceInterfaceFlags interface_flags, + gboolean set, + gboolean notify) +{ + return set_interface_flags_full(self, + interface_flags, + set ? interface_flags : NM_DEVICE_INTERFACE_FLAG_NONE, + notify); +} + void nm_device_assume_state_get(NMDevice * self, gboolean * out_assume_state_guess_assume, @@ -2810,15 +2787,6 @@ _add_capabilities(NMDevice *self, NMDeviceCapabilities capabilities) /*****************************************************************************/ -static NM_UTILS_LOOKUP_STR_DEFINE(_ip_state_to_string, - NMDeviceIPState, - NM_UTILS_LOOKUP_DEFAULT_WARN("unknown"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_IP_STATE_NONE, "none"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_IP_STATE_WAIT, "wait"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_IP_STATE_CONF, "conf"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_IP_STATE_DONE, "done"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_IP_STATE_FAIL, "fail"), ); - static void _set_ip_state(NMDevice *self, int addr_family, NMDeviceIPState new_state) { @@ -2834,7 +2802,7 @@ _set_ip_state(NMDevice *self, int addr_family, NMDeviceIPState new_state) "ip%c-state: set to %d (%s)", nm_utils_addr_family_to_char(addr_family), (int) new_state, - _ip_state_to_string(new_state)); + nm_device_ip_state_to_str(new_state)); priv->ip_state_x_[IS_IPv4] = new_state; @@ -2943,10 +2911,10 @@ nm_device_take_over_link(NMDevice *self, int ifindex, char **old_name, GError ** /* Rename the link to the device ifname */ if (up) - nm_platform_link_set_down(platform, ifindex); + nm_platform_link_change_flags(platform, ifindex, IFF_UP, FALSE); success = nm_platform_link_set_name(platform, ifindex, nm_device_get_iface(self)); if (up) - nm_platform_link_set_up(platform, ifindex, NULL); + nm_platform_link_change_flags(platform, ifindex, IFF_UP, TRUE); if (!success) { nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "failure renaming link %d", ifindex); @@ -3074,7 +3042,7 @@ _set_ip_ifindex(NMDevice *self, int ifindex, const char *ifname) nm_platform_link_set_user_ipv6ll_enabled(platform, priv->ip_ifindex, TRUE); if (!nm_platform_link_is_up(platform, priv->ip_ifindex)) - nm_platform_link_set_up(platform, priv->ip_ifindex, NULL); + nm_platform_link_change_flags(platform, priv->ip_ifindex, IFF_UP, TRUE); } /* We don't care about any saved values from the old iface */ @@ -4870,7 +4838,6 @@ void nm_device_update_dynamic_ip_setup(NMDevice *self) { NMDevicePrivate *priv; - GError * error = NULL; g_return_if_fail(NM_IS_DEVICE(self)); @@ -4903,17 +4870,6 @@ nm_device_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); - if (!nm_lldp_listener_start(priv->lldp_listener, nm_device_get_ifindex(self), &error)) { - _LOGD(LOGD_DEVICE, - "LLDP listener %p could not be restarted: %s", - priv->lldp_listener, - error->message); - g_clear_error(&error); - } - } } /*****************************************************************************/ @@ -5030,18 +4986,12 @@ nm_device_set_carrier(NMDevice *self, gboolean carrier) if (NM_FLAGS_ALL(priv->capabilities, NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_NONSTANDARD_CARRIER)) { - if (carrier) - priv->interface_flags |= NM_DEVICE_INTERFACE_FLAG_CARRIER; - else - priv->interface_flags &= ~NM_DEVICE_INTERFACE_FLAG_CARRIER; - notify_flags = TRUE; + notify_flags = set_interface_flags(self, NM_DEVICE_INTERFACE_FLAG_CARRIER, carrier, FALSE); } priv->carrier = carrier; - if (notify_flags) - nm_gobject_notify_together(self, PROP_CARRIER, PROP_INTERFACE_FLAGS); - else - _notify(self, PROP_CARRIER); + + nm_gobject_notify_together(self, PROP_CARRIER, notify_flags ? PROP_INTERFACE_FLAGS : PROP_0); if (priv->carrier) { _LOGI(LOGD_DEVICE, "carrier: link connected"); @@ -5216,11 +5166,11 @@ ndisc_set_router_config(NMNDisc *ndisc, NMDevice *self) if (addr->plen != 64) continue; - lifetime = nm_utils_lifetime_get(addr->timestamp, - addr->lifetime, - addr->preferred, - NM_NDISC_EXPIRY_BASE_TIMESTAMP / 1000, - &preferred); + lifetime = nmp_utils_lifetime_get(addr->timestamp, + addr->lifetime, + addr->preferred, + NM_NDISC_EXPIRY_BASE_TIMESTAMP / 1000, + &preferred); if (!lifetime) continue; @@ -5272,6 +5222,8 @@ device_update_interface_flags(NMDevice *self, const NMPlatformLink *plink) flags |= NM_DEVICE_INTERFACE_FLAG_UP; if (plink && NM_FLAGS_HAS(plink->n_ifi_flags, IFF_LOWER_UP)) flags |= NM_DEVICE_INTERFACE_FLAG_LOWER_UP; + if (plink && NM_FLAGS_HAS(plink->n_ifi_flags, IFF_PROMISC)) + flags |= NM_DEVICE_INTERFACE_FLAG_PROMISC; if (NM_FLAGS_ALL(priv->capabilities, NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_NONSTANDARD_CARRIER)) { @@ -5282,10 +5234,12 @@ device_update_interface_flags(NMDevice *self, const NMPlatformLink *plink) flags |= NM_DEVICE_INTERFACE_FLAG_CARRIER; } - if (flags != priv->interface_flags) { - priv->interface_flags = flags; - _notify(self, PROP_INTERFACE_FLAGS); - } + set_interface_flags_full(self, + NM_DEVICE_INTERFACE_FLAG_UP | NM_DEVICE_INTERFACE_FLAG_LOWER_UP + | NM_DEVICE_INTERFACE_FLAG_CARRIER + | NM_DEVICE_INTERFACE_FLAG_PROMISC, + flags, + TRUE); } static gboolean @@ -5415,11 +5369,11 @@ device_link_changed(NMDevice *self) /* Ensure the assume check is queued before any queued state changes * from the transition to UNAVAILABLE. */ - nm_device_queue_recheck_assume(self); reason = NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED; } } + nm_device_queue_recheck_assume(self); nm_device_set_unmanaged_by_flags(self, NM_UNMANAGED_PLATFORM_INIT, FALSE, reason); } @@ -5892,16 +5846,19 @@ sriov_op_queue(NMDevice * self, static void device_init_static_sriov_num_vfs(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - gs_free char * value = NULL; - int num_vfs; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); if (priv->ifindex > 0 && nm_device_has_capability(self, NM_DEVICE_CAP_SRIOV)) { - value = nm_config_data_get_device_config(NM_CONFIG_GET_DATA, - NM_CONFIG_KEYFILE_KEY_DEVICE_SRIOV_NUM_VFS, - self, - NULL); - num_vfs = _nm_utils_ascii_str_to_int64(value, 10, 0, G_MAXINT32, -1); + int num_vfs; + + num_vfs = nm_config_data_get_device_config_int64(NM_CONFIG_GET_DATA, + NM_CONFIG_KEYFILE_KEY_DEVICE_SRIOV_NUM_VFS, + self, + 10, + 0, + G_MAXINT32, + -1, + -1); if (num_vfs >= 0) sriov_op_queue(self, num_vfs, NM_OPTION_BOOL_DEFAULT, NULL, NULL); } @@ -7215,7 +7172,7 @@ nm_device_generate_connection(NMDevice *self, g_object_set(s_con, NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_buf(uuid), + nm_uuid_generate_random_str_arr(uuid), NM_SETTING_CONNECTION_ID, ifname, NM_SETTING_CONNECTION_AUTOCONNECT, @@ -7467,11 +7424,10 @@ check_connection_compatible(NMDevice *self, NMConnection *connection, GError **e s_match = (NMSettingMatch *) nm_connection_get_setting(connection, NM_TYPE_SETTING_MATCH); if (s_match) { const char *const *patterns; - const char * device_driver; guint num_patterns = 0; patterns = nm_setting_match_get_interface_names(s_match, &num_patterns); - if (!nm_wildcard_match_check(device_iface, patterns, num_patterns)) { + if (num_patterns > 0 && !nm_wildcard_match_check(device_iface, patterns, num_patterns)) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, "device does not satisfy match.interface-name property"); @@ -7486,9 +7442,9 @@ check_connection_compatible(NMDevice *self, NMConnection *connection, GError **e error)) return FALSE; - device_driver = nm_device_get_driver(self); - patterns = nm_setting_match_get_drivers(s_match, &num_patterns); - if (!nm_wildcard_match_check(device_driver, patterns, num_patterns)) { + patterns = nm_setting_match_get_drivers(s_match, &num_patterns); + if (num_patterns > 0 + && !nm_wildcard_match_check(nm_device_get_driver(self), patterns, num_patterns)) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, "device does not satisfy match.driver property"); @@ -7496,7 +7452,7 @@ check_connection_compatible(NMDevice *self, NMConnection *connection, GError **e } patterns = nm_setting_match_get_paths(s_match, &num_patterns); - if (!nm_wildcard_match_check(priv->path, patterns, num_patterns)) { + if (num_patterns > 0 && !nm_wildcard_match_check(priv->path, patterns, num_patterns)) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, "device does not satisfy match.path property"); @@ -7925,14 +7881,6 @@ master_ready_cb(NMActiveConnection *active, GParamSpec *pspec, NMDevice *self) nm_device_activate_schedule_stage1_device_prepare(self, FALSE); } -static void -lldp_neighbors_changed(NMLldpListener *lldp_listener, GParamSpec *pspec, gpointer user_data) -{ - NMDevice *self = NM_DEVICE(user_data); - - _notify(self, PROP_LLDP_NEIGHBORS); -} - static NMPlatformVF * sriov_vf_config_to_platform(NMDevice *self, NMSriovVF *vf, GError **error) { @@ -8220,38 +8168,56 @@ act_stage2_config(NMDevice *self, NMDeviceStateReason *out_failure_reason) } static void -lldp_init(NMDevice *self, gboolean restart) +_lldp_neighbors_changed_cb(NMLldpListener *lldp_listener, gpointer user_data) +{ + _notify(user_data, PROP_LLDP_NEIGHBORS); +} + +static void +lldp_setup(NMDevice *self, NMTernary enabled) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + int ifindex; + gboolean notify_lldp_neighbors = FALSE; + gboolean notify_interface_flags = FALSE; - if (priv->ifindex > 0 && _prop_get_connection_lldp(self)) { - gs_free_error GError *error = NULL; + ifindex = nm_device_get_ifindex(self); - if (priv->lldp_listener) { - if (restart && nm_lldp_listener_is_running(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); - } + if (ifindex <= 0) + enabled = FALSE; + else if (enabled == NM_TERNARY_DEFAULT) + enabled = _prop_get_connection_lldp(self); - if (!nm_lldp_listener_is_running(priv->lldp_listener)) { - if (nm_lldp_listener_start(priv->lldp_listener, nm_device_get_ifindex(self), &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); - } + if (priv->lldp_listener) { + if (!enabled || nm_lldp_listener_get_ifindex(priv->lldp_listener) != ifindex) { + nm_clear_pointer(&priv->lldp_listener, nm_lldp_listener_destroy); + notify_lldp_neighbors = TRUE; } - } else { - if (priv->lldp_listener) - nm_lldp_listener_stop(priv->lldp_listener); } + + if (enabled && !priv->lldp_listener) { + gs_free_error GError *error = NULL; + + priv->lldp_listener = + nm_lldp_listener_new(ifindex, _lldp_neighbors_changed_cb, self, &error); + if (!priv->lldp_listener) { + /* This really shouldn't happen. It's likely a bug. Investigate when this happens! */ + _LOGW(LOGD_DEVICE, + "LLDP listener for ifindex %d could not be started: %s", + ifindex, + error->message); + } else + notify_lldp_neighbors = TRUE; + } + + notify_interface_flags = set_interface_flags(self, + NM_DEVICE_INTERFACE_FLAG_LLDP_CLIENT_ENABLED, + !!priv->lldp_listener, + FALSE); + + nm_gobject_notify_together(self, + notify_lldp_neighbors ? PROP_LLDP_NEIGHBORS : PROP_0, + notify_interface_flags ? PROP_INTERFACE_FLAGS : PROP_0); } /* set-mode can be: @@ -8362,26 +8328,23 @@ _routing_rules_sync(NMDevice *self, NMTernary set_mode) static gboolean tc_commit(NMDevice *self) { - NMConnection * connection = NULL; gs_unref_ptrarray GPtrArray *qdiscs = NULL; gs_unref_ptrarray GPtrArray *tfilters = NULL; - NMSettingTCConfig * s_tc = NULL; + NMSettingTCConfig * s_tc; NMPlatform * platform; int ip_ifindex; - platform = nm_device_get_platform(self); - connection = nm_device_get_applied_connection(self); - if (connection) - s_tc = nm_connection_get_setting_tc_config(connection); + s_tc = nm_device_get_applied_setting(self, NM_TYPE_SETTING_TC_CONFIG); + if (!s_tc) + return TRUE; ip_ifindex = nm_device_get_ip_ifindex(self); if (!ip_ifindex) - return s_tc == NULL; + return FALSE; - if (s_tc) { - qdiscs = nm_utils_qdiscs_from_tc_setting(platform, s_tc, ip_ifindex); - tfilters = nm_utils_tfilters_from_tc_setting(platform, s_tc, ip_ifindex); - } + platform = nm_device_get_platform(self); + qdiscs = nm_utils_qdiscs_from_tc_setting(platform, s_tc, ip_ifindex); + tfilters = nm_utils_tfilters_from_tc_setting(platform, s_tc, ip_ifindex); if (!nm_platform_qdisc_sync(platform, ip_ifindex, qdiscs)) return FALSE; @@ -8405,8 +8368,10 @@ activate_stage2_device_config(NMDevice *self) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); NMDeviceClass * klass; NMActStageReturn ret; + NMSettingWired * s_wired; gboolean no_firmware = FALSE; CList * iter; + NMTernary accept_all_mac_addresses; nm_device_state_changed(self, NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_REASON_NONE); @@ -8464,7 +8429,30 @@ activate_stage2_device_config(NMDevice *self) nm_device_queue_recheck_assume(info->slave); } - lldp_init(self, TRUE); + s_wired = nm_device_get_applied_setting(self, NM_TYPE_SETTING_WIRED); + accept_all_mac_addresses = + s_wired ? nm_setting_wired_get_accept_all_mac_addresses(s_wired) : NM_TERNARY_DEFAULT; + if (accept_all_mac_addresses != NM_TERNARY_DEFAULT) { + int ifindex = nm_device_get_ip_ifindex(self); + + if (ifindex > 0) { + int ifi_flags = + nm_platform_link_get_ifi_flags(nm_device_get_platform(self), ifindex, IFF_PROMISC); + + if (ifi_flags >= 0 && ((!!ifi_flags) != (!!accept_all_mac_addresses))) { + nm_platform_link_change_flags(nm_device_get_platform(self), + ifindex, + IFF_PROMISC, + !!accept_all_mac_addresses); + if (priv->promisc_reset == NM_OPTION_BOOL_DEFAULT) + priv->promisc_reset = !accept_all_mac_addresses; + } + } + } + + lldp_setup(self, NM_TERNARY_DEFAULT); + + _commit_mtu(self, NULL); nm_device_activate_schedule_stage3_ip_config_start(self); } @@ -8881,6 +8869,21 @@ ensure_con_ip_config(NMDevice *self, int addr_family) /*****************************************************************************/ +static const char * +_device_get_dhcp_anycast_address(NMDevice *self) +{ + NMDeviceClass *klass; + + nm_assert(NM_IS_DEVICE(self)); + + klass = NM_DEVICE_GET_CLASS(self); + + if (klass->get_dhcp_anycast_address) + return klass->get_dhcp_anycast_address(self); + + return NULL; +} + static void dhcp4_cleanup(NMDevice *self, CleanupType cleanup_type, gboolean release) { @@ -9238,7 +9241,7 @@ dhcp4_fail(NMDevice *self, NMDhcpState dhcp_state) _LOGD(LOGD_DHCP4, "DHCPv4 failed (ip_state %s, was_active %d)", - _ip_state_to_string(priv->ip_state_4), + nm_device_ip_state_to_str(priv->ip_state_4), priv->dhcp_data_4.was_active); /* The client is always left running after a failure. */ @@ -9386,12 +9389,13 @@ dhcp4_start(NMDevice *self) gs_unref_bytes GBytes *hwaddr = NULL; gs_unref_bytes GBytes *bcast_hwaddr = NULL; gs_unref_bytes GBytes *client_id = NULL; - gs_free char * mud_url_free = NULL; NMConnection * connection; NMSettingConnection * s_con; GError * error = NULL; const NMPlatformLink * pllink; const char *const * reject_servers; + gboolean request_broadcast; + const char * str; connection = nm_device_get_applied_connection(self); g_return_val_if_fail(connection, FALSE); @@ -9405,10 +9409,22 @@ dhcp4_start(NMDevice *self) nm_dbus_object_clear_and_unexport(&priv->dhcp_data_4.config); priv->dhcp_data_4.config = nm_dhcp_config_new(AF_INET); + request_broadcast = FALSE; + pllink = nm_platform_link_get(nm_device_get_platform(self), nm_device_get_ip_ifindex(self)); if (pllink) { hwaddr = nmp_link_address_get_as_bytes(&pllink->l_address); bcast_hwaddr = nmp_link_address_get_as_bytes(&pllink->l_broadcast); + + str = nmp_object_link_udev_device_get_property_value(NMP_OBJECT_UP_CAST(pllink), + "ID_NET_DHCP_BROADCAST"); + if (str && _nm_utils_ascii_str_to_bool(str, FALSE)) { + /* Use the device property ID_NET_DHCP_BROADCAST setting, which may be set for interfaces + * requiring that the DHCPOFFER message is being broadcast because they can't handle unicast + * messages while not fully configured. + */ + request_broadcast = TRUE; + } } client_id = _prop_get_ipv4_dhcp_client_id(self, connection, hwaddr); @@ -9417,28 +9433,29 @@ dhcp4_start(NMDevice *self) reject_servers = nm_setting_ip_config_get_dhcp_reject_servers(s_ip4, NULL); g_warn_if_fail(priv->dhcp_data_4.client == NULL); - priv->dhcp_data_4.client = - nm_dhcp_manager_start_ip4(nm_dhcp_manager_get(), - nm_netns_get_multi_idx(nm_device_get_netns(self)), - nm_device_get_ip_iface(self), - nm_device_get_ip_ifindex(self), - hwaddr, - bcast_hwaddr, - nm_connection_get_uuid(connection), - nm_device_get_route_table(self, AF_INET), - nm_device_get_route_metric(self, AF_INET), - 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)), - _prop_get_ipvx_dhcp_hostname_flags(self, AF_INET), - _prop_get_connection_mud_url(self, s_con, &mud_url_free), - client_id, - _prop_get_ipvx_dhcp_timeout(self, AF_INET), - priv->dhcp_anycast_address, - NULL, - vendor_class_identifier, - reject_servers, - &error); + priv->dhcp_data_4.client = nm_dhcp_manager_start_ip4( + nm_dhcp_manager_get(), + nm_netns_get_multi_idx(nm_device_get_netns(self)), + nm_device_get_ip_iface(self), + nm_device_get_ip_ifindex(self), + hwaddr, + bcast_hwaddr, + nm_connection_get_uuid(connection), + nm_device_get_route_table(self, AF_INET), + nm_device_get_route_metric(self, AF_INET), + request_broadcast ? NM_DHCP_CLIENT_FLAGS_REQUEST_BROADCAST : NM_DHCP_CLIENT_FLAGS_NONE, + 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)), + _prop_get_ipvx_dhcp_hostname_flags(self, AF_INET), + _prop_get_connection_mud_url(self, s_con), + client_id, + _prop_get_ipvx_dhcp_timeout(self, AF_INET), + _device_get_dhcp_anycast_address(self), + NULL, + vendor_class_identifier, + reject_servers, + &error); if (!priv->dhcp_data_4.client) { _LOGW(LOGD_DHCP4, "failure to start DHCP: %s", error->message); g_clear_error(&error); @@ -9669,7 +9686,7 @@ dhcp6_fail(NMDevice *self, NMDhcpState dhcp_state) _LOGD(LOGD_DHCP6, "DHCPv6 failed (ip_state %s, was_active %d)", - _ip_state_to_string(priv->ip_state_6), + nm_device_ip_state_to_str(priv->ip_state_6), priv->dhcp_data_6.was_active); /* The client is always left running after a failure. */ @@ -9835,8 +9852,7 @@ dhcp6_start_with_link_ready(NMDevice *self, NMConnection *connection) gs_unref_bytes GBytes * duid = NULL; gboolean enforce_duid = FALSE; const NMPlatformLink * pllink; - gs_free char * mud_url_free = NULL; - GError * error = NULL; + GError * error = NULL; guint32 iaid; gboolean iaid_explicit; NMSettingConnection * s_con; @@ -9850,9 +9866,9 @@ dhcp6_start_with_link_ready(NMDevice *self, NMConnection *connection) nm_assert(s_con); if (priv->ext_ip6_config_captured) { - ll_addr = nm_ip6_config_find_first_address(priv->ext_ip6_config_captured, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL); + ll_addr = nm_ip_config_find_first_address(NM_IP_CONFIG(priv->ext_ip6_config_captured), + NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL); } if (!ll_addr) { @@ -9876,17 +9892,18 @@ dhcp6_start_with_link_ready(NMDevice *self, NMConnection *connection) nm_connection_get_uuid(connection), nm_device_get_route_table(self, AF_INET6), nm_device_get_route_metric(self, AF_INET6), + (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) ? NM_DHCP_CLIENT_FLAGS_INFO_ONLY + : NM_DHCP_CLIENT_FLAGS_NONE, nm_setting_ip_config_get_dhcp_send_hostname(s_ip6), nm_setting_ip_config_get_dhcp_hostname(s_ip6), _prop_get_ipvx_dhcp_hostname_flags(self, AF_INET6), - _prop_get_connection_mud_url(self, s_con, &mud_url_free), + _prop_get_connection_mud_url(self, s_con), duid, enforce_duid, iaid, iaid_explicit, _prop_get_ipvx_dhcp_timeout(self, AF_INET6), - priv->dhcp_anycast_address, - (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE, + _device_get_dhcp_anycast_address(self), nm_setting_ip6_config_get_ip6_privacy(NM_SETTING_IP6_CONFIG(s_ip6)), priv->dhcp6.needed_prefixes, &error); @@ -10090,9 +10107,9 @@ linklocal6_check_complete(NMDevice *self) } if (!priv->ext_ip6_config_captured - || !nm_ip6_config_find_first_address(priv->ext_ip6_config_captured, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) { + || !nm_ip_config_find_first_address(NM_IP_CONFIG(priv->ext_ip6_config_captured), + NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) { /* we don't have a non-tentative link local address yet. Wait longer. */ return; } @@ -10138,10 +10155,10 @@ check_and_add_ipv6ll_addr(NMDevice *self) return; if (priv->ext_ip6_config_captured - && nm_ip6_config_find_first_address(priv->ext_ip6_config_captured, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE)) { + && nm_ip_config_find_first_address(NM_IP_CONFIG(priv->ext_ip6_config_captured), + NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE)) { /* Already have an LL address, nothing to do */ return; } @@ -10211,9 +10228,9 @@ linklocal6_start(NMDevice *self) nm_clear_g_source(&priv->linklocal6_timeout_id); if (priv->ext_ip6_config_captured - && nm_ip6_config_find_first_address(priv->ext_ip6_config_captured, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) + && nm_ip_config_find_first_address(NM_IP_CONFIG(priv->ext_ip6_config_captured), + NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) return TRUE; _LOGD(LOGD_DEVICE, @@ -10458,9 +10475,9 @@ _commit_mtu(NMDevice *self, const NMIP4Config *config) _LOGT(LOGD_DEVICE, "mtu: value %u from source '%s' (%u), current source '%s' (%u)%s", (guint) mtu, - mtu_source_to_str(source), + nm_device_mtu_source_to_str(source), (guint) source, - mtu_source_to_str(priv->mtu_source), + nm_device_mtu_source_to_str(priv->mtu_source), (guint) priv->mtu_source, force ? " (forced)" : ""); } @@ -10792,9 +10809,9 @@ ndisc_ra_timeout(NMNDisc *ndisc, NMDevice *self) * addresses we find inside priv->ip_config_6. */ if (priv->ip_config_6 - && nm_ip6_config_find_first_address(priv->ip_config_6, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY)) + && nm_ip_config_find_first_address(NM_IP_CONFIG(priv->ip_config_6), + NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY)) nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); else nm_device_activate_schedule_ip_config_timeout(self, AF_INET6); @@ -11397,10 +11414,10 @@ activate_stage3_ip_config_start(NMDevice *self) } static void -fw_change_zone_cb(NMFirewallManager * firewall_manager, - NMFirewallManagerCallId *call_id, - GError * error, - gpointer user_data) +fw_change_zone_cb(NMFirewalldManager * firewalld_manager, + NMFirewalldManagerCallId *call_id, + GError * error, + gpointer user_data) { NMDevice * self = user_data; NMDevicePrivate *priv; @@ -11452,12 +11469,12 @@ fw_change_zone(NMDevice *self) nm_assert(s_con); if (priv->fw_call) { - nm_firewall_manager_cancel_call(priv->fw_call); + nm_firewalld_manager_cancel_call(priv->fw_call); nm_assert(!priv->fw_call); } if (G_UNLIKELY(!priv->fw_mgr)) - priv->fw_mgr = g_object_ref(nm_firewall_manager_get()); + priv->fw_mgr = g_object_ref(nm_firewalld_manager_get()); zone = nm_setting_connection_get_zone(s_con); #if WITH_FIREWALLD_ZONE @@ -11469,12 +11486,12 @@ fw_change_zone(NMDevice *self) zone = "nm-shared"; } #endif - priv->fw_call = nm_firewall_manager_add_or_change_zone(priv->fw_mgr, - nm_device_get_ip_iface(self), - zone, - FALSE, /* change zone */ - fw_change_zone_cb, - self); + priv->fw_call = nm_firewalld_manager_add_or_change_zone(priv->fw_mgr, + nm_device_get_ip_iface(self), + zone, + FALSE, /* change zone */ + fw_change_zone_cb, + self); } /* @@ -11634,7 +11651,7 @@ share_init(NMDevice *self, GError **error) } for (i = 0; i < G_N_ELEMENTS(modules); i++) - nm_utils_modprobe(NULL, FALSE, modules[i], NULL); + nmp_utils_modprobe(NULL, FALSE, modules[i], NULL); return TRUE; } @@ -11650,7 +11667,7 @@ start_sharing(NMDevice *self, NMIP4Config *config, GError **error) NMConnection * conn; NMSettingConnection * s_con; gboolean announce_android_metered; - NMUtilsShareRules * share_rules; + NMFirewallConfig * firewall_config; g_return_val_if_fail(config, FALSE); @@ -11675,13 +11692,9 @@ start_sharing(NMDevice *self, NMIP4Config *config, GError **error) req = nm_device_get_act_request(self); g_return_val_if_fail(req, FALSE); - share_rules = nm_utils_share_rules_new(); - - nm_utils_share_rules_add_all_rules(share_rules, ip_iface, ip4_addr->address, ip4_addr->plen); + firewall_config = nm_firewall_config_new(ip_iface, ip4_addr->address, ip4_addr->plen); - nm_utils_share_rules_apply(share_rules, TRUE); - - nm_act_request_set_shared(req, share_rules); + nm_act_request_set_shared(req, firewall_config); conn = nm_act_request_get_applied_connection(req); s_con = nm_connection_get_setting_connection(conn); @@ -11803,7 +11816,7 @@ activate_stage5_ip_config_result_x(NMDevice *self, int addr_family) if (!nm_platform_link_is_up(nm_device_get_platform(self), ip_ifindex) && !nm_device_sys_iface_state_is_external_or_assume(self)) { - nm_platform_link_set_up(nm_device_get_platform(self), ip_ifindex, NULL); + nm_platform_link_change_flags(nm_device_get_platform(self), ip_ifindex, IFF_UP, TRUE); if (!nm_platform_link_is_up(nm_device_get_platform(self), ip_ifindex)) _LOGW(LOGD_DEVICE, "interface %s not up for IP configuration", @@ -12141,28 +12154,19 @@ nm_device_is_nm_owned(NMDevice *self) static gboolean delete_on_deactivate_link_delete(gpointer user_data) { - DeleteOnDeactivateData *data = user_data; - NMDevice * self = data->device; + DeleteOnDeactivateData *data = user_data; + nm_auto_unref_object NMDevice *self = data->device; + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + gs_free_error GError *error = NULL; _LOGD(LOGD_DEVICE, - "delete_on_deactivate: cleanup and delete virtual link #%d (id=%u)", - data->ifindex, + "delete_on_deactivate: cleanup and delete virtual link (id=%u)", 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; + priv->delete_on_deactivate_data = NULL; - if (!nm_device_unrealize(data->device, TRUE, &error)) - _LOGD(LOGD_DEVICE, - "delete_on_deactivate: unrealizing %d failed (%s)", - data->ifindex, - error->message); - } else if (data->ifindex > 0) - nm_platform_link_delete(nm_device_get_platform(self), data->ifindex); + if (!nm_device_unrealize(self, TRUE, &error)) + _LOGD(LOGD_DEVICE, "delete_on_deactivate: unrealizing failed (%s)", error->message); nm_device_emit_recheck_auto_activate(self); @@ -12181,17 +12185,16 @@ delete_on_deactivate_unschedule(NMDevice *self) priv->delete_on_deactivate_data = NULL; g_source_remove(data->idle_add_id); - g_object_remove_weak_pointer(G_OBJECT(self), (void **) &data->device); _LOGD(LOGD_DEVICE, - "delete_on_deactivate: cancel cleanup and delete virtual link #%d (id=%u)", - data->ifindex, + "delete_on_deactivate: cancel cleanup and delete virtual link (id=%u)", data->idle_add_id); + g_object_unref(data->device); g_free(data); } } static void -delete_on_deactivate_check_and_schedule(NMDevice *self, int ifindex) +delete_on_deactivate_check_and_schedule(NMDevice *self) { NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); DeleteOnDeactivateData *data; @@ -12208,16 +12211,13 @@ delete_on_deactivate_check_and_schedule(NMDevice *self, int ifindex) return; delete_on_deactivate_unschedule(self); /* always cancel and reschedule */ - data = g_new(DeleteOnDeactivateData, 1); - g_object_add_weak_pointer(G_OBJECT(self), (void **) &data->device); - data->device = self; - data->ifindex = ifindex; + data = g_new(DeleteOnDeactivateData, 1); + data->device = g_object_ref(self); data->idle_add_id = g_idle_add(delete_on_deactivate_link_delete, data); priv->delete_on_deactivate_data = data; _LOGD(LOGD_DEVICE, - "delete_on_deactivate: schedule cleanup and delete virtual link #%d (id=%u)", - ifindex, + "delete_on_deactivate: schedule cleanup and delete virtual link (id=%u)", data->idle_add_id); } @@ -12696,7 +12696,7 @@ check_and_reapply_connection(NMDevice * self, klass->reapply_connection(self, con_old, con_new); if (priv->state >= NM_DEVICE_STATE_CONFIG) - lldp_init(self, FALSE); + lldp_setup(self, NM_TERNARY_DEFAULT); if (priv->state >= NM_DEVICE_STATE_IP_CONFIG) { s_ip4_old = nm_connection_get_setting_ip4_config(con_old); @@ -12927,9 +12927,10 @@ impl_device_get_applied_connection(NMDBusObject * obj, return; } - var_settings = nm_connection_to_dbus(applied_connection, NM_CONNECTION_SERIALIZE_NO_SECRETS); + var_settings = + nm_connection_to_dbus(applied_connection, NM_CONNECTION_SERIALIZE_WITH_NON_SECRET); if (!var_settings) - var_settings = g_variant_new_array(G_VARIANT_TYPE("{sa{sv}}"), NULL, 0); + var_settings = nm_g_variant_singleton_aLsaLsvII(); g_dbus_method_invocation_return_value( invocation, @@ -13478,12 +13479,13 @@ nm_device_set_ip_config(NMDevice * self, gboolean commit, GPtrArray * ip4_dev_route_blacklist) { - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - const int IS_IPv4 = NM_IS_IPv4(addr_family); - NMIPConfig * old_config; - gboolean has_changes = FALSE; - gboolean success = TRUE; - NMSettingsConnection *settings_connection; + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + const int IS_IPv4 = NM_IS_IPv4(addr_family); + NMIPConfig * old_config; + gboolean has_changes = FALSE; + gboolean success = TRUE; + NMSettingsConnection * settings_connection; + NMIPRouteTableSyncMode route_table_sync_mode; nm_assert_addr_family(addr_family); nm_assert(!new_config || nm_ip_config_get_addr_family(new_config) == addr_family); @@ -13495,11 +13497,18 @@ nm_device_set_ip_config(NMDevice * self, }))); nm_assert(IS_IPv4 || !ip4_dev_route_blacklist); + if (commit && new_config) + route_table_sync_mode = _get_route_table_sync_mode_stateful(self, addr_family); + else + route_table_sync_mode = NM_IP_ROUTE_TABLE_SYNC_MODE_NONE; + _LOGD(LOGD_IPX(IS_IPv4), - "ip%c-config: update (commit=%d, new-config=%p)", + "ip%c-config: update (commit=%d, new-config=" NM_HASH_OBFUSCATE_PTR_FMT + ", route-table-sync-mode=%d)", nm_utils_addr_family_to_char(addr_family), commit, - new_config); + NM_HASH_OBFUSCATE_PTR(new_config), + (int) route_table_sync_mode); /* Always commit to nm-platform to update lifetimes */ if (commit && new_config) { @@ -13508,7 +13517,7 @@ nm_device_set_ip_config(NMDevice * self, if (IS_IPv4) { success = nm_ip4_config_commit(NM_IP4_CONFIG(new_config), nm_device_get_platform(self), - _get_route_table_sync_mode_stateful(self, AF_INET)); + route_table_sync_mode); nm_platform_ip4_dev_route_blacklist_set(nm_device_get_platform(self), nm_ip_config_get_ifindex(new_config), ip4_dev_route_blacklist); @@ -13517,7 +13526,7 @@ nm_device_set_ip_config(NMDevice * self, success = nm_ip6_config_commit(NM_IP6_CONFIG(new_config), nm_device_get_platform(self), - _get_route_table_sync_mode_stateful(self, AF_INET6), + route_table_sync_mode, &temporary_not_available); if (!_rt6_temporary_not_available_set(self, temporary_not_available)) @@ -13596,7 +13605,7 @@ nm_device_set_ip_config(NMDevice * self, NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY, NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, - NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE, + NM_SETTINGS_CONNECTION_UPDATE_REASON_UPDATE_NON_SECRET, "update-external", NULL); } @@ -14007,13 +14016,14 @@ nm_device_is_up(NMDevice *self) static gint64 _get_carrier_wait_ms(NMDevice *self) { - gs_free char *value = NULL; - - value = nm_config_data_get_device_config(NM_CONFIG_GET_DATA, - NM_CONFIG_KEYFILE_KEY_DEVICE_CARRIER_WAIT_TIMEOUT, - self, - NULL); - return _nm_utils_ascii_str_to_int64(value, 10, 0, G_MAXINT32, CARRIER_WAIT_TIME_MS); + return nm_config_data_get_device_config_int64(NM_CONFIG_GET_DATA, + NM_CONFIG_KEYFILE_KEY_DEVICE_CARRIER_WAIT_TIMEOUT, + self, + 10, + 0, + G_MAXINT32, + CARRIER_WAIT_TIME_MS, + CARRIER_WAIT_TIME_MS); } gboolean @@ -14023,6 +14033,7 @@ nm_device_bring_up(NMDevice *self, gboolean block, gboolean *no_firmware) gboolean device_is_up = FALSE; NMDeviceCapabilities capabilities; int ifindex; + int r; g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); @@ -14038,7 +14049,9 @@ nm_device_bring_up(NMDevice *self, gboolean block, gboolean *no_firmware) if (ifindex <= 0) { /* assume success. */ } else { - if (!nm_platform_link_set_up(nm_device_get_platform(self), ifindex, no_firmware)) + r = nm_platform_link_change_flags(nm_device_get_platform(self), ifindex, IFF_UP, TRUE); + NM_SET_OUT(no_firmware, (r == -NME_PL_NO_FIRMWARE)); + if (r < 0) return FALSE; } @@ -14125,7 +14138,7 @@ nm_device_take_down(NMDevice *self, gboolean block) return; } - if (!nm_platform_link_set_down(nm_device_get_platform(self), ifindex)) + if (!nm_platform_link_change_flags(nm_device_get_platform(self), ifindex, IFF_UP, FALSE)) return; device_is_up = nm_device_is_up(self); @@ -14855,7 +14868,7 @@ _set_unmanaged_flags(NMDevice * self, flags, NM_PRINT_FMT_QUOTED(allow_state_transition, ", reason ", - reason_to_string_a(reason), + nm_device_state_reason_to_str_a(reason), transition_state ? ", transition-state" : "", "")); @@ -15044,20 +15057,6 @@ nm_device_set_unmanaged_by_quitting(NMDevice *self) /*****************************************************************************/ -void -nm_device_set_dhcp_anycast_address(NMDevice *self, const char *addr) -{ - NMDevicePrivate *priv; - - g_return_if_fail(NM_IS_DEVICE(self)); - g_return_if_fail(!addr || nm_utils_hwaddr_valid(addr, ETH_ALEN)); - - priv = NM_DEVICE_GET_PRIVATE(self); - - g_free(priv->dhcp_anycast_address); - priv->dhcp_anycast_address = g_strdup(addr); -} - void nm_device_reapply_settings_immediately(NMDevice *self) { @@ -15730,7 +15729,7 @@ _cancel_activation(NMDevice *self) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); if (priv->fw_call) { - nm_firewall_manager_cancel_call(priv->fw_call); + nm_firewalld_manager_cancel_call(priv->fw_call); nm_assert(!priv->fw_call); priv->fw_call = NULL; priv->fw_state = FIREWALL_STATE_INITIALIZED; @@ -15760,11 +15759,11 @@ _cleanup_generic_pre(NMDevice *self, CleanupType cleanup_type) if (cleanup_type == CLEANUP_TYPE_DECONFIGURE && priv->fw_state >= FIREWALL_STATE_INITIALIZED && priv->fw_mgr && !nm_device_sys_iface_state_is_external(self)) { - nm_firewall_manager_remove_from_zone(priv->fw_mgr, - nm_device_get_ip_iface(self), - NULL, - NULL, - NULL); + nm_firewalld_manager_remove_from_zone(priv->fw_mgr, + nm_device_get_ip_iface(self), + NULL, + NULL, + NULL); } priv->fw_state = FIREWALL_STATE_UNMANAGED; g_clear_object(&priv->fw_mgr); @@ -15846,7 +15845,7 @@ _cleanup_generic_post(NMDevice *self, CleanupType cleanup_type) /* Check if the device was deactivated, and if so, delete_link. * Don't call delete_link synchronously because we are currently * handling a state change -- which is not reentrant. */ - delete_on_deactivate_check_and_schedule(self, nm_device_get_ip_ifindex(self)); + delete_on_deactivate_check_and_schedule(self); } /* ip_iface should be cleared after flushing all routes and addresses, since @@ -15875,7 +15874,7 @@ nm_device_cleanup(NMDevice *self, NMDeviceStateReason reason, CleanupType cleanu else _LOGD(LOGD_DEVICE, "deactivating device (reason '%s') [%d]", - reason_to_string_a(reason), + nm_device_state_reason_to_str_a(reason), reason); /* Save whether or not we tried IPv6 for later */ @@ -15906,9 +15905,12 @@ nm_device_cleanup(NMDevice *self, NMDeviceStateReason reason, CleanupType cleanu nm_platform_ip_route_flush(platform, AF_UNSPEC, ifindex); nm_platform_ip_address_flush(platform, AF_UNSPEC, ifindex); - nm_platform_tfilter_sync(platform, ifindex, NULL); - nm_platform_qdisc_sync(platform, ifindex, NULL); set_ipv6_token(self, iid, "::"); + + if (nm_device_get_applied_setting(self, NM_TYPE_SETTING_TC_CONFIG)) { + nm_platform_tfilter_sync(platform, ifindex, NULL); + nm_platform_qdisc_sync(platform, ifindex, NULL); + } } } @@ -15927,8 +15929,7 @@ nm_device_cleanup(NMDevice *self, NMDeviceStateReason reason, CleanupType cleanu FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); - if (priv->lldp_listener) - nm_lldp_listener_stop(priv->lldp_listener); + lldp_setup(self, NM_TERNARY_FALSE); nm_device_update_metered(self); @@ -15979,6 +15980,14 @@ nm_device_cleanup(NMDevice *self, NMDeviceStateReason reason, CleanupType cleanu _ethtool_state_reset(self); + if (priv->promisc_reset != NM_OPTION_BOOL_DEFAULT && ifindex > 0) { + nm_platform_link_change_flags(nm_device_get_platform(self), + ifindex, + IFF_PROMISC, + !!priv->promisc_reset); + priv->promisc_reset = NM_OPTION_BOOL_DEFAULT; + } + _cleanup_generic_post(self, cleanup_type); } @@ -16093,7 +16102,8 @@ nm_device_spawn_iface_helper(NMDevice *self) hostname = nm_dhcp_client_get_hostname(priv->dhcp_data_4.client); if (hostname) { - if (nm_dhcp_client_get_use_fqdn(priv->dhcp_data_4.client)) + if (NM_FLAGS_HAS(nm_dhcp_client_get_client_flags(priv->dhcp_data_4.client), + NM_DHCP_CLIENT_FLAGS_USE_FQDN)) g_ptr_array_add(argv, g_strdup("--dhcp4-fqdn")); else g_ptr_array_add(argv, g_strdup("--dhcp4-hostname")); @@ -16360,8 +16370,8 @@ _set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason, "state change: %s -> %s (reason '%s', sys-iface-state: '%s'%s)", nm_device_state_to_str(old_state), nm_device_state_to_str(state), - reason_to_string_a(reason), - _sys_iface_state_to_str(priv->sys_iface_state), + nm_device_state_reason_to_str_a(reason), + nm_device_sys_iface_state_to_str(priv->sys_iface_state), priv->firmware_missing ? ", missing firmware" : ""); return; } @@ -16370,8 +16380,8 @@ _set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason, "state change: %s -> %s (reason '%s', sys-iface-state: '%s')", nm_device_state_to_str(old_state), nm_device_state_to_str(state), - reason_to_string_a(reason), - _sys_iface_state_to_str(priv->sys_iface_state)); + nm_device_state_reason_to_str_a(reason), + nm_device_sys_iface_state_to_str(priv->sys_iface_state)); /* in order to prevent triggering any callback caused * by the device not having any pending action anymore @@ -16717,7 +16727,7 @@ queued_state_set(gpointer user_data) _LOGD(LOGD_DEVICE, "queue-state[%s, reason:%s, id:%u]: %s", nm_device_state_to_str(priv->queued_state.state), - reason_to_string_a(priv->queued_state.reason), + nm_device_state_reason_to_str_a(priv->queued_state.reason), priv->queued_state.id, "change state"); @@ -16729,7 +16739,7 @@ queued_state_set(gpointer user_data) new_reason = priv->queued_state.reason; nm_device_state_changed(self, new_state, new_reason); - nm_device_remove_pending_action(self, queued_state_to_string(new_state), TRUE); + nm_device_remove_pending_action(self, nm_device_state_queued_state_to_str(new_state), TRUE); return G_SOURCE_REMOVE; } @@ -16747,12 +16757,12 @@ nm_device_queue_state(NMDevice *self, NMDeviceState state, NMDeviceStateReason r _LOGD(LOGD_DEVICE, "queue-state[%s, reason:%s, id:%u]: %s%s%s%s", nm_device_state_to_str(priv->queued_state.state), - reason_to_string_a(priv->queued_state.reason), + nm_device_state_reason_to_str_a(priv->queued_state.reason), priv->queued_state.id, "ignore queuing same state change", NM_PRINT_FMT_QUOTED(priv->queued_state.reason != reason, " (reason differs: ", - reason_to_string_a(reason), + nm_device_state_reason_to_str_a(reason), ")", "")); return; @@ -16760,20 +16770,21 @@ nm_device_queue_state(NMDevice *self, NMDeviceState state, NMDeviceStateReason r /* Add pending action for the new state before clearing the queued states, so * that we don't accidentally pop all pending states and reach 'startup complete' */ - nm_device_add_pending_action(self, queued_state_to_string(state), TRUE); + nm_device_add_pending_action(self, nm_device_state_queued_state_to_str(state), TRUE); /* We should only ever have one delayed state transition at a time */ if (priv->queued_state.id) { _LOGW(LOGD_DEVICE, "queue-state[%s, reason:%s, id:%u]: %s", nm_device_state_to_str(priv->queued_state.state), - reason_to_string_a(priv->queued_state.reason), + nm_device_state_reason_to_str_a(priv->queued_state.reason), priv->queued_state.id, "replace previously queued state change"); nm_clear_g_source(&priv->queued_state.id); - nm_device_remove_pending_action(self, - queued_state_to_string(priv->queued_state.state), - TRUE); + nm_device_remove_pending_action( + self, + nm_device_state_queued_state_to_str(priv->queued_state.state), + TRUE); } priv->queued_state.state = state; @@ -16783,7 +16794,7 @@ nm_device_queue_state(NMDevice *self, NMDeviceState state, NMDeviceStateReason r _LOGD(LOGD_DEVICE, "queue-state[%s, reason:%s, id:%u]: %s", nm_device_state_to_str(state), - reason_to_string_a(reason), + nm_device_state_reason_to_str_a(reason), priv->queued_state.id, "queue state change"); } @@ -16799,11 +16810,13 @@ queued_state_clear(NMDevice *self) _LOGD(LOGD_DEVICE, "queue-state[%s, reason:%s, id:%u]: %s", nm_device_state_to_str(priv->queued_state.state), - reason_to_string_a(priv->queued_state.reason), + nm_device_state_reason_to_str_a(priv->queued_state.reason), priv->queued_state.id, "clear queued state change"); nm_clear_g_source(&priv->queued_state.id); - nm_device_remove_pending_action(self, queued_state_to_string(priv->queued_state.state), TRUE); + nm_device_remove_pending_action(self, + nm_device_state_queued_state_to_str(priv->queued_state.state), + TRUE); } NMDeviceState @@ -16821,7 +16834,7 @@ const char * nm_device_get_hw_address(NMDevice *self) { NMDevicePrivate *priv; - char buf[NM_UTILS_HWADDR_LEN_MAX]; + char buf[_NM_UTILS_HWADDR_LEN_MAX]; gsize l; g_return_val_if_fail(NM_IS_DEVICE(self), NULL); @@ -16915,7 +16928,7 @@ void nm_device_update_permanent_hw_address(NMDevice *self, gboolean force_freeze) { NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - guint8 buf[NM_UTILS_HWADDR_LEN_MAX]; + guint8 buf[_NM_UTILS_HWADDR_LEN_MAX]; size_t len = 0; gboolean success_read; int ifindex; @@ -17033,7 +17046,7 @@ _hw_addr_set(NMDevice * self, NMDevicePrivate *priv; gboolean success = FALSE; int r; - guint8 addr_bytes[NM_UTILS_HWADDR_LEN_MAX]; + guint8 addr_bytes[_NM_UTILS_HWADDR_LEN_MAX]; gsize addr_len; gboolean was_taken_down = FALSE; gboolean retry_down; @@ -17234,14 +17247,13 @@ _hw_addr_get_cloned(NMDevice * self, gboolean * preserve, char ** hwaddr, HwAddrType * hwaddr_type, - char ** hwaddr_detail, + const char ** hwaddr_detail, GError ** error) { NMDevicePrivate *priv; - gs_free char * addr_setting_free = NULL; - gs_free char * hw_addr_generated = NULL; - gs_free char * generate_mac_address_mask_tmp = NULL; - const char * addr, *addr_setting; + gs_free char * hw_addr_generated = NULL; + const char * addr; + const char * addr_setting; char * addr_out; HwAddrType type_out; @@ -17254,15 +17266,16 @@ _hw_addr_get_cloned(NMDevice * self, if (!connection) g_return_val_if_reached(FALSE); - addr = addr_setting = - _prop_get_x_cloned_mac_address(self, connection, is_wifi, &addr_setting_free); + addr_setting = _prop_get_x_cloned_mac_address(self, connection, is_wifi); + + addr = addr_setting; if (nm_streq(addr, NM_CLONED_MAC_PRESERVE)) { /* "preserve" means to reset the initial MAC address. */ NM_SET_OUT(preserve, TRUE); NM_SET_OUT(hwaddr, NULL); NM_SET_OUT(hwaddr_type, HW_ADDR_TYPE_UNSET); - NM_SET_OUT(hwaddr_detail, g_steal_pointer(&addr_setting_free) ?: g_strdup(addr_setting)); + NM_SET_OUT(hwaddr_detail, addr_setting); return TRUE; } @@ -17275,8 +17288,7 @@ _hw_addr_get_cloned(NMDevice * self, NM_SET_OUT(preserve, TRUE); NM_SET_OUT(hwaddr, NULL); NM_SET_OUT(hwaddr_type, HW_ADDR_TYPE_UNSET); - NM_SET_OUT(hwaddr_detail, - g_steal_pointer(&addr_setting_free) ?: g_strdup(addr_setting)); + NM_SET_OUT(hwaddr_detail, addr_setting); return TRUE; } else if (!addr) { g_set_error_literal(error, @@ -17296,10 +17308,7 @@ _hw_addr_get_cloned(NMDevice * self, } hw_addr_generated = nm_utils_hw_addr_gen_random_eth( nm_device_get_initial_hw_address(self), - _prop_get_x_generate_mac_address_mask(self, - connection, - is_wifi, - &generate_mac_address_mask_tmp)); + _prop_get_x_generate_mac_address_mask(self, connection, is_wifi)); if (!hw_addr_generated) { g_set_error(error, NM_DEVICE_ERROR, @@ -17327,10 +17336,7 @@ _hw_addr_get_cloned(NMDevice * self, stable_id, nm_device_get_ip_iface(self), nm_device_get_initial_hw_address(self), - _prop_get_x_generate_mac_address_mask(self, - connection, - is_wifi, - &generate_mac_address_mask_tmp)); + _prop_get_x_generate_mac_address_mask(self, connection, is_wifi)); if (!hw_addr_generated) { g_set_error(error, NM_DEVICE_ERROR, @@ -17354,7 +17360,7 @@ _hw_addr_get_cloned(NMDevice * self, NM_SET_OUT(preserve, FALSE); NM_SET_OUT(hwaddr, addr_out); NM_SET_OUT(hwaddr_type, type_out); - NM_SET_OUT(hwaddr_detail, g_steal_pointer(&addr_setting_free) ?: g_strdup(addr_setting)); + NM_SET_OUT(hwaddr_detail, addr_setting); return TRUE; out_no_action: NM_SET_OUT(preserve, FALSE); @@ -17384,7 +17390,7 @@ nm_device_hw_addr_set_cloned(NMDevice *self, NMConnection *connection, gboolean NMDevicePrivate *priv; gboolean preserve = FALSE; gs_free char * hwaddr = NULL; - gs_free char * detail = NULL; + const char * detail = NULL; HwAddrType type = HW_ADDR_TYPE_UNSET; gs_free_error GError *error = NULL; @@ -17624,23 +17630,38 @@ hostname_dns_lookup_callback(GObject *source, GAsyncResult *result, gpointer use { HostnameResolver *resolver; NMDevice * self; - gs_free char * hostname = NULL; gs_free char * addr_str = NULL; + gs_free char * output = NULL; gs_free_error GError *error = NULL; - hostname = g_resolver_lookup_by_address_finish(G_RESOLVER(source), result, &error); + output = nm_device_resolve_address_finish(result, &error); if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; - resolver = user_data; - self = resolver->device; - resolver->state = RESOLVER_DONE; - resolver->hostname = g_strdup(hostname); + resolver = user_data; + self = resolver->device; + resolver->state = RESOLVER_DONE; - _LOGD(LOGD_DNS, - "hostname-from-dns: lookup done for %s, result %s%s%s", - (addr_str = g_inet_address_to_string(resolver->address)), - NM_PRINT_FMT_QUOTE_STRING(hostname)); + if (error) { + _LOGD(LOGD_DNS, + "hostname-from-dns: lookup error for %s: %s", + (addr_str = g_inet_address_to_string(resolver->address)), + error->message); + } else { + gboolean valid; + + resolver->hostname = g_steal_pointer(&output); + valid = nm_hostname_manager_validate_hostname(resolver->hostname); + + _LOGD(LOGD_DNS, + "hostname-from-dns: lookup done for %s, result %s%s%s%s", + (addr_str = g_inet_address_to_string(resolver->address)), + NM_PRINT_FMT_QUOTE_STRING(resolver->hostname), + valid ? "" : " (invalid)"); + + if (!valid) + g_clear_pointer(&resolver->hostname, g_free); + } nm_clear_g_cancellable(&resolver->cancellable); g_signal_emit(self, signals[DNS_LOOKUP_DONE], 0); @@ -17738,7 +17759,6 @@ nm_device_get_hostname_from_dns_lookup(NMDevice *self, int addr_family, gboolean if (!resolver) { resolver = g_slice_new(HostnameResolver); *resolver = (HostnameResolver){ - .resolver = g_resolver_get_default(), .device = self, .addr_family = addr_family, .state = RESOLVER_WAIT_ADDRESS, @@ -17746,13 +17766,36 @@ nm_device_get_hostname_from_dns_lookup(NMDevice *self, int addr_family, gboolean priv->hostname_resolver_x[IS_IPv4] = resolver; } - /* Determine the first address of the interface and - * whether it changed from the previous lookup */ + /* Determine the most suitable address of the interface + * and whether it changed from the previous lookup */ ip_config = priv->ip_config_x[IS_IPv4]; if (ip_config) { - const NMPlatformIPAddress *addr; + const NMPlatformIPAddress *addr = NULL; + + if (IS_IPv4) { + addr = nm_ip_config_get_first_address(ip_config); + } else { + /* For IPv6 prefer, in order: + * - !link-local, !deprecated + * - !link-local, deprecated + * - link-local + */ + addr = nm_ip_config_find_first_address(ip_config, + NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL); + if (!addr) { + addr = nm_ip_config_find_first_address( + ip_config, + NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_DEPRECATED); + } + if (!addr) { + addr = nm_ip_config_find_first_address(ip_config, + NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY); + } + } - addr = nm_ip_config_get_first_address(ip_config); if (addr) { new_address = g_inet_address_new_from_bytes(addr->address_ptr, IS_IPv4 ? G_SOCKET_FAMILY_IPV4 @@ -17788,20 +17831,15 @@ nm_device_get_hostname_from_dns_lookup(NMDevice *self, int addr_family, gboolean } if (address_changed && new_address) { - gs_free char *str = NULL; - - _LOGT(LOGD_DNS, - "hostname-from-dns: starting lookup for address %s", - (str = g_inet_address_to_string(new_address))); - resolver->state = RESOLVER_IN_PROGRESS; resolver->cancellable = g_cancellable_new(); resolver->address = g_steal_pointer(&new_address); - g_resolver_lookup_by_address_async(resolver->resolver, - resolver->address, - resolver->cancellable, - hostname_dns_lookup_callback, - resolver); + + nm_device_resolve_address(addr_family, + g_inet_address_to_bytes(resolver->address), + resolver->cancellable, + hostname_dns_lookup_callback, + resolver); nm_clear_g_source(&resolver->timeout_id); } @@ -17851,7 +17889,6 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NMDevice * self = NM_DEVICE(object); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - GVariantBuilder array_builder; switch (prop_id) { case PROP_UDI: @@ -18002,12 +18039,10 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) 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)); - } + g_value_set_variant(value, + priv->lldp_listener + ? nm_lldp_listener_get_neighbors(priv->lldp_listener) + : nm_g_variant_singleton_aaLsvI()); break; case PROP_REAL: g_value_set_boolean(value, nm_device_is_real(self)); @@ -18187,6 +18222,8 @@ nm_device_init(NMDevice *self) priv->v4_commit_first_time = TRUE; priv->v6_commit_first_time = TRUE; + + priv->promisc_reset = NM_OPTION_BOOL_DEFAULT; } static GObject * @@ -18216,7 +18253,7 @@ constructor(GType type, guint n_construct_params, GObjectConstructParam *constru } if (priv->hw_addr_perm) { - guint8 buf[NM_UTILS_HWADDR_LEN_MAX]; + guint8 buf[_NM_UTILS_HWADDR_LEN_MAX]; gsize l; if (!_nm_utils_hwaddr_aton(priv->hw_addr_perm, buf, sizeof(buf), &l)) { @@ -18364,13 +18401,7 @@ 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); - } + lldp_setup(self, FALSE); nm_clear_g_source(&priv->concheck_x[0].p_cur_id); nm_clear_g_source(&priv->concheck_x[1].p_cur_id); @@ -18413,7 +18444,6 @@ finalize(GObject *object) g_free(priv->driver_version); g_free(priv->firmware_version); g_free(priv->type_desc); - g_free(priv->dhcp_anycast_address); g_free(priv->current_stable_id); g_hash_table_unref(priv->ip6_saved_properties); @@ -18468,75 +18498,69 @@ static const NMDBusInterfaceInfoExtended interface_info_device = { .handle = impl_device_delete, ), ), .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&signal_info_state_changed, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Udi", "s", NM_DEVICE_UDI), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Path", "s", NM_DEVICE_PATH), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Interface", "s", NM_DEVICE_IFACE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("IpInterface", - "s", - NM_DEVICE_IP_IFACE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Driver", "s", NM_DEVICE_DRIVER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("DriverVersion", - "s", - NM_DEVICE_DRIVER_VERSION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("FirmwareVersion", - "s", - NM_DEVICE_FIRMWARE_VERSION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Capabilities", - "u", - NM_DEVICE_CAPABILITIES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Ip4Address", - "u", - NM_DEVICE_IP4_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("State", "u", NM_DEVICE_STATE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("StateReason", - "(uu)", - NM_DEVICE_STATE_REASON), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("ActiveConnection", - "o", - NM_DEVICE_ACTIVE_CONNECTION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Ip4Config", - "o", - NM_DEVICE_IP4_CONFIG), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Dhcp4Config", - "o", - NM_DEVICE_DHCP4_CONFIG), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Ip6Config", - "o", - NM_DEVICE_IP6_CONFIG), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Dhcp6Config", - "o", - NM_DEVICE_DHCP6_CONFIG), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L("Managed", - "b", - NM_DEVICE_MANAGED, - NM_AUTH_PERMISSION_NETWORK_CONTROL, - NM_AUDIT_OP_DEVICE_MANAGED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L("Autoconnect", - "b", - NM_DEVICE_AUTOCONNECT, - NM_AUTH_PERMISSION_NETWORK_CONTROL, - NM_AUDIT_OP_DEVICE_AUTOCONNECT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("FirmwareMissing", - "b", - NM_DEVICE_FIRMWARE_MISSING), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("NmPluginMissing", - "b", - NM_DEVICE_NM_PLUGIN_MISSING), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("DeviceType", - "u", - NM_DEVICE_DEVICE_TYPE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("AvailableConnections", - "ao", - NM_DEVICE_AVAILABLE_CONNECTIONS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("PhysicalPortId", - "s", - NM_DEVICE_PHYSICAL_PORT_ID), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Mtu", "u", NM_DEVICE_MTU), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Metered", "u", NM_DEVICE_METERED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("LldpNeighbors", - "aa{sv}", - NM_DEVICE_LLDP_NEIGHBORS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Real", "b", NM_DEVICE_REAL), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Udi", "s", NM_DEVICE_UDI), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Path", "s", NM_DEVICE_PATH), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Interface", "s", NM_DEVICE_IFACE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("IpInterface", "s", NM_DEVICE_IP_IFACE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Driver", "s", NM_DEVICE_DRIVER), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("DriverVersion", + "s", + NM_DEVICE_DRIVER_VERSION), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("FirmwareVersion", + "s", + NM_DEVICE_FIRMWARE_VERSION), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Capabilities", + "u", + NM_DEVICE_CAPABILITIES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Ip4Address", + "u", + NM_DEVICE_IP4_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("State", "u", NM_DEVICE_STATE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("StateReason", + "(uu)", + NM_DEVICE_STATE_REASON), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("ActiveConnection", + "o", + NM_DEVICE_ACTIVE_CONNECTION), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Ip4Config", "o", NM_DEVICE_IP4_CONFIG), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Dhcp4Config", + "o", + NM_DEVICE_DHCP4_CONFIG), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Ip6Config", "o", NM_DEVICE_IP6_CONFIG), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Dhcp6Config", + "o", + NM_DEVICE_DHCP6_CONFIG), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE("Managed", + "b", + NM_DEVICE_MANAGED, + NM_AUTH_PERMISSION_NETWORK_CONTROL, + NM_AUDIT_OP_DEVICE_MANAGED), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE("Autoconnect", + "b", + NM_DEVICE_AUTOCONNECT, + NM_AUTH_PERMISSION_NETWORK_CONTROL, + NM_AUDIT_OP_DEVICE_AUTOCONNECT), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("FirmwareMissing", + "b", + NM_DEVICE_FIRMWARE_MISSING), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("NmPluginMissing", + "b", + NM_DEVICE_NM_PLUGIN_MISSING), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("DeviceType", + "u", + NM_DEVICE_DEVICE_TYPE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("AvailableConnections", + "ao", + NM_DEVICE_AVAILABLE_CONNECTIONS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("PhysicalPortId", + "s", + NM_DEVICE_PHYSICAL_PORT_ID), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Mtu", "u", NM_DEVICE_MTU), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Metered", "u", NM_DEVICE_METERED), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("LldpNeighbors", + "aa{sv}", + NM_DEVICE_LLDP_NEIGHBORS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Real", "b", NM_DEVICE_REAL), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Ip4Connectivity", "u", NM_DEVICE_IP4_CONNECTIVITY), @@ -18551,10 +18575,9 @@ static const NMDBusInterfaceInfoExtended interface_info_device = { NM_DEVICE_HW_ADDRESS), ), ), }; -const NMDBusInterfaceInfoExtended nm_interface_info_device_statistics = { +static const NMDBusInterfaceInfoExtended interface_info_device_statistics = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_STATISTICS, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE( "RefreshRateMs", @@ -18580,7 +18603,7 @@ nm_device_class_init(NMDeviceClass *klass) dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED(NM_DBUS_PATH "/Devices"); dbus_object_class->interface_infos = - NM_DBUS_INTERFACE_INFOS(&interface_info_device, &nm_interface_info_device_statistics); + NM_DBUS_INTERFACE_INFOS(&interface_info_device, &interface_info_device_statistics); object_class->dispose = dispose; object_class->finalize = finalize; diff --git a/src/core/devices/nm-device.h b/src/core/devices/nm-device.h index 72777d0a..53211c6f 100644 --- a/src/core/devices/nm-device.h +++ b/src/core/devices/nm-device.h @@ -15,54 +15,7 @@ #include "nm-connection.h" #include "nm-rfkill-manager.h" #include "NetworkManagerUtils.h" - -typedef enum _nm_packed { - NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, - NM_DEVICE_SYS_IFACE_STATE_ASSUME, - NM_DEVICE_SYS_IFACE_STATE_MANAGED, - - /* the REMOVED state applies when the device is manually set to unmanaged - * or the link was externally removed. In both cases, we move the device - * to UNMANAGED state, without touching the link -- be it, because the link - * is already gone or because we want to release it (give it up). - */ - NM_DEVICE_SYS_IFACE_STATE_REMOVED, -} NMDeviceSysIfaceState; - -typedef enum { - NM_DEVICE_MTU_SOURCE_NONE, - NM_DEVICE_MTU_SOURCE_PARENT, - NM_DEVICE_MTU_SOURCE_IP_CONFIG, - NM_DEVICE_MTU_SOURCE_CONNECTION, -} NMDeviceMtuSource; - -static inline NMDeviceStateReason -nm_device_state_reason_check(NMDeviceStateReason reason) -{ - /* the device-state-reason serves mostly informational purpose during a state - * change. In some cases however, decisions are made based on the reason. - * I tend to think that interpreting the state reason to derive some behaviors - * is confusing, because the cause and effect are so far apart. - * - * This function is here to mark source that inspects the reason to make - * a decision -- contrary to places that set the reason. Thus, by grepping - * for nm_device_state_reason_check() you can find the "effect" to a certain - * reason. - */ - return reason; -} - -#define NM_PENDING_ACTION_AUTOACTIVATE "autoactivate" -#define NM_PENDING_ACTION_IN_STATE_CHANGE "in-state-change" -#define NM_PENDING_ACTION_RECHECK_AVAILABLE "recheck-available" -#define NM_PENDING_ACTION_CARRIER_WAIT "carrier-wait" -#define NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT "waiting-for-supplicant" -#define NM_PENDING_ACTION_WIFI_SCAN "wifi-scan" -#define NM_PENDING_ACTION_WAITING_FOR_COMPANION "waiting-for-companion" -#define NM_PENDING_ACTION_LINK_INIT "link-init" - -#define NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "queued-state-change-" -#define NM_PENDING_ACTIONPREFIX_ACTIVATION "activation-" +#include "nm-device-utils.h" /* Properties */ #define NM_DEVICE_UDI "udi" @@ -109,10 +62,10 @@ nm_device_state_reason_check(NMDeviceStateReason reason) * NMDeviceOvsBridge and NMDeviceOvsPort. */ #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 */ -#define NM_DEVICE_IFINDEX "ifindex" /* Internal only */ -#define NM_DEVICE_MASTER "master" /* Internal only */ +#define NM_DEVICE_TYPE_DESC "type-desc" /* Internal only */ +#define NM_DEVICE_RFKILL_TYPE "rfkill-type" /* Internal only */ +#define NM_DEVICE_IFINDEX "ifindex" /* Internal only */ +#define NM_DEVICE_MASTER "master" /* Internal only */ #define NM_DEVICE_HAS_PENDING_ACTION "has-pending-action" /* Internal only */ /* Internal signals */ @@ -459,6 +412,8 @@ typedef struct _NMDeviceClass { gboolean (*set_platform_mtu)(NMDevice *self, guint32 mtu); + const char *(*get_dhcp_anycast_address)(NMDevice *self); + } NMDeviceClass; GType nm_device_get_type(void); @@ -627,27 +582,28 @@ void nm_device_copy_ip6_dns_config(NMDevice *self, NMDevice *from_device); * setting the NM_UNMANAGED_IS_SLAVE to %TRUE makes no sense, this flag has only * meaning to set a slave device as managed if the parent is managed too. */ -typedef enum { /*< skip >*/ - NM_UNMANAGED_NONE = 0, +typedef enum { + NM_UNMANAGED_NONE = 0, - /* these flags are authoritative. If one of them is set, + /* these flags are authoritative. If one of them is set, * the device cannot be managed. */ - NM_UNMANAGED_SLEEPING = (1LL << 0), - NM_UNMANAGED_QUITTING = (1LL << 1), - NM_UNMANAGED_PARENT = (1LL << 2), - NM_UNMANAGED_BY_TYPE = (1LL << 3), - NM_UNMANAGED_PLATFORM_INIT = (1LL << 4), - NM_UNMANAGED_USER_EXPLICIT = (1LL << 5), - NM_UNMANAGED_USER_SETTINGS = (1LL << 6), - - /* These flags can be non-effective and be overwritten + NM_UNMANAGED_SLEEPING = (1LL << 0), + NM_UNMANAGED_QUITTING = (1LL << 1), + NM_UNMANAGED_PARENT = (1LL << 2), + NM_UNMANAGED_BY_TYPE = (1LL << 3), + NM_UNMANAGED_PLATFORM_INIT = (1LL << 4), + NM_UNMANAGED_USER_EXPLICIT = (1LL << 5), + NM_UNMANAGED_USER_SETTINGS = (1LL << 6), + + /* These flags can be non-effective and be overwritten * by other flags. */ - NM_UNMANAGED_BY_DEFAULT = (1LL << 8), - NM_UNMANAGED_USER_CONF = (1LL << 9), - NM_UNMANAGED_USER_UDEV = (1LL << 10), - NM_UNMANAGED_EXTERNAL_DOWN = (1LL << 11), - NM_UNMANAGED_IS_SLAVE = (1LL << 12), + NM_UNMANAGED_BY_DEFAULT = (1LL << 7), + NM_UNMANAGED_USER_CONF = (1LL << 8), + NM_UNMANAGED_USER_UDEV = (1LL << 9), + NM_UNMANAGED_EXTERNAL_DOWN = (1LL << 10), + NM_UNMANAGED_IS_SLAVE = (1LL << 11), + NM_UNMANAGED_ALL = ((1LL << 12) - 1), } NMUnmanagedFlags; typedef enum { @@ -861,9 +817,6 @@ struct _NMBtVTableNetworkServer { gboolean (*unregister_bridge)(const NMBtVTableNetworkServer *vtable, NMDevice *device); }; -const char *nm_device_state_to_str(NMDeviceState state); -const char *nm_device_state_reason_to_str(NMDeviceStateReason reason); - gboolean nm_device_is_vpn(NMDevice *self); const char * diff --git a/src/core/devices/nm-lldp-listener.c b/src/core/devices/nm-lldp-listener.c index c60fb3ad..aba972ae 100644 --- a/src/core/devices/nm-lldp-listener.c +++ b/src/core/devices/nm-lldp-listener.c @@ -9,12 +9,15 @@ #include -#include "nm-std-aux/unaligned.h" -#include "platform/nm-platform.h" -#include "nm-glib-aux/nm-c-list.h" +#include "NetworkManagerUtils.h" +#include "libnm-core-public/nm-errors.h" +#include "libnm-glib-aux/nm-time-utils.h" +#include "libnm-std-aux/unaligned.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-glib-aux/nm-c-list.h" #include "nm-utils.h" -#include "systemd/nm-sd.h" +#include "libnm-systemd-core/nm-sd.h" #define MAX_NEIGHBORS 128 #define MIN_UPDATE_INTERVAL_NSEC (2 * NM_UTILS_NSEC_PER_SEC) @@ -28,34 +31,21 @@ /*****************************************************************************/ -NM_GOBJECT_PROPERTIES_DEFINE(NMLldpListener, PROP_NEIGHBORS, ); - -typedef struct { +struct _NMLldpListener { sd_lldp * lldp_handle; GHashTable *lldp_neighbors; GVariant * variant; + NMLldpListenerNotify notify_callback; + gpointer notify_user_data; + /* the timestamp in nsec until which we delay updates. */ - gint64 ratelimit_next_nsec; - guint ratelimit_id; + GSource *ratelimit_source; + gint64 ratelimit_next_nsec; int ifindex; -} NMLldpListenerPrivate; - -struct _NMLldpListener { - GObject parent; - NMLldpListenerPrivate _priv; -}; - -struct _NMLldpListenerClass { - GObjectClass parent; }; -G_DEFINE_TYPE(NMLldpListener, nm_lldp_listener, G_TYPE_OBJECT) - -#define NM_LLDP_LISTENER_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMLldpListener, NM_IS_LLDP_LISTENER) - /*****************************************************************************/ typedef struct { @@ -71,27 +61,28 @@ typedef struct { #define _NMLOG_PREFIX_NAME "lldp" #define _NMLOG_DOMAIN LOGD_DEVICE -#define _NMLOG(level, ...) \ - G_STMT_START \ - { \ - const NMLogLevel _level = (level); \ - \ - if (nm_logging_enabled(_level, _NMLOG_DOMAIN)) { \ - char _sbuf[64]; \ - int _ifindex = (self) ? NM_LLDP_LISTENER_GET_PRIVATE(self)->ifindex : 0; \ - \ - _nm_log(_level, \ - _NMLOG_DOMAIN, \ - 0, \ - _ifindex > 0 ? nm_platform_link_get_name(NM_PLATFORM_GET, _ifindex) : NULL, \ - NULL, \ - "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - _NMLOG_PREFIX_NAME, \ - ((_ifindex > 0) ? nm_sprintf_buf(_sbuf, "[%p,%d]", (self), _ifindex) \ - : ((self) ? nm_sprintf_buf(_sbuf, "[%p]", (self)) : "")) \ - _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } \ +#define _NMLOG(level, ...) \ + G_STMT_START \ + { \ + const NMLogLevel _level = (level); \ + \ + if (nm_logging_enabled(_level, _NMLOG_DOMAIN)) { \ + char _sbuf[100]; \ + \ + _nm_log(_level, \ + _NMLOG_DOMAIN, \ + 0, \ + (self) ? nm_platform_link_get_name(NM_PLATFORM_GET, (self)->ifindex) : NULL, \ + NULL, \ + "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + _NMLOG_PREFIX_NAME, \ + ((self) ? nm_sprintf_buf(_sbuf, \ + "[" NM_HASH_OBFUSCATE_PTR_FMT ",%d]", \ + NM_HASH_OBFUSCATE_PTR(self), \ + (self)->ifindex) \ + : "") _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } \ G_STMT_END #define LOG_NEIGH_FMT "CHASSIS=%u/%s PORT=%u/%s" @@ -809,80 +800,73 @@ nmtst_lldp_parse_from_raw(const guint8 *raw_data, gsize raw_len) /*****************************************************************************/ static void -data_changed_notify(NMLldpListener *self, NMLldpListenerPrivate *priv) +data_changed_notify(NMLldpListener *self) { - nm_clear_g_variant(&priv->variant); - _notify(self, PROP_NEIGHBORS); + nm_clear_g_variant(&self->variant); + + self->notify_callback(self, self->notify_user_data); } static gboolean data_changed_timeout(gpointer user_data) { - NMLldpListener * self = user_data; - NMLldpListenerPrivate *priv; + NMLldpListener *self = user_data; - g_return_val_if_fail(NM_IS_LLDP_LISTENER(self), G_SOURCE_REMOVE); - - priv = NM_LLDP_LISTENER_GET_PRIVATE(self); - - priv->ratelimit_id = 0; - priv->ratelimit_next_nsec = nm_utils_get_monotonic_timestamp_nsec() + MIN_UPDATE_INTERVAL_NSEC; - data_changed_notify(self, priv); - return G_SOURCE_REMOVE; + nm_clear_g_source_inst(&self->ratelimit_source); + self->ratelimit_next_nsec = nm_utils_get_monotonic_timestamp_nsec() + MIN_UPDATE_INTERVAL_NSEC; + data_changed_notify(self); + return G_SOURCE_CONTINUE; } static void data_changed_schedule(NMLldpListener *self) { - NMLldpListenerPrivate *priv = NM_LLDP_LISTENER_GET_PRIVATE(self); - gint64 now_nsec; + gint64 now_nsec; - if (priv->ratelimit_id != 0) + if (self->ratelimit_source) return; now_nsec = nm_utils_get_monotonic_timestamp_nsec(); - if (now_nsec < priv->ratelimit_next_nsec) { - priv->ratelimit_id = - g_timeout_add_full(G_PRIORITY_LOW, - NM_UTILS_NSEC_TO_MSEC_CEIL(priv->ratelimit_next_nsec - now_nsec), - data_changed_timeout, - self, - NULL); - return; + if (now_nsec < self->ratelimit_next_nsec) { + self->ratelimit_source = nm_g_timeout_source_new( + NM_UTILS_NSEC_TO_MSEC_CEIL(self->ratelimit_next_nsec - now_nsec), + G_PRIORITY_LOW, + data_changed_timeout, + self, + NULL); + } else { + self->ratelimit_source = + nm_g_idle_source_new(G_PRIORITY_LOW, data_changed_timeout, self, NULL); } - priv->ratelimit_id = g_idle_add_full(G_PRIORITY_LOW, data_changed_timeout, self, NULL); + g_source_attach(self->ratelimit_source, NULL); } static void process_lldp_neighbor(NMLldpListener *self, sd_lldp_neighbor *neighbor_sd, gboolean remove) { - NMLldpListenerPrivate * priv; nm_auto(lldp_neighbor_freep) LldpNeighbor *neigh = NULL; LldpNeighbor * neigh_old; - g_return_if_fail(NM_IS_LLDP_LISTENER(self)); + nm_assert(self); + nm_assert(self->lldp_handle); + nm_assert(self->lldp_neighbors); - priv = NM_LLDP_LISTENER_GET_PRIVATE(self); - - g_return_if_fail(priv->lldp_handle); g_return_if_fail(neighbor_sd); - nm_assert(priv->lldp_neighbors); - neigh = lldp_neighbor_new(neighbor_sd); if (!neigh) { _LOGT("process: failed to parse neighbor"); return; } - neigh_old = g_hash_table_lookup(priv->lldp_neighbors, neigh); + neigh_old = g_hash_table_lookup(self->lldp_neighbors, neigh); if (remove) { if (neigh_old) { _LOGT("process: %s neigh: " LOG_NEIGH_FMT, "remove", LOG_NEIGH_ARG(neigh)); - g_hash_table_remove(priv->lldp_neighbors, neigh_old); + g_hash_table_remove(self->lldp_neighbors, neigh_old); goto handle_changed; } return; @@ -893,14 +877,14 @@ process_lldp_neighbor(NMLldpListener *self, sd_lldp_neighbor *neighbor_sd, gbool _LOGD("process: %s neigh: " LOG_NEIGH_FMT, neigh_old ? "update" : "new", LOG_NEIGH_ARG(neigh)); - g_hash_table_add(priv->lldp_neighbors, g_steal_pointer(&neigh)); + g_hash_table_add(self->lldp_neighbors, g_steal_pointer(&neigh)); handle_changed: data_changed_schedule(self); } static void -lldp_event_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata) +lldp_event_handler(sd_lldp *lldp, sd_lldp_event_t event, sd_lldp_neighbor *n, void *userdata) { process_lldp_neighbor( userdata, @@ -908,25 +892,57 @@ lldp_event_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void !NM_IN_SET(event, SD_LLDP_EVENT_ADDED, SD_LLDP_EVENT_UPDATED, SD_LLDP_EVENT_REFRESHED)); } -gboolean -nm_lldp_listener_start(NMLldpListener *self, int ifindex, GError **error) +/*****************************************************************************/ + +int +nm_lldp_listener_get_ifindex(NMLldpListener *self) { - NMLldpListenerPrivate *priv; - int ret; + g_return_val_if_fail(self, 0); - g_return_val_if_fail(NM_IS_LLDP_LISTENER(self), FALSE); - g_return_val_if_fail(ifindex > 0, FALSE); - g_return_val_if_fail(!error || !*error, FALSE); + return self->ifindex; +} - 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; +GVariant * +nm_lldp_listener_get_neighbors(NMLldpListener *self) +{ + g_return_val_if_fail(self, FALSE); + + if (G_UNLIKELY(!self->variant)) { + gs_free LldpNeighbor **neighbors = NULL; + GVariantBuilder array_builder; + guint i, n; + + g_variant_builder_init(&array_builder, G_VARIANT_TYPE("aa{sv}")); + neighbors = (LldpNeighbor **) + nm_utils_hash_keys_to_array(self->lldp_neighbors, lldp_neighbor_id_cmp_p, NULL, &n); + for (i = 0; i < n; i++) + g_variant_builder_add_value(&array_builder, lldp_neighbor_to_variant(neighbors[i])); + self->variant = g_variant_ref_sink(g_variant_builder_end(&array_builder)); } - ret = sd_lldp_new(&priv->lldp_handle); - if (ret < 0) { + return self->variant; +} + +/*****************************************************************************/ + +NMLldpListener * +nm_lldp_listener_new(int ifindex, + NMLldpListenerNotify notify_callback, + gpointer notify_user_data, + GError ** error) +{ + NMLldpListener *self = NULL; + sd_lldp * lldp_handle; + int r; + + g_return_val_if_fail(ifindex > 0, FALSE); + g_return_val_if_fail(!error || !*error, FALSE); + g_return_val_if_fail(notify_callback, FALSE); + + r = sd_lldp_new(&lldp_handle); + if (r < 0) { g_set_error_literal(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, @@ -934,189 +950,77 @@ nm_lldp_listener_start(NMLldpListener *self, int ifindex, GError **error) return FALSE; } - ret = sd_lldp_set_ifindex(priv->lldp_handle, ifindex); - if (ret < 0) { + r = sd_lldp_set_ifindex(lldp_handle, ifindex); + if (r < 0) { g_set_error_literal(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "failed setting ifindex"); - goto err; + goto fail_handle; } - ret = sd_lldp_set_callback(priv->lldp_handle, lldp_event_handler, self); - if (ret < 0) { - g_set_error_literal(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "set callback failed"); - goto err; - } + r = sd_lldp_set_neighbors_max(lldp_handle, MAX_NEIGHBORS); + nm_assert(r == 0); - ret = sd_lldp_set_neighbors_max(priv->lldp_handle, MAX_NEIGHBORS); - nm_assert(ret == 0); + self = g_slice_new(NMLldpListener); + *self = (NMLldpListener){ + .ifindex = ifindex, + .notify_callback = notify_callback, + .notify_user_data = notify_user_data, + }; - priv->ifindex = ifindex; + r = sd_lldp_set_callback(lldp_handle, lldp_event_handler, self); + if (r < 0) { + g_set_error_literal(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "set callback failed"); + goto fail_handle; + } - ret = sd_lldp_attach_event(priv->lldp_handle, NULL, 0); - if (ret < 0) { + r = sd_lldp_attach_event(lldp_handle, NULL, 0); + if (r < 0) { g_set_error_literal(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "attach event failed"); - goto err_free; + goto fail_attached; } - ret = sd_lldp_start(priv->lldp_handle); - if (ret < 0) { + r = sd_lldp_start(lldp_handle); + if (r < 0) { g_set_error_literal(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "start failed"); - goto err; + goto fail_attached; } - priv->lldp_neighbors = g_hash_table_new_full(lldp_neighbor_id_hash, + self->lldp_neighbors = g_hash_table_new_full(lldp_neighbor_id_hash, lldp_neighbor_id_equal, (GDestroyNotify) lldp_neighbor_free, NULL); - - _LOGD("start"); - - return TRUE; - -err: - sd_lldp_detach_event(priv->lldp_handle); -err_free: - sd_lldp_unref(priv->lldp_handle); - priv->lldp_handle = NULL; - priv->ifindex = 0; - return FALSE; + self->lldp_handle = lldp_handle; + + _LOGD("start lldp listener"); + return self; + +fail_attached: + sd_lldp_detach_event(lldp_handle); +fail_handle: + if (self) + nm_g_slice_free(self); + sd_lldp_unref(lldp_handle); + return NULL; } void -nm_lldp_listener_stop(NMLldpListener *self) +nm_lldp_listener_destroy(NMLldpListener *self) { - NMLldpListenerPrivate *priv; - guint size; - gboolean changed = FALSE; - - g_return_if_fail(NM_IS_LLDP_LISTENER(self)); - priv = NM_LLDP_LISTENER_GET_PRIVATE(self); - - if (priv->lldp_handle) { - _LOGD("stop"); - sd_lldp_stop(priv->lldp_handle); - sd_lldp_detach_event(priv->lldp_handle); - sd_lldp_unref(priv->lldp_handle); - priv->lldp_handle = NULL; - - size = g_hash_table_size(priv->lldp_neighbors); - g_hash_table_remove_all(priv->lldp_neighbors); - nm_clear_pointer(&priv->lldp_neighbors, g_hash_table_unref); - if (size > 0 || priv->ratelimit_id != 0) - changed = TRUE; - } + g_return_if_fail(self); - nm_clear_g_source(&priv->ratelimit_id); - priv->ratelimit_next_nsec = 0; - priv->ifindex = 0; + sd_lldp_stop(self->lldp_handle); + sd_lldp_detach_event(self->lldp_handle); + sd_lldp_unref(self->lldp_handle); - if (changed) - data_changed_notify(self, priv); -} - -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) -{ - NMLldpListenerPrivate *priv; - - g_return_val_if_fail(NM_IS_LLDP_LISTENER(self), FALSE); - - priv = NM_LLDP_LISTENER_GET_PRIVATE(self); - - if (G_UNLIKELY(!priv->variant)) { - gs_free LldpNeighbor **neighbors = NULL; - GVariantBuilder array_builder; - guint i, n; - - g_variant_builder_init(&array_builder, G_VARIANT_TYPE("aa{sv}")); - neighbors = (LldpNeighbor **) - nm_utils_hash_keys_to_array(priv->lldp_neighbors, lldp_neighbor_id_cmp_p, NULL, &n); - for (i = 0; i < n; i++) - g_variant_builder_add_value(&array_builder, lldp_neighbor_to_variant(neighbors[i])); - priv->variant = g_variant_ref_sink(g_variant_builder_end(&array_builder)); - } - 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) -{ - _LOGT("lldp listener created"); -} + nm_clear_g_source_inst(&self->ratelimit_source); -NMLldpListener * -nm_lldp_listener_new(void) -{ - return g_object_new(NM_TYPE_LLDP_LISTENER, NULL); -} + g_hash_table_destroy(self->lldp_neighbors); -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); - - nm_clear_g_variant(&priv->variant); + nm_g_variant_unref(self->variant); _LOGT("lldp listener destroyed"); - 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); - - object_class->dispose = dispose; - object_class->finalize = finalize; - object_class->get_property = get_property; - - obj_properties[PROP_NEIGHBORS] = - g_param_spec_variant(NM_LLDP_LISTENER_NEIGHBORS, - "", - "", - G_VARIANT_TYPE("aa{sv}"), - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); + nm_g_slice_free(self); } diff --git a/src/core/devices/nm-lldp-listener.h b/src/core/devices/nm-lldp-listener.h index 9d3e2436..762eb3d2 100644 --- a/src/core/devices/nm-lldp-listener.h +++ b/src/core/devices/nm-lldp-listener.h @@ -6,28 +6,21 @@ #ifndef __NM_LLDP_LISTENER__ #define __NM_LLDP_LISTENER__ -#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" - -typedef struct _NMLldpListenerClass NMLldpListenerClass; - -GType nm_lldp_listener_get_type(void); -NMLldpListener *nm_lldp_listener_new(void); -gboolean nm_lldp_listener_start(NMLldpListener *self, int ifindex, GError **error); -void nm_lldp_listener_stop(NMLldpListener *self); -gboolean nm_lldp_listener_is_running(NMLldpListener *self); +/*****************************************************************************/ +typedef void (*NMLldpListenerNotify)(NMLldpListener *self, gpointer user_data); + +NMLldpListener *nm_lldp_listener_new(int ifindex, + NMLldpListenerNotify notify_callback, + gpointer notify_user_data, + GError ** error); +void nm_lldp_listener_destroy(NMLldpListener *self); + +int nm_lldp_listener_get_ifindex(NMLldpListener *self); GVariant *nm_lldp_listener_get_neighbors(NMLldpListener *self); +/*****************************************************************************/ + GVariant *nmtst_lldp_parse_from_raw(const guint8 *raw_data, gsize raw_len); #endif /* __NM_LLDP_LISTENER__ */ diff --git a/src/core/devices/ovs/meson.build b/src/core/devices/ovs/meson.build index 81c29bd6..1974ff4c 100644 --- a/src/core/devices/ovs/meson.build +++ b/src/core/devices/ovs/meson.build @@ -13,7 +13,6 @@ libnm_device_plugin_ovs = shared_module( core_plugin_dep, jansson_dep, ], - c_args: daemon_c_flags, link_args: ldflags_linker_script_devices, link_depends: linker_script_devices, install: true, diff --git a/src/core/devices/ovs/nm-device-ovs-bridge.c b/src/core/devices/ovs/nm-device-ovs-bridge.c index 3ae8a481..26a5ba00 100644 --- a/src/core/devices/ovs/nm-device-ovs-bridge.c +++ b/src/core/devices/ovs/nm-device-ovs-bridge.c @@ -16,7 +16,7 @@ #include "nm-setting-connection.h" #include "nm-setting-ovs-bridge.h" #include "nm-setting-ovs-external-ids.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #define _NMLOG_DEVICE_TYPE NMDeviceOvsBridge #include "devices/nm-device-logging.h" @@ -134,9 +134,7 @@ static const NMDBusInterfaceInfoExtended interface_info_device_ovs_bridge = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_OVS_BRIDGE, .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Slaves", "ao", NM_DEVICE_SLAVES), ), - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Slaves", "ao", NM_DEVICE_SLAVES), ), ), }; static void diff --git a/src/core/devices/ovs/nm-device-ovs-interface.c b/src/core/devices/ovs/nm-device-ovs-interface.c index 5d07c211..46a612ac 100644 --- a/src/core/devices/ovs/nm-device-ovs-interface.c +++ b/src/core/devices/ovs/nm-device-ovs-interface.c @@ -77,6 +77,15 @@ is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) return nm_ovsdb_is_ready(priv->ovsdb); } +static gboolean +can_auto_connect(NMDevice *device, NMSettingsConnection *sett_conn, char **specific_object) +{ + NMDeviceOvsInterface * self = NM_DEVICE_OVS_INTERFACE(device); + NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self); + + return nm_ovsdb_is_ready(priv->ovsdb); +} + static gboolean check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error) { @@ -405,10 +414,7 @@ dispose(GObject *object) } static const NMDBusInterfaceInfoExtended interface_info_device_ovs_interface = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_OVS_INTERFACE, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), ), - .legacy_property_changed = TRUE, + .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT(NM_DBUS_INTERFACE_DEVICE_OVS_INTERFACE, ), }; static void @@ -427,6 +433,7 @@ nm_device_ovs_interface_class_init(NMDeviceOvsInterfaceClass *klass) device_class->connection_type_check_compatible = NM_SETTING_OVS_INTERFACE_SETTING_NAME; device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_OPENVSWITCH); + device_class->can_auto_connect = can_auto_connect; device_class->can_update_from_platform_link = can_update_from_platform_link; device_class->deactivate = deactivate; device_class->deactivate_async = deactivate_async; diff --git a/src/core/devices/ovs/nm-device-ovs-port.c b/src/core/devices/ovs/nm-device-ovs-port.c index 2ecb95e8..f11c5852 100644 --- a/src/core/devices/ovs/nm-device-ovs-port.c +++ b/src/core/devices/ovs/nm-device-ovs-port.c @@ -167,9 +167,7 @@ static const NMDBusInterfaceInfoExtended interface_info_device_ovs_port = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_OVS_PORT, .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Slaves", "ao", NM_DEVICE_SLAVES), ), - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Slaves", "ao", NM_DEVICE_SLAVES), ), ), }; static void diff --git a/src/core/devices/ovs/nm-ovs-factory.c b/src/core/devices/ovs/nm-ovs-factory.c index e7af38d8..6f5d8832 100644 --- a/src/core/devices/ovs/nm-ovs-factory.c +++ b/src/core/devices/ovs/nm-ovs-factory.c @@ -10,8 +10,8 @@ #include "nm-device-ovs-interface.h" #include "nm-device-ovs-port.h" #include "nm-device-ovs-bridge.h" -#include "platform/nm-platform.h" -#include "nm-core-internal.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-core-intern/nm-core-internal.h" #include "settings/nm-settings.h" #include "devices/nm-device-factory.h" #include "devices/nm-device-private.h" diff --git a/src/core/devices/ovs/nm-ovsdb.c b/src/core/devices/ovs/nm-ovsdb.c index da3a7989..b8d5311a 100644 --- a/src/core/devices/ovs/nm-ovsdb.c +++ b/src/core/devices/ovs/nm-ovsdb.c @@ -10,10 +10,10 @@ #include #include -#include "nm-glib-aux/nm-jansson.h" -#include "nm-glib-aux/nm-str-buf.h" +#include "libnm-glib-aux/nm-jansson.h" +#include "libnm-glib-aux/nm-str-buf.h" #include "nm-core-utils.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "devices/nm-device.h" #include "nm-manager.h" #include "nm-setting-ovs-external-ids.h" diff --git a/src/core/devices/team/meson.build b/src/core/devices/team/meson.build index d0ff4caa..b1ee9103 100644 --- a/src/core/devices/team/meson.build +++ b/src/core/devices/team/meson.build @@ -11,7 +11,6 @@ libnm_device_plugin_team = shared_module( jansson_dep, libteamdctl_dep, ], - c_args: daemon_c_flags, link_args: ldflags_linker_script_devices, link_depends: linker_script_devices, install: true, diff --git a/src/core/devices/team/nm-device-team.c b/src/core/devices/team/nm-device-team.c index d2d71729..0f1a8c4c 100644 --- a/src/core/devices/team/nm-device-team.c +++ b/src/core/devices/team/nm-device-team.c @@ -15,15 +15,15 @@ #include #include -#include "nm-glib-aux/nm-jansson.h" +#include "libnm-glib-aux/nm-jansson.h" #include "NetworkManagerUtils.h" #include "devices/nm-device-private.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-config.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-dbus-manager.h" #include "nm-ip4-config.h" -#include "nm-std-aux/nm-dbus-compat.h" +#include "libnm-std-aux/nm-dbus-compat.h" #define _NMLOG_DEVICE_TYPE NMDeviceTeam #include "devices/nm-device-logging.h" @@ -829,12 +829,12 @@ enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gbool "enslaved team port %s config not changed, not connected to teamd", slave_iface); } else { - int err; - char *sanitized_config; + gs_free char *sanitized_config = NULL; + int err; - sanitized_config = g_strdelimit(g_strdup(config), "\r\n", ' '); + sanitized_config = g_strdup(config); + g_strdelimit(sanitized_config, "\r\n", ' '); err = teamdctl_port_config_update_raw(priv->tdc, slave_iface, sanitized_config); - g_free(sanitized_config); if (err != 0) { _LOGE(LOGD_TEAM, "failed to update config for port %s (err=%d)", @@ -1042,17 +1042,13 @@ dispose(GObject *object) static const NMDBusInterfaceInfoExtended interface_info_device_team = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_TEAM, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Carrier", "b", NM_DEVICE_CARRIER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Slaves", "ao", NM_DEVICE_SLAVES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Config", - "s", - NM_DEVICE_TEAM_CONFIG), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Carrier", "b", NM_DEVICE_CARRIER), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Slaves", "ao", NM_DEVICE_SLAVES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Config", + "s", + NM_DEVICE_TEAM_CONFIG), ), ), }; static void diff --git a/src/core/devices/team/nm-team-factory.c b/src/core/devices/team/nm-team-factory.c index 57b51bf8..e2040d19 100644 --- a/src/core/devices/team/nm-team-factory.c +++ b/src/core/devices/team/nm-team-factory.c @@ -10,8 +10,8 @@ #include "nm-manager.h" #include "devices/nm-device-factory.h" #include "nm-device-team.h" -#include "platform/nm-platform.h" -#include "nm-core-internal.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-core-intern/nm-core-internal.h" /*****************************************************************************/ diff --git a/src/core/devices/tests/test-acd.c b/src/core/devices/tests/test-acd.c index b0af59db..b4b65165 100644 --- a/src/core/devices/tests/test-acd.c +++ b/src/core/devices/tests/test-acd.c @@ -78,8 +78,8 @@ fixture_setup(test_fixture *fixture, gconstpointer user_data) fixture->ifindex1 = nmtstp_link_get_typed(NM_PLATFORM_GET, -1, IFACE_VETH1, NM_LINK_TYPE_VETH)->ifindex; - g_assert(nm_platform_link_set_up(NM_PLATFORM_GET, fixture->ifindex0, NULL)); - g_assert(nm_platform_link_set_up(NM_PLATFORM_GET, fixture->ifindex1, NULL)); + g_assert(nm_platform_link_change_flags(NM_PLATFORM_GET, fixture->ifindex0, IFF_UP, TRUE) >= 0); + g_assert(nm_platform_link_change_flags(NM_PLATFORM_GET, fixture->ifindex1, IFF_UP, TRUE) >= 0); fixture->hwaddr0 = nm_platform_link_get_address(NM_PLATFORM_GET, fixture->ifindex0, &fixture->hwaddr0_len); diff --git a/src/core/devices/tests/test-lldp.c b/src/core/devices/tests/test-lldp.c index ef0b1549..c64c7c11 100644 --- a/src/core/devices/tests/test-lldp.c +++ b/src/core/devices/tests/test-lldp.c @@ -13,7 +13,7 @@ #include #include "devices/nm-lldp-listener.h" -#include "systemd/nm-sd.h" +#include "libnm-systemd-core/nm-sd.h" #include "platform/tests/test-common.h" @@ -83,6 +83,7 @@ typedef struct { const uint8_t *frame; const char * as_variant; } TestRecvFrame; + #define TEST_RECV_FRAME_DEFINE(name, _as_variant, ...) \ static const guint8 _##name##_v[] = {__VA_ARGS__}; \ static const TestRecvFrame name = { \ @@ -91,12 +92,18 @@ typedef struct { .frame = _##name##_v, \ } +typedef struct { + int num_called; + GMainLoop *loop_to_quit; +} TestRecvCallbackInfo; + typedef struct { guint expected_num_called; gsize frames_len; const TestRecvFrame *frames[10]; - void (*check)(GMainLoop *loop, NMLldpListener *listener); + void (*check)(GMainLoop *loop, NMLldpListener *listener, TestRecvCallbackInfo *info); } TestRecvData; + #define TEST_RECV_DATA_DEFINE(name, _expected_num_called, _check, ...) \ static const TestRecvData name = { \ .expected_num_called = _expected_num_called, \ @@ -213,7 +220,7 @@ _test_recv_data0_check_do(GMainLoop *loop, NMLldpListener *listener, const TestR } static void -_test_recv_data0_check(GMainLoop *loop, NMLldpListener *listener) +_test_recv_data0_check(GMainLoop *loop, NMLldpListener *listener, TestRecvCallbackInfo *info) { _test_recv_data0_check_do(loop, listener, &_test_recv_data0_frame0); } @@ -528,7 +535,7 @@ TEST_RECV_FRAME_DEFINE( ); static void -_test_recv_data1_check(GMainLoop *loop, NMLldpListener *listener) +_test_recv_data1_check(GMainLoop *loop, NMLldpListener *listener, TestRecvCallbackInfo *info) { GVariant * neighbors, *attr, *child; gs_unref_variant GVariant *neighbor = NULL; @@ -756,21 +763,17 @@ TEST_RECV_FRAME_DEFINE( ); static void -_test_recv_data2_ttl1_check(GMainLoop *loop, NMLldpListener *listener) +_test_recv_data2_ttl1_check(GMainLoop *loop, NMLldpListener *listener, TestRecvCallbackInfo *info) { - gulong notify_id; GVariant *neighbors; _test_recv_data0_check_do(loop, listener, &_test_recv_data2_frame0_ttl1); /* wait for signal. */ - notify_id = g_signal_connect(listener, - "notify::" NM_LLDP_LISTENER_NEIGHBORS, - nmtst_main_loop_quit_on_notify, - loop); + info->loop_to_quit = loop; if (!nmtst_main_loop_run(loop, 5000)) g_assert_not_reached(); - nm_clear_g_signal_handler(listener, ¬ify_id); + info->loop_to_quit = NULL; neighbors = nm_lldp_listener_get_neighbors(listener); nmtst_assert_variant_is_of_type(neighbors, G_VARIANT_TYPE("aa{sv}")); @@ -852,46 +855,37 @@ again: memcpy(fixture->mac, link->l_address.data, ETH_ALEN); } -typedef struct { - int num_called; -} TestRecvCallbackInfo; - static void -lldp_neighbors_changed(NMLldpListener *lldp_listener, GParamSpec *pspec, gpointer user_data) +lldp_neighbors_changed(NMLldpListener *lldp_listener, gpointer user_data) { TestRecvCallbackInfo *info = user_data; info->num_called++; + if (info->loop_to_quit) + g_main_loop_quit(info->loop_to_quit); } static void test_recv(TestRecvFixture *fixture, gconstpointer user_data) { - const TestRecvData *data = user_data; - gs_unref_object NMLldpListener *listener = NULL; - GMainLoop * loop; - TestRecvCallbackInfo info = {}; - gsize i_frames; - gulong notify_id; - GError * error = NULL; - guint sd_id; + const TestRecvData * data = user_data; + NMLldpListener * listener; + GMainLoop * loop; + TestRecvCallbackInfo info = {}; + gsize i_frames; + GError * error = NULL; + guint sd_id; if (fixture->ifindex == 0) { g_test_skip("Tun device not available"); return; } - listener = nm_lldp_listener_new(); - g_assert(listener != NULL); - g_assert(nm_lldp_listener_start(listener, fixture->ifindex, &error)); - g_assert_no_error(error); + listener = nm_lldp_listener_new(fixture->ifindex, lldp_neighbors_changed, &info, &error); + nmtst_assert_success(listener, error); - notify_id = g_signal_connect(listener, - "notify::" NM_LLDP_LISTENER_NEIGHBORS, - (GCallback) lldp_neighbors_changed, - &info); - loop = g_main_loop_new(NULL, FALSE); - sd_id = nm_sd_event_attach_default(); + loop = g_main_loop_new(NULL, FALSE); + sd_id = nm_sd_event_attach_default(); for (i_frames = 0; i_frames < data->frames_len; i_frames++) { const TestRecvFrame *f = data->frames[i_frames]; @@ -904,9 +898,9 @@ test_recv(TestRecvFixture *fixture, gconstpointer user_data) g_assert_cmpint(info.num_called, ==, data->expected_num_called); - nm_clear_g_signal_handler(listener, ¬ify_id); + data->check(loop, listener, &info); - data->check(loop, listener); + nm_clear_pointer(&listener, nm_lldp_listener_destroy); nm_clear_g_source(&sd_id); nm_clear_pointer(&loop, g_main_loop_unref); diff --git a/src/core/devices/wifi/meson.build b/src/core/devices/wifi/meson.build index 743937db..85553c53 100644 --- a/src/core/devices/wifi/meson.build +++ b/src/core/devices/wifi/meson.build @@ -22,7 +22,6 @@ libnm_device_plugin_wifi_static = static_library( dependencies: [ core_plugin_dep, ], - c_args: daemon_c_flags, ) libnm_device_plugin_wifi_static_dep = declare_dependency( @@ -38,7 +37,6 @@ libnm_device_plugin_wifi = shared_module( core_plugin_dep, libnm_device_plugin_wifi_static_dep ], - c_args: daemon_c_flags, link_args: ldflags_linker_script_devices, link_depends: linker_script_devices, install: true, diff --git a/src/core/devices/wifi/nm-device-iwd.c b/src/core/devices/wifi/nm-device-iwd.c index 95ade44b..56338743 100644 --- a/src/core/devices/wifi/nm-device-iwd.c +++ b/src/core/devices/wifi/nm-device-iwd.c @@ -13,16 +13,16 @@ #include "devices/nm-device.h" #include "nm-act-request.h" #include "nm-config.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-dbus-manager.h" -#include "nm-glib-aux/nm-ref-string.h" +#include "libnm-glib-aux/nm-ref-string.h" #include "nm-iwd-manager.h" -#include "nm-libnm-core-intern/nm-common-macros.h" +#include "libnm-core-aux-intern/nm-common-macros.h" #include "nm-setting-8021x.h" #include "nm-setting-connection.h" #include "nm-setting-wireless-security.h" #include "nm-setting-wireless.h" -#include "nm-std-aux/nm-dbus-compat.h" +#include "libnm-std-aux/nm-dbus-compat.h" #include "nm-utils.h" #include "nm-wifi-common.h" #include "nm-wifi-utils.h" @@ -55,7 +55,7 @@ typedef struct { CList aps_lst_head; NMWifiAP * current_ap; GCancellable * cancellable; - NMDeviceWifiCapabilities capabilities; + _NMDeviceWifiCapabilities capabilities; NMActRequestGetSecretsCallId *wifi_secrets_id; guint periodic_scan_id; guint periodic_update_id; @@ -265,7 +265,7 @@ ap_from_network(NMDeviceIwd *self, .bss_path = bss_path, .last_seen_msec = last_seen_msec, .bssid_valid = TRUE, - .mode = NM_802_11_MODE_INFRA, + .mode = _NM_802_11_MODE_INFRA, .rsn_flags = ap_security_flags_from_network_type(type), .ssid = ssid, .signal_percent = nm_wifi_utils_level_to_quality(signal / 100), @@ -588,10 +588,16 @@ deactivate(NMDevice *device) return; } - cleanup_association_attempt(self, TRUE); + cleanup_association_attempt(self, FALSE); priv->act_mode_switch = FALSE; - if (!priv->dbus_station_proxy) + /* Don't trigger any actions on the IWD side until the device is managed */ + if (priv->iwd_autoconnect && nm_device_get_state(device) < NM_DEVICE_STATE_DISCONNECTED) + return; + + if (priv->dbus_station_proxy) + send_disconnect(self); + else reset_mode(self, NULL, NULL, NULL); } @@ -647,6 +653,11 @@ deactivate_async(NMDevice * device, cleanup_association_attempt(self, FALSE); priv->act_mode_switch = FALSE; + if (priv->iwd_autoconnect && nm_device_get_state(device) < NM_DEVICE_STATE_DISCONNECTED) { + nm_utils_invoke_on_idle(cancellable, disconnect_cb_on_idle, user_data); + return; + } + if (priv->dbus_station_proxy) { g_dbus_proxy_call(priv->dbus_station_proxy, "Disconnect", @@ -801,7 +812,7 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError * NMSettingWirelessSecurity *s_wireless_sec = nm_connection_get_setting_wireless_security(connection); - if (!(priv->capabilities & NM_WIFI_DEVICE_CAP_AP)) { + if (!(priv->capabilities & _NM_WIFI_DEVICE_CAP_AP)) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, "device does not support Access Point mode"); @@ -819,7 +830,7 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError * NMSettingWirelessSecurity *s_wireless_sec = nm_connection_get_setting_wireless_security(connection); - if (!(priv->capabilities & NM_WIFI_DEVICE_CAP_ADHOC)) { + if (!(priv->capabilities & _NM_WIFI_DEVICE_CAP_ADHOC)) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, "device does not support Ad-Hoc mode"); @@ -1034,16 +1045,15 @@ complete_connection(NMDevice * device, } ssid_utf8 = iwd_ssid_to_str(ssid); - nm_utils_complete_generic( - nm_device_get_platform(device), - connection, - NM_SETTING_WIRELESS_SETTING_NAME, - existing_connections, - ssid_utf8, - ssid_utf8, - NULL, - nm_setting_wireless_get_mac_address(s_wifi) ? NULL : nm_device_get_iface(device), - TRUE); + nm_utils_complete_generic(nm_device_get_platform(device), + connection, + NM_SETTING_WIRELESS_SETTING_NAME, + existing_connections, + ssid_utf8, + ssid_utf8, + NULL, + NULL, + TRUE); if (hidden) g_object_set(s_wifi, NM_SETTING_WIRELESS_HIDDEN, TRUE, NULL); @@ -1306,6 +1316,7 @@ static gboolean try_reply_agent_request(NMDeviceIwd * self, NMConnection * connection, GDBusMethodInvocation *invocation, + gboolean allow_existing, const char ** setting_name, const char ** setting_key, gboolean * replied) @@ -1320,56 +1331,64 @@ try_reply_agent_request(NMDeviceIwd * self, *replied = FALSE; if (nm_streq(method_name, "RequestPassphrase")) { - const char *psk; - if (!s_wireless_sec) return FALSE; - psk = nm_setting_wireless_security_get_psk(s_wireless_sec); - if (psk) { - _LOGD(LOGD_DEVICE | LOGD_WIFI, "Returning the PSK to the IWD Agent"); + if (allow_existing) { + const char *psk = nm_setting_wireless_security_get_psk(s_wireless_sec); - g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", psk)); - *replied = TRUE; - return TRUE; + if (psk) { + _LOGD(LOGD_DEVICE | LOGD_WIFI, "Returning the PSK to the IWD Agent"); + + g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", psk)); + *replied = TRUE; + return TRUE; + } } *setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME; *setting_key = NM_SETTING_WIRELESS_SECURITY_PSK; return TRUE; } else if (nm_streq(method_name, "RequestPrivateKeyPassphrase")) { - const char *password; - if (!s_8021x) return FALSE; - password = nm_setting_802_1x_get_private_key_password(s_8021x); - if (password) { - _LOGD(LOGD_DEVICE | LOGD_WIFI, "Returning the private key password to the IWD Agent"); + if (allow_existing) { + const char *password = nm_setting_802_1x_get_private_key_password(s_8021x); - g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", password)); - *replied = TRUE; - return TRUE; + if (password) { + _LOGD(LOGD_DEVICE | LOGD_WIFI, + "Returning the private key password to the IWD Agent"); + + g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", password)); + *replied = TRUE; + return TRUE; + } } *setting_name = NM_SETTING_802_1X_SETTING_NAME; *setting_key = NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD; return TRUE; } else if (nm_streq(method_name, "RequestUserNameAndPassword")) { - const char *identity, *password; + const char *identity; if (!s_8021x) return FALSE; identity = nm_setting_802_1x_get_identity(s_8021x); - password = nm_setting_802_1x_get_password(s_8021x); - if (identity && password) { - _LOGD(LOGD_DEVICE | LOGD_WIFI, "Returning the username and password to the IWD Agent"); - g_dbus_method_invocation_return_value(invocation, - g_variant_new("(ss)", identity, password)); - *replied = TRUE; - return TRUE; + if (allow_existing) { + const char *password = nm_setting_802_1x_get_password(s_8021x); + + if (identity && password) { + _LOGD(LOGD_DEVICE | LOGD_WIFI, + "Returning the username and password to the IWD Agent"); + + g_dbus_method_invocation_return_value(invocation, + g_variant_new("(ss)", identity, password)); + *replied = TRUE; + return TRUE; + } } *setting_name = NM_SETTING_802_1X_SETTING_NAME; @@ -1379,18 +1398,19 @@ try_reply_agent_request(NMDeviceIwd * self, *setting_key = NM_SETTING_802_1X_PASSWORD; return TRUE; } else if (nm_streq(method_name, "RequestUserPassword")) { - const char *password; - if (!s_8021x) return FALSE; - password = nm_setting_802_1x_get_password(s_8021x); - if (password) { - _LOGD(LOGD_DEVICE | LOGD_WIFI, "Returning the user password to the IWD Agent"); + if (allow_existing) { + const char *password = nm_setting_802_1x_get_password(s_8021x); - g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", password)); - *replied = TRUE; - return TRUE; + if (password) { + _LOGD(LOGD_DEVICE | LOGD_WIFI, "Returning the user password to the IWD Agent"); + + g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", password)); + *replied = TRUE; + return TRUE; + } } *setting_name = NM_SETTING_802_1X_SETTING_NAME; @@ -1441,6 +1461,8 @@ wifi_secrets_cb(NMActRequest * req, gboolean replied; NMSecretAgentGetSecretsFlags get_secret_flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; + NMIwdNetworkSecurity security; + NMConnection * connection; nm_utils_user_data_unpack(user_data, &self, &invocation); @@ -1473,9 +1495,18 @@ wifi_secrets_cb(NMActRequest * req, goto secrets_error; } + connection = nm_device_get_applied_connection(device); + + if (nm_wifi_connection_get_iwd_ssid_and_security(connection, NULL, &security) + && security == NM_IWD_NETWORK_SECURITY_PSK) { + if (nm_settings_connection_get_timestamp(nm_device_get_settings_connection(device), NULL)) + get_secret_flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW; + } + if (!try_reply_agent_request(self, - nm_act_request_get_applied_connection(req), + connection, invocation, + TRUE, &setting_name, &setting_key, &replied)) @@ -1501,9 +1532,6 @@ wifi_secrets_cb(NMActRequest * req, return; } - if (nm_settings_connection_get_timestamp(nm_act_request_get_settings_connection(req), NULL)) - get_secret_flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW; - /* Request further secrets if we still need something */ wifi_secrets_get_one(self, setting_name, get_secret_flags, setting_key, invocation); return; @@ -1595,8 +1623,6 @@ network_connect_cb(GObject *source, GAsyncResult *res, gpointer user_data) dbus_error = g_dbus_error_get_remote_error(error); if (nm_streq0(dbus_error, "net.connman.iwd.Failed")) { - nm_connection_clear_secrets(connection); - /* If secrets were wrong, we'd be getting a net.connman.iwd.Failed */ reason = NM_DEVICE_STATE_REASON_NO_SECRETS; } else if (nm_streq0(dbus_error, "net.connman.iwd.Aborted") && priv->secrets_failed) { @@ -2610,9 +2636,9 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) switch (prop_id) { case PROP_MODE: if (!priv->current_ap) - g_value_set_uint(value, NM_802_11_MODE_UNKNOWN); + g_value_set_uint(value, _NM_802_11_MODE_UNKNOWN); else if (nm_wifi_ap_is_hotspot(priv->current_ap)) - g_value_set_uint(value, NM_802_11_MODE_AP); + g_value_set_uint(value, _NM_802_11_MODE_AP); else g_value_set_uint(value, nm_wifi_ap_get_mode(priv->current_ap)); @@ -3034,7 +3060,7 @@ nm_device_iwd_set_dbus_object(NMDeviceIwd *self, GDBusObject *object) GVariantIter * iter; const char * mode; gboolean powered; - NMDeviceWifiCapabilities capabilities; + _NMDeviceWifiCapabilities capabilities; if (!nm_g_object_ref_set(&priv->dbus_obj, object)) return; @@ -3096,14 +3122,14 @@ nm_device_iwd_set_dbus_object(NMDeviceIwd *self, GDBusObject *object) goto error; } - capabilities = NM_WIFI_DEVICE_CAP_CIPHER_CCMP | NM_WIFI_DEVICE_CAP_RSN; + capabilities = _NM_WIFI_DEVICE_CAP_CIPHER_CCMP | _NM_WIFI_DEVICE_CAP_RSN; g_variant_get(value, "as", &iter); while (g_variant_iter_next(iter, "&s", &mode)) { if (nm_streq(mode, "ap")) - capabilities |= NM_WIFI_DEVICE_CAP_AP; + capabilities |= _NM_WIFI_DEVICE_CAP_AP; else if (nm_streq(mode, "ad-hoc")) - capabilities |= NM_WIFI_DEVICE_CAP_ADHOC; + capabilities |= _NM_WIFI_DEVICE_CAP_ADHOC; } g_variant_iter_free(iter); @@ -3145,8 +3171,11 @@ nm_device_iwd_agent_query(NMDeviceIwd *self, GDBusMethodInvocation *invocation) const char * setting_key; gboolean replied; NMWifiAP * ap; + gboolean allow_existing = FALSE; NMSecretAgentGetSecretsFlags get_secret_flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; + NMIwdNetworkSecurity security; + NMConnection * connection; nm_auto_ref_string NMRefString *network_path = NULL; if (!invocation) { @@ -3250,9 +3279,37 @@ nm_device_iwd_agent_query(NMDeviceIwd *self, GDBusMethodInvocation *invocation) /* Otherwise handle as usual */ } + /* Normally for PSK networks require new secret every time IWD asks for + * it. IWD only queries us if it has not saved the PSK (e.g. by policy) + * or a previous attempt has failed with current secrets so it wants a + * fresh value. It doesn't know about agent-owned secrets so whenever + * possible and the PSK is saved and not asked from NM. However if this + * is a new connection it may include all of the needed settings already + * so allow using these, too. Connection timestamp is set after + * activation or after first activation failure (to 0). + * + * For 802.1x, since IWD assumes the network is pre-provisioned by an + * admin and tested, there's no reason for IWD to save secrets in + * the network config file and there's no reason to ask for a new value + * of a saved (i.e. system-owned) secret because it can't be wrong. + * Since NM has a richer set of secret storage options we never specify + * NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW and let + * nm_settings_connection_get_secrets decide. + */ + connection = nm_device_get_applied_connection(device); + + if (nm_wifi_connection_get_iwd_ssid_and_security(connection, NULL, &security) + && security == NM_IWD_NETWORK_SECURITY_PSK) { + if (nm_settings_connection_get_timestamp(nm_device_get_settings_connection(device), NULL)) + get_secret_flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW; + else + allow_existing = TRUE; + } + if (!try_reply_agent_request(self, - nm_device_get_applied_connection(device), + connection, invocation, + allow_existing, &setting_name, &setting_key, &replied)) { @@ -3263,17 +3320,6 @@ nm_device_iwd_agent_query(NMDeviceIwd *self, GDBusMethodInvocation *invocation) if (replied) return TRUE; - /* Normally require new secrets every time IWD asks for them. - * IWD only queries us if it has not saved the secrets (e.g. by policy) - * or a previous attempt has failed with current secrets so it wants - * a fresh set. However if this is a new connection it may include - * all of the needed settings already so allow using these, too. - * Connection timestamp is set after activation or after first - * activation failure (to 0). - */ - if (nm_settings_connection_get_timestamp(nm_device_get_settings_connection(device), NULL)) - get_secret_flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW; - nm_device_state_changed(device, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NO_SECRETS); wifi_secrets_get_one(self, setting_name, get_secret_flags, setting_key, invocation); @@ -3452,9 +3498,9 @@ nm_device_iwd_class_init(NMDeviceIwdClass *klass) obj_properties[PROP_MODE] = g_param_spec_uint(NM_DEVICE_IWD_MODE, "", "", - NM_802_11_MODE_UNKNOWN, - NM_802_11_MODE_AP, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_UNKNOWN, + _NM_802_11_MODE_AP, + _NM_802_11_MODE_INFRA, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_BITRATE] = g_param_spec_uint(NM_DEVICE_IWD_BITRATE, @@ -3485,7 +3531,7 @@ nm_device_iwd_class_init(NMDeviceIwdClass *klass) "", 0, G_MAXUINT32, - NM_WIFI_DEVICE_CAP_NONE, + _NM_WIFI_DEVICE_CAP_NONE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_SCANNING] = g_param_spec_boolean(NM_DEVICE_IWD_SCANNING, diff --git a/src/core/devices/wifi/nm-device-olpc-mesh.c b/src/core/devices/wifi/nm-device-olpc-mesh.c index af83c4a3..040350d5 100644 --- a/src/core/devices/wifi/nm-device-olpc-mesh.c +++ b/src/core/devices/wifi/nm-device-olpc-mesh.c @@ -28,7 +28,7 @@ #include "nm-setting-connection.h" #include "nm-setting-olpc-mesh.h" #include "nm-manager.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #define _NMLOG_DEVICE_TYPE NMDeviceOlpcMesh #include "devices/nm-device-logging.h" @@ -122,6 +122,17 @@ complete_connection(NMDevice * device, /*****************************************************************************/ +static const char * +get_dhcp_anycast_address(NMDevice *device) +{ + NMSettingOlpcMesh *s_mesh; + + s_mesh = nm_device_get_applied_setting(device, NM_TYPE_SETTING_OLPC_MESH); + return s_mesh ? nm_setting_olpc_mesh_get_dhcp_anycast_address(s_mesh) : NULL; +} + +/*****************************************************************************/ + static NMActStageReturn act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) { @@ -178,7 +189,6 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) NMDeviceOlpcMesh * self = NM_DEVICE_OLPC_MESH(device); NMSettingOlpcMesh *s_mesh; GBytes * ssid; - const char * anycast_addr; gboolean success; s_mesh = nm_device_get_applied_setting(device, NM_TYPE_SETTING_OLPC_MESH); @@ -197,9 +207,6 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) return NM_ACT_STAGE_RETURN_FAILURE; } - anycast_addr = nm_setting_olpc_mesh_get_dhcp_anycast_address(s_mesh); - nm_device_set_dhcp_anycast_address(device, anycast_addr); - if (!_mesh_set_channel(self, nm_setting_olpc_mesh_get_channel(s_mesh))) { _LOGW(LOGD_WIFI, "Unable to set the mesh channel"); return NM_ACT_STAGE_RETURN_FAILURE; @@ -492,19 +499,15 @@ dispose(GObject *object) static const NMDBusInterfaceInfoExtended interface_info_device_olpc_mesh = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_OLPC_MESH, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Companion", - "o", - NM_DEVICE_OLPC_MESH_COMPANION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L( + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Companion", + "o", + NM_DEVICE_OLPC_MESH_COMPANION), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE( "ActiveChannel", "u", NM_DEVICE_OLPC_MESH_ACTIVE_CHANNEL), ), ), - .legacy_property_changed = TRUE, }; static void @@ -531,6 +534,7 @@ nm_device_olpc_mesh_class_init(NMDeviceOlpcMeshClass *klass) device_class->act_stage2_config = act_stage2_config; device_class->state_changed = state_changed; device_class->get_dhcp_timeout_for_device = get_dhcp_timeout_for_device; + device_class->get_dhcp_anycast_address = get_dhcp_anycast_address; obj_properties[PROP_COMPANION] = g_param_spec_string(NM_DEVICE_OLPC_MESH_COMPANION, "", diff --git a/src/core/devices/wifi/nm-device-wifi-p2p.c b/src/core/devices/wifi/nm-device-wifi-p2p.c index fb987600..a8ea2ed7 100644 --- a/src/core/devices/wifi/nm-device-wifi-p2p.c +++ b/src/core/devices/wifi/nm-device-wifi-p2p.c @@ -15,16 +15,16 @@ #include "NetworkManagerUtils.h" #include "devices/nm-device-private.h" #include "nm-act-request.h" -#include "nm-core-internal.h" -#include "nm-glib-aux/nm-ref-string.h" +#include "libnm-core-intern/nm-core-internal.h" +#include "libnm-glib-aux/nm-ref-string.h" #include "nm-ip4-config.h" #include "nm-manager.h" #include "nm-manager.h" #include "nm-setting-wifi-p2p.h" #include "nm-utils.h" #include "nm-wifi-p2p-peer.h" -#include "platform/nm-platform.h" -#include "platform/nmp-object.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-platform/nmp-object.h" #include "settings/nm-settings.h" #define _NMLOG_DEVICE_TYPE NMDeviceWifiP2P @@ -1149,7 +1149,6 @@ static const NMDBusInterfaceInfoExtended interface_info_device_wifi_p2p = { NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Peers", "ao", NM_DEVICE_WIFI_P2P_PEERS), ), ), - .legacy_property_changed = FALSE, }; /*****************************************************************************/ diff --git a/src/core/devices/wifi/nm-device-wifi.c b/src/core/devices/wifi/nm-device-wifi.c index 042d4887..fca2fde5 100644 --- a/src/core/devices/wifi/nm-device-wifi.c +++ b/src/core/devices/wifi/nm-device-wifi.c @@ -12,11 +12,11 @@ #include #include -#include "nm-glib-aux/nm-ref-string.h" -#include "nm-glib-aux/nm-c-list.h" +#include "libnm-glib-aux/nm-ref-string.h" +#include "libnm-glib-aux/nm-c-list.h" #include "nm-device-wifi-p2p.h" #include "nm-wifi-ap.h" -#include "nm-libnm-core-intern/nm-common-macros.h" +#include "libnm-core-aux-intern/nm-common-macros.h" #include "devices/nm-device.h" #include "devices/nm-device-private.h" #include "nm-dbus-manager.h" @@ -33,13 +33,13 @@ #include "nm-setting-ip4-config.h" #include "nm-ip4-config.h" #include "nm-setting-ip6-config.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-auth-utils.h" #include "settings/nm-settings-connection.h" #include "settings/nm-settings.h" #include "nm-wifi-utils.h" #include "nm-wifi-common.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-config.h" #define _NMLOG_DEVICE_TYPE NMDeviceWifi @@ -114,11 +114,11 @@ typedef struct { guint wps_timeout_id; guint sup_timeout_id; /* supplicant association timeout */ - NMDeviceWifiCapabilities capabilities; - NMSettingWirelessWakeOnWLan wowlan_restore; + _NMDeviceWifiCapabilities capabilities; + _NMSettingWirelessWakeOnWLan wowlan_restore; NMDeviceWifiP2P *p2p_device; - NM80211Mode mode; + _NM80211Mode mode; guint32 failed_iface_count; gint32 hw_addr_scan_expire; @@ -487,7 +487,7 @@ _scan_notify_allowed(NMDeviceWifi *self, NMTernary do_kickoff) if (!c_list_is_empty(&priv->scanning_prohibited_lst_head)) { /* something prohibits scanning. */ - } else if (NM_IN_SET(priv->mode, NM_802_11_MODE_ADHOC, NM_802_11_MODE_AP)) { + } else if (NM_IN_SET(priv->mode, _NM_802_11_MODE_ADHOC, _NM_802_11_MODE_AP)) { /* Don't scan when a an AP or Ad-Hoc connection is active as it will * disrupt connected clients or peers. */ } else if (NM_IN_SET(state, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_FAILED)) { @@ -678,7 +678,7 @@ update_seen_bssids_cache(NMDeviceWifi *self, NMWifiAP *ap) return; /* Don't cache the BSSID for Ad-Hoc APs */ - if (nm_wifi_ap_get_mode(ap) != NM_802_11_MODE_INFRA) + if (nm_wifi_ap_get_mode(ap) != _NM_802_11_MODE_INFRA) return; if (nm_device_get_state(NM_DEVICE(self)) == NM_DEVICE_STATE_ACTIVATED @@ -712,10 +712,11 @@ set_current_ap(NMDeviceWifi *self, NMWifiAP *new_ap, gboolean recheck_available_ priv->current_ap = NULL; if (old_ap) { - NM80211Mode mode = nm_wifi_ap_get_mode(old_ap); + _NM80211Mode mode = nm_wifi_ap_get_mode(old_ap); /* Remove any AP from the internal list if it was created by NM or isn't known to the supplicant */ - if (NM_IN_SET(mode, NM_802_11_MODE_ADHOC, NM_802_11_MODE_AP) || nm_wifi_ap_get_fake(old_ap)) + if (NM_IN_SET(mode, _NM_802_11_MODE_ADHOC, _NM_802_11_MODE_AP) + || nm_wifi_ap_get_fake(old_ap)) ap_add_remove(self, FALSE, old_ap, recheck_available_connections); g_object_unref(old_ap); } @@ -750,7 +751,7 @@ periodic_update(NMDeviceWifi *self) return; } - if (priv->mode == NM_802_11_MODE_AP) { + if (priv->mode == _NM_802_11_MODE_AP) { /* In AP mode we currently have nothing to do. */ return; } @@ -845,14 +846,14 @@ remove_all_aps(NMDeviceWifi *self) static gboolean wake_on_wlan_restore(NMDeviceWifi *self) { - NMDeviceWifiPrivate * priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - NMSettingWirelessWakeOnWLan w; + NMDeviceWifiPrivate * priv = NM_DEVICE_WIFI_GET_PRIVATE(self); + _NMSettingWirelessWakeOnWLan w; w = priv->wowlan_restore; - if (w == NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE) + if (w == _NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE) return TRUE; - priv->wowlan_restore = NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE; + priv->wowlan_restore = _NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE; return nm_platform_wifi_set_wake_on_wlan(NM_PLATFORM_GET, nm_device_get_ifindex(NM_DEVICE(self)), w); @@ -937,14 +938,14 @@ deactivate(NMDevice *device) * (usually older ones) don't scan well in adhoc mode. */ if (nm_platform_wifi_get_mode(nm_device_get_platform(device), ifindex) - != NM_802_11_MODE_INFRA) { + != _NM_802_11_MODE_INFRA) { nm_device_take_down(NM_DEVICE(self), TRUE); - nm_platform_wifi_set_mode(nm_device_get_platform(device), ifindex, NM_802_11_MODE_INFRA); + nm_platform_wifi_set_mode(nm_device_get_platform(device), ifindex, _NM_802_11_MODE_INFRA); nm_device_bring_up(NM_DEVICE(self), TRUE, NULL); } - if (priv->mode != NM_802_11_MODE_INFRA) { - priv->mode = NM_802_11_MODE_INFRA; + if (priv->mode != _NM_802_11_MODE_INFRA) { + priv->mode = _NM_802_11_MODE_INFRA; _notify(self, PROP_MODE); } @@ -1010,14 +1011,14 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError * /* Early exit if supplicant or device doesn't support requested mode */ mode = nm_setting_wireless_get_mode(s_wireless); if (g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_ADHOC) == 0) { - if (!(priv->capabilities & NM_WIFI_DEVICE_CAP_ADHOC)) { + if (!(priv->capabilities & _NM_WIFI_DEVICE_CAP_ADHOC)) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, "the device does not support Ad-Hoc networks"); return FALSE; } } else if (g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_AP) == 0) { - if (!(priv->capabilities & NM_WIFI_DEVICE_CAP_AP)) { + if (!(priv->capabilities & _NM_WIFI_DEVICE_CAP_AP)) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, "the device does not support Access Point mode"); @@ -1034,7 +1035,7 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError * } } } else if (g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_MESH) == 0) { - if (!(priv->capabilities & NM_WIFI_DEVICE_CAP_MESH)) { + if (!(priv->capabilities & _NM_WIFI_DEVICE_CAP_MESH)) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, "the device does not support Mesh mode"); @@ -1381,8 +1382,8 @@ _hw_addr_set_scanning(NMDeviceWifi *self, gboolean do_reset) now = nm_utils_get_monotonic_timestamp_sec(); if (now >= priv->hw_addr_scan_expire) { - gs_free char *generate_mac_address_mask = NULL; - gs_free char *hw_addr_scan = NULL; + gs_free char *hw_addr_scan = NULL; + const char * generate_mac_address_mask; /* the random MAC address for scanning expires after a while. * @@ -1433,7 +1434,7 @@ ssids_options_to_ptrarray(GVariant *value, GError **error) v = g_variant_get_child_value(value, i); bytes = g_variant_get_fixed_array(v, &len, sizeof(guint8)); - if (len > 32) { + if (len > NM_IW_ESSID_MAX_SIZE) { g_set_error(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_ARGUMENT, @@ -1822,7 +1823,7 @@ _scan_kickoff(NMDeviceWifi *self) strv = g_new(char *, ssids->len + 1u); for (i = 0; i < ssids->len; i++) - strv[i] = _nm_utils_ssid_to_string(ssids->pdata[i]); + strv[i] = _nm_utils_ssid_to_string_gbytes(ssids->pdata[i]); strv[i] = NULL; nm_assert(ssids->len > 0); @@ -1884,13 +1885,13 @@ ap_list_dump(gpointer user_data) _LOGD(LOGD_WIFI_SCAN, "APs: [now:%u.%03u, last:%s]", - (guint)(now_msec / NM_UTILS_MSEC_PER_SEC), - (guint)(now_msec % NM_UTILS_MSEC_PER_SEC), + (guint) (now_msec / NM_UTILS_MSEC_PER_SEC), + (guint) (now_msec % NM_UTILS_MSEC_PER_SEC), priv->scan_last_complete_msec > 0 ? nm_sprintf_buf(str_buf, "%u.%03u", - (guint)(priv->scan_last_complete_msec / NM_UTILS_MSEC_PER_SEC), - (guint)(priv->scan_last_complete_msec % NM_UTILS_MSEC_PER_SEC)) + (guint) (priv->scan_last_complete_msec / NM_UTILS_MSEC_PER_SEC), + (guint) (priv->scan_last_complete_msec % NM_UTILS_MSEC_PER_SEC)) : "-1"); c_list_for_each_entry (ap, &priv->aps_lst_head, aps_lst) _ap_dump(self, LOGL_DEBUG, ap, "dump", now_msec); @@ -1986,19 +1987,19 @@ supplicant_iface_bss_changed_cb(NMSupplicantInterface *iface, /* Let the manager try to fill in the SSID from seen-bssids lists */ ssid = nm_wifi_ap_get_ssid(ap); - if (!ssid || _nm_utils_is_empty_ssid(ssid)) { + if (!ssid || _nm_utils_is_empty_ssid_gbytes(ssid)) { /* Try to fill the SSID from the AP database */ try_fill_ssid_for_hidden_ap(self, ap); ssid = nm_wifi_ap_get_ssid(ap); - if (ssid && !_nm_utils_is_empty_ssid(ssid)) { + if (ssid && !_nm_utils_is_empty_ssid_gbytes(ssid)) { gs_free char *s = NULL; /* Yay, matched it, no longer treat as hidden */ _LOGD(LOGD_WIFI, "matched hidden AP %s => %s", nm_wifi_ap_get_address(ap), - (s = _nm_utils_ssid_to_string(ssid))); + (s = _nm_utils_ssid_to_string_gbytes(ssid))); } else { /* Didn't have an entry for this AP in the database */ _LOGD(LOGD_WIFI, "failed to match hidden AP %s", nm_wifi_ap_get_address(ap)); @@ -2481,9 +2482,9 @@ supplicant_iface_state(NMDeviceWifi * self, _LOGI(LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) Stage 2 of 5 (Device Configure) successful. %s %s", - priv->mode == NM_802_11_MODE_AP ? "Started Wi-Fi Hotspot" - : "Connected to wireless network", - (ssid_str = _nm_utils_ssid_to_string(ssid))); + priv->mode == _NM_802_11_MODE_AP ? "Started Wi-Fi Hotspot" + : "Connected to wireless network", + (ssid_str = _nm_utils_ssid_to_string_gbytes(ssid))); nm_device_activate_schedule_stage3_ip_config_start(device); } else if (devstate == NM_DEVICE_STATE_ACTIVATED) periodic_update(self); @@ -2565,6 +2566,7 @@ supplicant_iface_notify_current_bss(NMSupplicantInterface *iface, NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); NMRefString * current_bss; NMWifiAP * new_ap = NULL; + NMActRequest * req; current_bss = nm_supplicant_interface_get_current_bss(iface); if (current_bss) @@ -2598,9 +2600,9 @@ supplicant_iface_notify_current_bss(NMSupplicantInterface *iface, _LOGD(LOGD_WIFI, "roamed from BSSID %s (%s) to %s (%s)", old_bssid ?: "(none)", - (old_ssid_s = _nm_utils_ssid_to_string(old_ssid)), + (old_ssid_s = _nm_utils_ssid_to_string_gbytes(old_ssid)), new_bssid ?: "(none)", - (new_ssid_s = _nm_utils_ssid_to_string(new_ssid))); + (new_ssid_s = _nm_utils_ssid_to_string_gbytes(new_ssid))); if (new_bssid) { /* The new AP could be in a different layer 3 network @@ -2612,6 +2614,13 @@ supplicant_iface_notify_current_bss(NMSupplicantInterface *iface, } set_current_ap(self, new_ap, TRUE); + + req = nm_device_get_act_request(NM_DEVICE(self)); + if (req) { + nm_active_connection_set_specific_object( + NM_ACTIVE_CONNECTION(req), + new_ap ? nm_dbus_object_get_path(NM_DBUS_OBJECT(new_ap)) : NULL); + } } } @@ -2782,21 +2791,21 @@ supplicant_connection_timeout_cb(gpointer user_data) connection = nm_act_request_get_applied_connection(req); g_assert(connection); - if (NM_IN_SET(priv->mode, NM_802_11_MODE_ADHOC, NM_802_11_MODE_MESH, NM_802_11_MODE_AP)) { + if (NM_IN_SET(priv->mode, _NM_802_11_MODE_ADHOC, _NM_802_11_MODE_MESH, _NM_802_11_MODE_AP)) { /* In Ad-Hoc and AP modes there's nothing to check the encryption key * (if any), so supplicant timeouts here are almost certainly the wifi * driver being really stupid. */ _LOGW(LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) %s network creation took too long, failing activation", - priv->mode == NM_802_11_MODE_ADHOC ? "Ad-Hoc" : "Hotspot"); + priv->mode == _NM_802_11_MODE_ADHOC ? "Ad-Hoc" : "Hotspot"); nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT); return FALSE; } - g_assert(priv->mode == NM_802_11_MODE_INFRA); + g_assert(priv->mode == _NM_802_11_MODE_INFRA); if (priv->ssid_found && nm_connection_get_setting_wireless_security(connection)) { guint64 timestamp = 0; @@ -2948,9 +2957,10 @@ error: static gboolean wake_on_wlan_enable(NMDeviceWifi *self) { - NMDeviceWifiPrivate * priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - NMSettingWirelessWakeOnWLan wowl; - NMSettingWireless * s_wireless; + NMDeviceWifiPrivate * priv = NM_DEVICE_WIFI_GET_PRIVATE(self); + NMSettingWirelessWakeOnWLan wowl; + _NMSettingWirelessWakeOnWLan wowl2; + NMSettingWireless * s_wireless; s_wireless = nm_device_get_applied_setting(NM_DEVICE(self), NM_TYPE_SETTING_WIRELESS); if (s_wireless) { @@ -2982,9 +2992,11 @@ wake_on_wlan_enable(NMDeviceWifi *self) goto found; wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE; + found: - if (wowl == NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE) { - priv->wowlan_restore = wowl; + wowl2 = _NM_SETTING_WIRELESS_WAKE_ON_WLAN_CAST(wowl); + if (wowl2 == _NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE) { + priv->wowlan_restore = wowl2; return TRUE; } @@ -2993,7 +3005,7 @@ found: return nm_platform_wifi_set_wake_on_wlan(NM_PLATFORM_GET, nm_device_get_ifindex(NM_DEVICE(self)), - wowl); + wowl2); } static NMActStageReturn @@ -3022,16 +3034,16 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) mode = nm_setting_wireless_get_mode(s_wireless); if (g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_INFRA) == 0) - priv->mode = NM_802_11_MODE_INFRA; + priv->mode = _NM_802_11_MODE_INFRA; else if (g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_ADHOC) == 0) - priv->mode = NM_802_11_MODE_ADHOC; + priv->mode = _NM_802_11_MODE_ADHOC; else if (g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_AP) == 0) { - priv->mode = NM_802_11_MODE_AP; + priv->mode = _NM_802_11_MODE_AP; /* Scanning not done in AP mode; clear the scan list */ remove_all_aps(self); } else if (g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_MESH) == 0) - priv->mode = NM_802_11_MODE_MESH; + priv->mode = _NM_802_11_MODE_MESH; _notify(self, PROP_MODE); /* expire the temporary MAC address used during scanning */ @@ -3044,7 +3056,7 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) } /* AP and Mesh modes never use a specific object or existing scanned AP */ - if (!NM_IN_SET(priv->mode, NM_802_11_MODE_AP, NM_802_11_MODE_MESH)) { + if (!NM_IN_SET(priv->mode, _NM_802_11_MODE_AP, _NM_802_11_MODE_MESH)) { ap_path = nm_active_connection_get_specific_object(NM_ACTIVE_CONNECTION(req)); ap = ap_path ? nm_wifi_ap_lookup_for_device(NM_DEVICE(self), ap_path) : NULL; } @@ -3146,7 +3158,7 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) NMDeviceWifi * self = NM_DEVICE_WIFI(device); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); gs_unref_object NMSupplicantConfig *config = NULL; - NM80211Mode ap_mode; + _NM80211Mode ap_mode; NMActRequest * req; NMWifiAP * ap; NMConnection * connection; @@ -3213,10 +3225,11 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) * if the user didn't specify one and we didn't find an AP that matched * the connection, just pick a frequency the device supports. */ - if (NM_IN_SET(ap_mode, NM_802_11_MODE_ADHOC, NM_802_11_MODE_MESH) || nm_wifi_ap_is_hotspot(ap)) + if (NM_IN_SET(ap_mode, _NM_802_11_MODE_ADHOC, _NM_802_11_MODE_MESH) + || nm_wifi_ap_is_hotspot(ap)) ensure_hotspot_frequency(self, s_wireless, ap); - if (ap_mode == NM_802_11_MODE_INFRA) + if (ap_mode == _NM_802_11_MODE_INFRA) set_powersave(device); /* Build up the supplicant configuration */ @@ -3333,7 +3346,7 @@ act_stage4_ip_config_timeout(NMDevice * device, s_ip = nm_connection_get_setting_ip_config(connection, addr_family); may_fail = nm_setting_ip_config_get_may_fail(s_ip); - if (priv->mode == NM_802_11_MODE_AP) + if (priv->mode == _NM_802_11_MODE_AP) goto call_parent; if (may_fail || !is_static_wep(connection)) { @@ -3686,8 +3699,8 @@ nm_device_wifi_init(NMDeviceWifi *self) priv->scan_last_request_started_at_msec = G_MININT64; priv->hidden_probe_scan_warn = TRUE; - priv->mode = NM_802_11_MODE_INFRA; - priv->wowlan_restore = NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE; + priv->mode = _NM_802_11_MODE_INFRA; + priv->wowlan_restore = _NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE; } static void @@ -3698,7 +3711,7 @@ constructed(GObject *object) G_OBJECT_CLASS(nm_device_wifi_parent_class)->constructed(object); - if (priv->capabilities & NM_WIFI_DEVICE_CAP_AP) + if (priv->capabilities & _NM_WIFI_DEVICE_CAP_AP) _LOGI(LOGD_PLATFORM | LOGD_WIFI, "driver supports Access Point (AP) mode"); /* Connect to the supplicant manager */ @@ -3706,7 +3719,7 @@ constructed(GObject *object) } NMDevice * -nm_device_wifi_new(const char *iface, NMDeviceWifiCapabilities capabilities) +nm_device_wifi_new(const char *iface, _NMDeviceWifiCapabilities capabilities) { return g_object_new(NM_TYPE_DEVICE_WIFI, NM_DEVICE_IFACE, @@ -3814,9 +3827,9 @@ nm_device_wifi_class_init(NMDeviceWifiClass *klass) obj_properties[PROP_MODE] = g_param_spec_uint(NM_DEVICE_WIFI_MODE, "", "", - NM_802_11_MODE_UNKNOWN, - NM_802_11_MODE_AP, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_UNKNOWN, + _NM_802_11_MODE_AP, + _NM_802_11_MODE_INFRA, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_BITRATE] = g_param_spec_uint(NM_DEVICE_WIFI_BITRATE, @@ -3847,7 +3860,7 @@ nm_device_wifi_class_init(NMDeviceWifiClass *klass) "", 0, G_MAXUINT32, - NM_WIFI_DEVICE_CAP_NONE, + _NM_WIFI_DEVICE_CAP_NONE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); obj_properties[PROP_SCANNING] = g_param_spec_boolean(NM_DEVICE_WIFI_SCANNING, diff --git a/src/core/devices/wifi/nm-device-wifi.h b/src/core/devices/wifi/nm-device-wifi.h index d9e9038c..c7ff1a14 100644 --- a/src/core/devices/wifi/nm-device-wifi.h +++ b/src/core/devices/wifi/nm-device-wifi.h @@ -33,7 +33,7 @@ typedef struct _NMDeviceWifiClass NMDeviceWifiClass; GType nm_device_wifi_get_type(void); -NMDevice *nm_device_wifi_new(const char *iface, NMDeviceWifiCapabilities capabilities); +NMDevice *nm_device_wifi_new(const char *iface, _NMDeviceWifiCapabilities capabilities); const CList *_nm_device_wifi_get_aps(NMDeviceWifi *self); diff --git a/src/core/devices/wifi/nm-iwd-manager.c b/src/core/devices/wifi/nm-iwd-manager.c index b4b019d3..56386c57 100644 --- a/src/core/devices/wifi/nm-iwd-manager.c +++ b/src/core/devices/wifi/nm-iwd-manager.c @@ -8,14 +8,20 @@ #include "nm-iwd-manager.h" #include +#include +#include +#include -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-manager.h" #include "nm-device-iwd.h" #include "nm-wifi-utils.h" -#include "nm-glib-aux/nm-random-utils.h" +#include "libnm-glib-aux/nm-uuid.h" +#include "libnm-glib-aux/nm-random-utils.h" +#include "libnm-glib-aux/nm-io-utils.h" #include "settings/nm-settings.h" -#include "nm-std-aux/nm-dbus-compat.h" +#include "libnm-std-aux/nm-dbus-compat.h" +#include "nm-config.h" /*****************************************************************************/ @@ -28,6 +34,7 @@ typedef struct { typedef struct { GDBusProxy * known_network; NMSettingsConnection *mirror_connection; + const KnownNetworkId *id; } KnownNetworkData; typedef struct { @@ -40,6 +47,8 @@ typedef struct { char * agent_path; GHashTable * known_networks; NMDeviceIwd * last_agent_call_device; + char * last_state_dir; + char * warned_state_dir; } NMIwdManagerPrivate; struct _NMIwdManager { @@ -419,25 +428,94 @@ known_network_update_cb(GObject *source, GAsyncResult *res, gpointer user_data) variant = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error); if (!variant) { nm_log_warn(LOGD_WIFI, - "Updating %s on IWD known network %s failed: %s", + "iwd: updating %s on IWD known network %s failed: %s", (const char *) user_data, g_dbus_proxy_get_object_path(G_DBUS_PROXY(source)), error->message); } } +static gboolean +iwd_config_write(GKeyFile * config, + const char * filepath, + const struct timespec *mtime, + GError ** error) +{ + gsize length; + gs_free char * data = g_key_file_to_data(config, &length, NULL); + struct timespec times[2] = {{.tv_nsec = UTIME_OMIT}, *mtime}; + + /* Atomically write or replace the file with the right permission bits + * and timestamps set. We rely on the temporary file created by + * nm_utils_file_set_contents having only upper-case letters and digits + * in the last few filename characters -- it cannot end in .open, .psk + * or .8021x. + */ + return nm_utils_file_set_contents(filepath, data, length, 0600, times, NULL, error); +} + +static const char * +get_config_path(NMIwdManager *self) +{ + NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); + const char * path; + + path = nm_config_data_get_iwd_config_path(NM_CONFIG_GET_DATA); + if (path && path[0] == '\0') { + nm_clear_g_free(&priv->warned_state_dir); + return NULL; + } + + if (!path || nm_streq(path, "auto")) { + path = priv->last_state_dir; + if (!path) { + nm_clear_g_free(&priv->warned_state_dir); + return NULL; + } + } + + if (priv->warned_state_dir && !nm_streq(priv->warned_state_dir, path)) + nm_clear_g_free(&priv->warned_state_dir); + + if (path && (path[0] != '/' || !g_file_test(path, G_FILE_TEST_IS_DIR))) { + if (!priv->warned_state_dir) { + priv->warned_state_dir = g_strdup(path); + _LOGW("IWD StateDirectory '%s' not accessible", priv->warned_state_dir); + } + return NULL; + } + + return path; +} + static void -sett_conn_changed(NMSettingsConnection *sett_conn, guint update_reason, KnownNetworkData *data) +sett_conn_changed(NMSettingsConnection * sett_conn, + guint update_reason, + const KnownNetworkData *data) { NMSettingsConnectionIntFlags flags; - NMConnection * conn = nm_settings_connection_get_connection(sett_conn); - NMSettingConnection * s_conn = nm_connection_get_setting_connection(conn); - gboolean nm_autoconnectable = nm_setting_connection_get_autoconnect(s_conn); - gboolean iwd_autoconnectable = get_property_bool(data->known_network, "AutoConnect", TRUE); + NMConnection * conn = nm_settings_connection_get_connection(sett_conn); + NMSettingConnection * s_conn = nm_connection_get_setting_connection(conn); + NMSettingWireless * s_wifi = nm_connection_get_setting_wireless(conn); + nm_auto_unref_keyfile GKeyFile *iwd_config = NULL; + const char * iwd_dir; + gs_free char * filename = NULL; + gs_free char * full_path = NULL; + gs_free_error GError *error = NULL; + NMIwdNetworkSecurity security; + GBytes * ssid; + const guint8 * ssid_data; + gsize ssid_len; + gboolean removed; + GStatBuf statbuf; + gboolean have_mtime; nm_assert(sett_conn == data->mirror_connection); - if (iwd_autoconnectable == nm_autoconnectable) + if (!NM_FLAGS_ANY(update_reason, + NM_SETTINGS_CONNECTION_UPDATE_REASON_UPDATE_NON_SECRET + | NM_SETTINGS_CONNECTION_UPDATE_REASON_CLEAR_SYSTEM_SECRETS + | NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_SYSTEM_SECRETS)) return; /* If this is a generated connection it may be ourselves updating it */ @@ -445,21 +523,131 @@ sett_conn_changed(NMSettingsConnection *sett_conn, guint update_reason, KnownNet if (NM_FLAGS_HAS(flags, NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) return; + iwd_dir = get_config_path(nm_iwd_manager_get()); + if (!iwd_dir) { + gboolean nm_autoconnectable = nm_setting_connection_get_autoconnect(s_conn); + gboolean iwd_autoconnectable = get_property_bool(data->known_network, "AutoConnect", TRUE); + + if (iwd_autoconnectable != nm_autoconnectable) { + nm_log_dbg(LOGD_WIFI, + "iwd: updating AutoConnect on known network at %s based on connection %s", + g_dbus_proxy_get_object_path(data->known_network), + nm_settings_connection_get_id(data->mirror_connection)); + g_dbus_proxy_call(data->known_network, + DBUS_INTERFACE_PROPERTIES ".Set", + g_variant_new("(ssv)", + NM_IWD_KNOWN_NETWORK_INTERFACE, + "AutoConnect", + g_variant_new_boolean(nm_autoconnectable)), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + known_network_update_cb, + "AutoConnect"); + } + + return; + } + + /* If the SSID and the security type in the NMSettingsConnection haven't + * changed, we just need to overwrite the original IWD config file. + * Otherwise we need to call Forget on the original KnownNetwork or + * remove its file. IWD will have to delete one D-Bus object and + * create another anyway because the SSID and security type are in the + * D-Bus object path, so no point renaming the file. + */ + ssid = nm_setting_wireless_get_ssid(s_wifi); + ssid_data = ssid ? g_bytes_get_data(ssid, &ssid_len) : NULL; + removed = FALSE; + have_mtime = FALSE; + + if (!nm_wifi_connection_get_iwd_ssid_and_security(conn, NULL, &security) + || security != data->id->security || !ssid_data || ssid_len != strlen(data->id->name) + || memcmp(ssid_data, data->id->name, ssid_len)) { + gs_free char *orig_filename = + nm_wifi_utils_get_iwd_config_filename(data->id->name, -1, data->id->security); + gs_free char *orig_full_path = g_strdup_printf("%s/%s", iwd_dir, orig_filename); + + if (g_stat(orig_full_path, &statbuf) == 0) + have_mtime = TRUE; + + if (g_remove(orig_full_path) == 0) + nm_log_dbg(LOGD_WIFI, "iwd: profile at %s removed", orig_full_path); + else if (errno != ENOENT) + nm_log_dbg(LOGD_WIFI, + "iwd: profile at %s not removed: %s (%i)", + orig_full_path, + strerror(errno), + errno); + + removed = TRUE; + } + + if (!nm_streq(nm_settings_connection_get_connection_type(sett_conn), "802-11-wireless") + || !s_wifi) + return; + + /* If the connection has any permissions other than the default we don't + * want to save it as an IWD profile. IWD will make it available for + * everybody to attempt a connection, remove, or toggle "autoconnectable". + */ + if (s_conn && nm_setting_connection_get_num_permissions(s_conn)) { + nm_log_dbg( + LOGD_WIFI, + "iwd: changed Wi-Fi connection %s not mirrored as IWD profile because of non-default " + "permissions", + nm_settings_connection_get_id(sett_conn)); + return; + } + + iwd_config = nm_wifi_utils_connection_to_iwd_config(conn, &filename, &error); + if (!iwd_config) { + /* The error message here is not translated and it only goes in + * the logs. + */ + nm_log_dbg(LOGD_WIFI, + "iwd: changed Wi-Fi connection %s not mirrored as IWD profile: %s", + nm_settings_connection_get_id(sett_conn), + error->message); + return; + } + + full_path = g_strdup_printf("%s/%s", iwd_dir, filename); + if (removed && g_file_test(full_path, G_FILE_TEST_EXISTS)) { + nm_log_dbg(LOGD_WIFI, + "iwd: changed Wi-Fi connection %s not mirrored as IWD profile because %s " + "already exists", + nm_settings_connection_get_id(sett_conn), + full_path); + return; + } + + if (!removed && g_stat(full_path, &statbuf) == 0) + have_mtime = TRUE; + + /* If modifying an existing network try to preserve the file mtime, + * otherwise use a small non-zero timespec value to signal that the + * network is autoconnectable (according to its AutoConnect value) + * but hasn't recently been connected to and thus shouldn't be + * prioritized by autoconnect. + */ + if (!have_mtime) { + statbuf.st_mtim.tv_sec = 1; + statbuf.st_mtim.tv_nsec = 0; + } + + if (!iwd_config_write(iwd_config, full_path, &statbuf.st_mtim, &error)) { + nm_log_dbg(LOGD_WIFI, + "iwd: changed Wi-Fi connection %s not mirrored as IWD profile: save error: %s", + nm_settings_connection_get_id(sett_conn), + error->message); + return; + } + nm_log_dbg(LOGD_WIFI, - "Updating AutoConnect on known network at %s based on connection %s", - g_dbus_proxy_get_object_path(data->known_network), - nm_settings_connection_get_id(data->mirror_connection)); - g_dbus_proxy_call(data->known_network, - DBUS_INTERFACE_PROPERTIES ".Set", - g_variant_new("(ssv)", - NM_IWD_KNOWN_NETWORK_INTERFACE, - "AutoConnect", - g_variant_new_boolean(nm_autoconnectable)), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - known_network_update_cb, - "AutoConnect"); + "iwd: changed Wi-Fi connection %s mirrored as IWD profile %s", + nm_settings_connection_get_id(sett_conn), + full_path); } /* Look up an existing NMSettingsConnection for a network that has been @@ -590,8 +778,10 @@ mirror_connection(NMIwdManager * self, NULL); g_object_set(G_OBJECT(s_wifi), NM_SETTING_WIRELESS_HIDDEN, hidden, NULL); } else { - KnownNetworkData data = {known_network, settings_connection}; - sett_conn_changed(settings_connection, 0, &data); + KnownNetworkData data = {known_network, settings_connection, id}; + sett_conn_changed(settings_connection, + NM_SETTINGS_CONNECTION_UPDATE_REASON_UPDATE_NON_SECRET, + &data); } } @@ -621,7 +811,7 @@ mirror_connection(NMIwdManager * self, NM_SETTING_CONNECTION_ID, id->name, NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_buf(uuid), + nm_uuid_generate_random_str_arr(uuid), NM_SETTING_CONNECTION_AUTOCONNECT, autoconnectable, NULL); @@ -779,6 +969,7 @@ interface_added(GDBusObjectManager *object_manager, } else { data = g_slice_new0(KnownNetworkData); data->known_network = g_object_ref(proxy); + data->id = id; g_hash_table_insert(priv->known_networks, id, data); } @@ -907,6 +1098,9 @@ connection_removed(NMSettings *settings, NMSettingsConnection *sett_conn, gpoint const guint8 * ssid_bytes; gsize ssid_len; NMSettingsConnection *new_mirror_conn; + const char * iwd_dir; + gs_free char * filename = NULL; + gs_free char * full_path = NULL; if (!nm_wifi_connection_get_iwd_ssid_and_security(conn, NULL, &id.security)) return; @@ -923,8 +1117,12 @@ connection_removed(NMSettings *settings, NMSettingsConnection *sett_conn, gpoint ssid_buf[ssid_len] = '\0'; id.name = ssid_buf; data = g_hash_table_lookup(priv->known_networks, &id); - if (!data) - return; + if (!data) { + if (!g_utf8_validate((const char *) ssid_bytes, ssid_len, NULL)) + return; + + goto try_delete_file; + } if (data->mirror_connection != sett_conn) return; @@ -941,7 +1139,7 @@ connection_removed(NMSettings *settings, NMSettingsConnection *sett_conn, gpoint } if (!priv->running) - return; + goto try_delete_file; g_dbus_proxy_call(data->known_network, "Forget", @@ -951,6 +1149,91 @@ connection_removed(NMSettings *settings, NMSettingsConnection *sett_conn, gpoint NULL, NULL, NULL); + return; + +try_delete_file: + if (mirror_connection(self, &id, FALSE, NULL)) + return; + + iwd_dir = get_config_path(self); + if (!iwd_dir) + return; + + filename = nm_wifi_utils_get_iwd_config_filename(id.name, ssid_len, id.security); + full_path = g_strdup_printf("%s/%s", iwd_dir, filename); + if (g_remove(full_path) == 0) + _LOGD("IWD profile at %s removed", full_path); + else if (errno != ENOENT) + _LOGD("IWD profile at %s not removed: %s (%i)", full_path, strerror(errno), errno); +} + +static void +connection_added(NMSettings *settings, NMSettingsConnection *sett_conn, gpointer user_data) +{ + NMIwdManager * self = user_data; + NMConnection * conn = nm_settings_connection_get_connection(sett_conn); + NMSettingConnection *s_conn = nm_connection_get_setting_connection(conn); + const char * iwd_dir; + gs_free char * filename = NULL; + gs_free char * full_path = NULL; + gs_free_error GError *error = NULL; + nm_auto_unref_keyfile GKeyFile *iwd_config = NULL; + NMSettingsConnectionIntFlags flags; + + if (!nm_streq(nm_settings_connection_get_connection_type(sett_conn), "802-11-wireless")) + return; + + iwd_dir = get_config_path(self); + if (!iwd_dir) + return; + + /* If this is a generated connection it may be ourselves creating it and + * directly assigning it to a KnownNetwork's .mirror_connection. + */ + flags = nm_settings_connection_get_flags(sett_conn); + if (NM_FLAGS_HAS(flags, NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) + return; + + /* If the connection has any permissions other than the default we don't + * want to save it as an IWD profile. IWD will make it available for + * everybody to attempt a connection, remove, or toggle "autoconnectable". + */ + if (s_conn && nm_setting_connection_get_num_permissions(s_conn)) { + _LOGD("New Wi-Fi connection %s not mirrored as IWD profile because of non-default " + "permissions", + nm_settings_connection_get_id(sett_conn)); + return; + } + + iwd_config = nm_wifi_utils_connection_to_iwd_config(conn, &filename, &error); + if (!iwd_config) { + /* The error message here is not translated and it only goes in + * the logs. + */ + _LOGD("New Wi-Fi connection %s not mirrored as IWD profile: %s", + nm_settings_connection_get_id(sett_conn), + error->message); + return; + } + + full_path = g_strdup_printf("%s/%s", iwd_dir, filename); + if (g_file_test(full_path, G_FILE_TEST_EXISTS)) { + _LOGD("New Wi-Fi connection %s not mirrored as IWD profile because %s already exists", + nm_settings_connection_get_id(sett_conn), + full_path); + return; + } + + if (!g_key_file_save_to_file(iwd_config, full_path, &error)) { + _LOGD("New Wi-Fi connection %s not mirrored as IWD profile: save error: %s", + nm_settings_connection_get_id(sett_conn), + error->message); + return; + } + + _LOGD("New Wi-Fi connection %s mirrored as IWD profile %s", + nm_settings_connection_get_id(sett_conn), + full_path); } static gboolean @@ -1115,10 +1398,11 @@ device_removed(NMManager *manager, NMDevice *device, gpointer user_data) static int object_compare_interfaces(gconstpointer a, gconstpointer b) { - static const char *interface_order[] = { + static const char *const interface_order[] = { NM_IWD_KNOWN_NETWORK_INTERFACE, NM_IWD_NETWORK_INTERFACE, NM_IWD_DEVICE_INTERFACE, + NULL, }; int rank_a = G_N_ELEMENTS(interface_order); int rank_b = G_N_ELEMENTS(interface_order); @@ -1144,6 +1428,56 @@ object_compare_interfaces(gconstpointer a, gconstpointer b) return rank_a - rank_b; } +static void +get_daemon_info_cb(GObject *source, GAsyncResult *res, gpointer user_data) +{ + NMIwdManager * self = user_data; + NMIwdManagerPrivate *priv; + gs_unref_variant GVariant *properties = NULL; + gs_free_error GError *error = NULL; + GVariantIter * properties_iter; + const char * key; + GVariant * value; + + properties = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error); + if (!properties) { + if (nm_utils_error_is_cancelled(error)) + return; + + nm_log_warn(LOGD_WIFI, "iwd: Daemon.GetInfo() failed: %s", error->message); + return; + } + + priv = NM_IWD_MANAGER_GET_PRIVATE(self); + + if (!g_variant_is_of_type(properties, G_VARIANT_TYPE("(a{sv})"))) { + _LOGE("Daemon.GetInfo returned type %s instead of (a{sv})", + g_variant_get_type_string(properties)); + return; + } + + g_variant_get(properties, "(a{sv})", &properties_iter); + + while (g_variant_iter_next(properties_iter, "{&sv}", &key, &value)) { + if (nm_streq(key, "StateDirectory")) { + if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) { + _LOGE("Daemon.GetInfo property %s is typed '%s' instead of 's'", + key, + g_variant_get_type_string(value)); + goto next; + } + + nm_clear_g_free(&priv->last_state_dir); + priv->last_state_dir = g_variant_dup_string(value, NULL); + } + +next: + g_variant_unref(value); + } + + g_variant_iter_free(properties_iter); +} + static void got_object_manager(GObject *object, GAsyncResult *result, gpointer user_data) { @@ -1181,7 +1515,8 @@ got_object_manager(GObject *object, GAsyncResult *result, gpointer user_data) } if (_om_has_name_owner(object_manager)) { - GList *objects, *iter; + GList * objects, *iter; + gs_unref_object GDBusInterface *daemon = NULL; priv->running = true; @@ -1207,6 +1542,19 @@ got_object_manager(GObject *object, GAsyncResult *result, gpointer user_data) if (priv->agent_id) register_agent(self); + + daemon = g_dbus_object_manager_get_interface(object_manager, + "/net/connman/iwd", /* IWD 1.15+ */ + NM_IWD_DAEMON_INTERFACE); + if (daemon) + g_dbus_proxy_call(G_DBUS_PROXY(daemon), + "GetInfo", + g_variant_new("()"), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + get_daemon_info_cb, + self); } } @@ -1304,11 +1652,31 @@ nm_iwd_manager_init(NMIwdManager *self) g_signal_connect(priv->manager, NM_MANAGER_DEVICE_ADDED, G_CALLBACK(device_added), self); g_signal_connect(priv->manager, NM_MANAGER_DEVICE_REMOVED, G_CALLBACK(device_removed), self); + /* The current logic is that we track all creations and removals but + * for modifications we only listen to those connections that are + * currently a KnownNetwork's mirror_connection. There may be multiple + * NMSettingsConnections referring to the same SSID+Security type tuple + * so to the same KnownNetwork. So to make connection profile editing + * work at least for the simple cases, we track one NMSettingsConnection + * out of those, and we map its changes to the IWD KnownNetwork. + * + * When an NMSettingsConnection is created by a user for a completely + * new network and the settings are compatible with IWD, we create an + * IWD KnownNetwork config file for it. IWD will notice that and a + * KnownNetwork objects pops up on D-Bus. We look up a suitable + * mirror_connection for it and only then subscribe to modification + * signals. There are various different ways that this could be done, + * it's not clear which one's the best. + */ priv->settings = g_object_ref(NM_SETTINGS_GET); g_signal_connect(priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, G_CALLBACK(connection_removed), self); + g_signal_connect(priv->settings, + NM_SETTINGS_SIGNAL_CONNECTION_ADDED, + G_CALLBACK(connection_added), + self); priv->cancellable = g_cancellable_new(); @@ -1347,6 +1715,9 @@ dispose(GObject *object) priv->last_agent_call_device = NULL; + nm_clear_g_free(&priv->last_state_dir); + nm_clear_g_free(&priv->warned_state_dir); + G_OBJECT_CLASS(nm_iwd_manager_parent_class)->dispose(object); } diff --git a/src/core/devices/wifi/nm-iwd-manager.h b/src/core/devices/wifi/nm-iwd-manager.h index 466f67c7..e794e661 100644 --- a/src/core/devices/wifi/nm-iwd-manager.h +++ b/src/core/devices/wifi/nm-iwd-manager.h @@ -13,6 +13,7 @@ #define NM_IWD_BUS_TYPE G_BUS_TYPE_SYSTEM #define NM_IWD_SERVICE "net.connman.iwd" +#define NM_IWD_DAEMON_INTERFACE "net.connman.iwd.Daemon" #define NM_IWD_AGENT_MANAGER_INTERFACE "net.connman.iwd.AgentManager" #define NM_IWD_WIPHY_INTERFACE "net.connman.iwd.Adapter" #define NM_IWD_DEVICE_INTERFACE "net.connman.iwd.Device" diff --git a/src/core/devices/wifi/nm-wifi-ap.c b/src/core/devices/wifi/nm-wifi-ap.c index 08fa10ec..20ed6833 100644 --- a/src/core/devices/wifi/nm-wifi-ap.c +++ b/src/core/devices/wifi/nm-wifi-ap.c @@ -13,13 +13,13 @@ #include "NetworkManagerUtils.h" #include "devices/nm-device.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-dbus-manager.h" -#include "nm-glib-aux/nm-ref-string.h" +#include "libnm-glib-aux/nm-ref-string.h" #include "nm-setting-wireless.h" #include "nm-utils.h" #include "nm-wifi-utils.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "supplicant/nm-supplicant-interface.h" #define PROTO_WPA "wpa" @@ -41,12 +41,12 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMWifiAP, struct _NMWifiAPPrivate { /* Scanned or cached values */ - GBytes * ssid; - char * address; - NM80211Mode mode; - 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) */ + GBytes * ssid; + char * address; + _NM80211Mode mode; + 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) */ gint64 last_seen_msec; /* Timestamp when the AP was seen lastly (in nm_utils_get_monotonic_timestamp_*() scale). @@ -98,7 +98,7 @@ nm_wifi_ap_set_ssid(NMWifiAP *ap, GBytes *ssid) } l = g_bytes_get_size(ssid); - if (l == 0 || l > 32) + if (l == 0 || l > NM_IW_ESSID_MAX_SIZE) g_return_val_if_reached(FALSE); priv = NM_WIFI_AP_GET_PRIVATE(ap); @@ -191,24 +191,24 @@ nm_wifi_ap_set_address(NMWifiAP *ap, const char *addr) return nm_wifi_ap_set_address_bin(ap, &addr_buf); } -NM80211Mode +_NM80211Mode nm_wifi_ap_get_mode(NMWifiAP *ap) { - g_return_val_if_fail(NM_IS_WIFI_AP(ap), NM_802_11_MODE_UNKNOWN); + g_return_val_if_fail(NM_IS_WIFI_AP(ap), _NM_802_11_MODE_UNKNOWN); return NM_WIFI_AP_GET_PRIVATE(ap)->mode; } static gboolean -nm_wifi_ap_set_mode(NMWifiAP *ap, NM80211Mode mode) +nm_wifi_ap_set_mode(NMWifiAP *ap, _NM80211Mode mode) { NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(ap); nm_assert(NM_IN_SET(mode, - NM_802_11_MODE_UNKNOWN, - NM_802_11_MODE_ADHOC, - NM_802_11_MODE_INFRA, - NM_802_11_MODE_MESH)); + _NM_802_11_MODE_UNKNOWN, + _NM_802_11_MODE_ADHOC, + _NM_802_11_MODE_INFRA, + _NM_802_11_MODE_MESH)); if (priv->mode != mode) { priv->mode = mode; @@ -513,34 +513,35 @@ nm_wifi_ap_to_string(const NMWifiAP *self, char *str_buf, gulong buf_len, gint64 nm_utils_get_monotonic_timestamp_msec_cached(&now_msec); - g_snprintf(str_buf, - buf_len, - "%17s %-35s [ %c %3u %3u%% %c%c %c%c W:%04X R:%04X ] %s sup:%s [nm:%s]", - priv->address ?: "(none)", - (ssid_to_free = _nm_utils_ssid_to_string(priv->ssid)), - (priv->mode == NM_802_11_MODE_ADHOC - ? '*' - : (priv->hotspot - ? '#' - : (priv->fake ? 'f' : (priv->mode == NM_802_11_MODE_MESH ? 'm' : 'a')))), - chan, - priv->strength, - priv->flags & NM_802_11_AP_FLAGS_PRIVACY ? 'P' : '_', - priv->metered ? 'M' : '_', - priv->flags & NM_802_11_AP_FLAGS_WPS ? 'W' : '_', - priv->flags & NM_802_11_AP_FLAGS_WPS_PIN - ? 'p' - : (priv->flags & NM_802_11_AP_FLAGS_WPS_PBC ? '#' : '_'), - priv->wpa_flags & 0xFFFF, - priv->rsn_flags & 0xFFFF, - priv->last_seen_msec != G_MININT64 - ? nm_sprintf_buf(str_buf_ts, - "%3u.%03us", - (guint)((now_msec - priv->last_seen_msec) / 1000), - (guint)((now_msec - priv->last_seen_msec) % 1000)) - : " ", - supplicant_id, - export_path); + g_snprintf( + str_buf, + buf_len, + "%17s %-35s [ %c %3u %3u%% %c%c %c%c W:%04X R:%04X ] %s sup:%s [nm:%s]", + priv->address ?: "(none)", + (ssid_to_free = _nm_utils_ssid_to_string_gbytes(priv->ssid)), + (priv->mode == _NM_802_11_MODE_ADHOC + ? '*' + : (priv->hotspot + ? '#' + : (priv->fake ? 'f' : (priv->mode == _NM_802_11_MODE_MESH ? 'm' : 'a')))), + chan, + priv->strength, + priv->flags & NM_802_11_AP_FLAGS_PRIVACY ? 'P' : '_', + priv->metered ? 'M' : '_', + priv->flags & NM_802_11_AP_FLAGS_WPS ? 'W' : '_', + priv->flags & NM_802_11_AP_FLAGS_WPS_PIN + ? 'p' + : (priv->flags & NM_802_11_AP_FLAGS_WPS_PBC ? '#' : '_'), + priv->wpa_flags & 0xFFFF, + priv->rsn_flags & 0xFFFF, + priv->last_seen_msec != G_MININT64 + ? nm_sprintf_buf(str_buf_ts, + "%3u.%03us", + (guint) ((now_msec - priv->last_seen_msec) / 1000), + (guint) ((now_msec - priv->last_seen_msec) % 1000)) + : " ", + supplicant_id, + export_path); return str_buf; } @@ -589,13 +590,13 @@ nm_wifi_ap_check_compatible(NMWifiAP *self, NMConnection *connection) mode = nm_setting_wireless_get_mode(s_wireless); if (mode) { - if (!strcmp(mode, "infrastructure") && (priv->mode != NM_802_11_MODE_INFRA)) + if (!strcmp(mode, "infrastructure") && (priv->mode != _NM_802_11_MODE_INFRA)) return FALSE; - if (!strcmp(mode, "adhoc") && (priv->mode != NM_802_11_MODE_ADHOC)) + if (!strcmp(mode, "adhoc") && (priv->mode != _NM_802_11_MODE_ADHOC)) return FALSE; - if (!strcmp(mode, "ap") && (priv->mode != NM_802_11_MODE_INFRA || priv->hotspot != TRUE)) + if (!strcmp(mode, "ap") && (priv->mode != _NM_802_11_MODE_INFRA || priv->hotspot != TRUE)) return FALSE; - if (!strcmp(mode, "mesh") && (priv->mode != NM_802_11_MODE_MESH)) + if (!strcmp(mode, "mesh") && (priv->mode != _NM_802_11_MODE_MESH)) return FALSE; } @@ -624,7 +625,7 @@ nm_wifi_ap_check_compatible(NMWifiAP *self, NMConnection *connection) priv->flags, priv->wpa_flags, priv->rsn_flags, - priv->mode); + NM_802_11_MODE_CAST(priv->mode)); } gboolean @@ -713,7 +714,7 @@ nm_wifi_ap_init(NMWifiAP *self) c_list_init(&self->aps_lst); - priv->mode = NM_802_11_MODE_INFRA; + 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; @@ -758,19 +759,19 @@ nm_wifi_ap_new_fake_from_connection(NMConnection *connection) mode = nm_setting_wireless_get_mode(s_wireless); if (mode) { if (!strcmp(mode, "infrastructure")) - nm_wifi_ap_set_mode(ap, NM_802_11_MODE_INFRA); + nm_wifi_ap_set_mode(ap, _NM_802_11_MODE_INFRA); else if (!strcmp(mode, "adhoc")) { - nm_wifi_ap_set_mode(ap, NM_802_11_MODE_ADHOC); + nm_wifi_ap_set_mode(ap, _NM_802_11_MODE_ADHOC); adhoc = TRUE; } else if (!strcmp(mode, "mesh")) - nm_wifi_ap_set_mode(ap, NM_802_11_MODE_MESH); + nm_wifi_ap_set_mode(ap, _NM_802_11_MODE_MESH); else if (!strcmp(mode, "ap")) { - nm_wifi_ap_set_mode(ap, NM_802_11_MODE_INFRA); + nm_wifi_ap_set_mode(ap, _NM_802_11_MODE_INFRA); NM_WIFI_AP_GET_PRIVATE(ap)->hotspot = TRUE; } else goto error; } else { - nm_wifi_ap_set_mode(ap, NM_802_11_MODE_INFRA); + nm_wifi_ap_set_mode(ap, _NM_802_11_MODE_INFRA); } band = nm_setting_wireless_get_band(s_wireless); @@ -861,27 +862,21 @@ finalize(GObject *object) static const NMDBusInterfaceInfoExtended interface_info_access_point = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_ACCESS_POINT, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Flags", "u", NM_WIFI_AP_FLAGS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("WpaFlags", "u", NM_WIFI_AP_WPA_FLAGS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("RsnFlags", "u", NM_WIFI_AP_RSN_FLAGS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Ssid", "ay", NM_WIFI_AP_SSID), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Frequency", - "u", - NM_WIFI_AP_FREQUENCY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_WIFI_AP_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Mode", "u", NM_WIFI_AP_MODE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("MaxBitrate", - "u", - NM_WIFI_AP_MAX_BITRATE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Strength", "y", NM_WIFI_AP_STRENGTH), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("LastSeen", - "i", - NM_WIFI_AP_LAST_SEEN), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Flags", "u", NM_WIFI_AP_FLAGS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("WpaFlags", "u", NM_WIFI_AP_WPA_FLAGS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("RsnFlags", "u", NM_WIFI_AP_RSN_FLAGS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Ssid", "ay", NM_WIFI_AP_SSID), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Frequency", "u", NM_WIFI_AP_FREQUENCY), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_WIFI_AP_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Mode", "u", NM_WIFI_AP_MODE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("MaxBitrate", + "u", + NM_WIFI_AP_MAX_BITRATE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Strength", "y", NM_WIFI_AP_STRENGTH), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("LastSeen", + "i", + NM_WIFI_AP_LAST_SEEN), ), ), }; static void @@ -955,9 +950,9 @@ nm_wifi_ap_class_init(NMWifiAPClass *ap_class) obj_properties[PROP_MODE] = g_param_spec_uint(NM_WIFI_AP_MODE, "", "", - NM_802_11_MODE_ADHOC, - NM_802_11_MODE_INFRA, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_ADHOC, + _NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_MAX_BITRATE] = g_param_spec_uint(NM_WIFI_AP_MAX_BITRATE, diff --git a/src/core/devices/wifi/nm-wifi-ap.h b/src/core/devices/wifi/nm-wifi-ap.h index bdd72415..bffd28a8 100644 --- a/src/core/devices/wifi/nm-wifi-ap.h +++ b/src/core/devices/wifi/nm-wifi-ap.h @@ -10,6 +10,7 @@ #include "nm-dbus-object.h" #include "nm-dbus-interface.h" #include "nm-connection.h" +#include "libnm-base/nm-base.h" #define NM_TYPE_WIFI_AP (nm_wifi_ap_get_type()) #define NM_WIFI_AP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WIFI_AP, NMWifiAP)) @@ -69,7 +70,7 @@ gboolean nm_wifi_ap_set_ssid(NMWifiAP *ap, GBytes *ssid); const char * nm_wifi_ap_get_address(const NMWifiAP *ap); gboolean nm_wifi_ap_set_address(NMWifiAP *ap, const char *addr); gboolean nm_wifi_ap_set_address_bin(NMWifiAP *ap, const NMEtherAddr *addr); -NM80211Mode nm_wifi_ap_get_mode(NMWifiAP *ap); +_NM80211Mode nm_wifi_ap_get_mode(NMWifiAP *ap); gboolean nm_wifi_ap_is_hotspot(NMWifiAP *ap); gint8 nm_wifi_ap_get_strength(NMWifiAP *ap); gboolean nm_wifi_ap_set_strength(NMWifiAP *ap, gint8 strength); diff --git a/src/core/devices/wifi/nm-wifi-common.c b/src/core/devices/wifi/nm-wifi-common.c index c715c07c..b98ef222 100644 --- a/src/core/devices/wifi/nm-wifi-common.c +++ b/src/core/devices/wifi/nm-wifi-common.c @@ -146,31 +146,25 @@ const NMDBusInterfaceInfoExtended nm_interface_info_device_wireless = { .in_args = NM_DEFINE_GDBUS_ARG_INFOS( NM_DEFINE_GDBUS_ARG_INFO("options", "a{sv}"), ), ), .handle = impl_device_wifi_request_scan, ), ), - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, - &nm_signal_info_wireless_access_point_added, + .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_wireless_access_point_added, &nm_signal_info_wireless_access_point_removed, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("PermHwAddress", - "s", - NM_DEVICE_PERM_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Mode", "u", NM_DEVICE_WIFI_MODE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Bitrate", - "u", - NM_DEVICE_WIFI_BITRATE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("AccessPoints", - "ao", - NM_DEVICE_WIFI_ACCESS_POINTS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("ActiveAccessPoint", - "o", - NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("WirelessCapabilities", - "u", - NM_DEVICE_WIFI_CAPABILITIES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("PermHwAddress", + "s", + NM_DEVICE_PERM_HW_ADDRESS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Mode", "u", NM_DEVICE_WIFI_MODE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Bitrate", "u", NM_DEVICE_WIFI_BITRATE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("AccessPoints", + "ao", + NM_DEVICE_WIFI_ACCESS_POINTS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("ActiveAccessPoint", + "o", + NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("WirelessCapabilities", + "u", + NM_DEVICE_WIFI_CAPABILITIES), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("LastScan", "x", NM_DEVICE_WIFI_LAST_SCAN), ), ), - .legacy_property_changed = TRUE, }; diff --git a/src/core/devices/wifi/nm-wifi-factory.c b/src/core/devices/wifi/nm-wifi-factory.c index 40375e1c..d2269c74 100644 --- a/src/core/devices/wifi/nm-wifi-factory.c +++ b/src/core/devices/wifi/nm-wifi-factory.c @@ -15,7 +15,7 @@ #include "nm-device-olpc-mesh.h" #include "nm-device-iwd.h" #include "settings/nm-settings-connection.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-config.h" /*****************************************************************************/ @@ -74,7 +74,8 @@ create_device(NMDeviceFactory * factory, NMConnection * connection, gboolean * out_ignore) { - gs_free char *backend = NULL; + gs_free char *backend_free = NULL; + const char * backend; g_return_val_if_fail(iface != NULL, NULL); g_return_val_if_fail(plink != NULL, NULL); @@ -89,7 +90,7 @@ create_device(NMDeviceFactory * factory, plink, "wifi", NULL); - nm_strstrip(backend); + backend = nm_strstrip_avoid_copy_a(300, backend, &backend_free); nm_log_dbg(LOGD_PLATFORM | LOGD_WIFI, "(%s) config: backend is %s%s%s%s", @@ -97,9 +98,9 @@ create_device(NMDeviceFactory * factory, NM_PRINT_FMT_QUOTE_STRING(backend), WITH_IWD ? " (iwd support enabled)" : ""); if (!backend || !g_ascii_strcasecmp(backend, "wpa_supplicant")) { - NMDevice * device; - NMDeviceWifiCapabilities capabilities; - NM80211Mode mode; + NMDevice * device; + _NMDeviceWifiCapabilities capabilities; + _NM80211Mode mode; if (!nm_platform_wifi_get_capabilities(NM_PLATFORM_GET, plink->ifindex, &capabilities)) { nm_log_warn(LOGD_PLATFORM | LOGD_WIFI, @@ -114,7 +115,7 @@ create_device(NMDeviceFactory * factory, * them if/when they change to a handled type. */ mode = nm_platform_wifi_get_mode(NM_PLATFORM_GET, plink->ifindex); - if (mode == NM_802_11_MODE_UNKNOWN) { + if (mode == _NM_802_11_MODE_UNKNOWN) { *out_ignore = TRUE; return NULL; } diff --git a/src/core/devices/wifi/nm-wifi-p2p-peer.c b/src/core/devices/wifi/nm-wifi-p2p-peer.c index 8488f32d..433c2833 100644 --- a/src/core/devices/wifi/nm-wifi-p2p-peer.c +++ b/src/core/devices/wifi/nm-wifi-p2p-peer.c @@ -12,13 +12,13 @@ #include "NetworkManagerUtils.h" #include "devices/nm-device.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-dbus-manager.h" -#include "nm-glib-aux/nm-ref-string.h" +#include "libnm-glib-aux/nm-ref-string.h" #include "nm-setting-wireless.h" #include "nm-utils.h" #include "nm-wifi-utils.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "supplicant/nm-supplicant-types.h" /*****************************************************************************/ @@ -608,7 +608,6 @@ static const NMDBusInterfaceInfoExtended interface_info_p2p_peer = { NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("LastSeen", "i", NM_WIFI_P2P_PEER_LAST_SEEN), ), ), - .legacy_property_changed = FALSE, }; static void diff --git a/src/core/devices/wifi/nm-wifi-utils.c b/src/core/devices/wifi/nm-wifi-utils.c index aed236cc..15ced990 100644 --- a/src/core/devices/wifi/nm-wifi-utils.c +++ b/src/core/devices/wifi/nm-wifi-utils.c @@ -7,10 +7,14 @@ #include "nm-wifi-utils.h" +#include +#include #include #include "nm-utils.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" +#include "libnm-core-aux-intern/nm-common-macros.h" +#include "libnm-base/nm-config-base.h" static gboolean verify_no_wep(NMSettingWirelessSecurity *s_wsec, const char *tag, GError **error) @@ -526,7 +530,7 @@ verify_adhoc(NMSettingWirelessSecurity *s_wsec, gboolean nm_wifi_utils_complete_connection(GBytes * ap_ssid, const char * bssid, - NM80211Mode ap_mode, + _NM80211Mode ap_mode, guint32 ap_freq, guint32 ap_flags, guint32 ap_wpa_flags, @@ -575,14 +579,14 @@ nm_wifi_utils_complete_connection(GBytes * ap_ssid, /* Make sure the supplied mode matches the AP's */ if (!strcmp(mode, NM_SETTING_WIRELESS_MODE_INFRA) || !strcmp(mode, NM_SETTING_WIRELESS_MODE_AP)) { - if (ap_mode == NM_802_11_MODE_INFRA) + if (ap_mode == _NM_802_11_MODE_INFRA) valid = TRUE; } else if (!strcmp(mode, NM_SETTING_WIRELESS_MODE_ADHOC)) { - if (ap_mode == NM_802_11_MODE_ADHOC) + if (ap_mode == _NM_802_11_MODE_ADHOC) valid = TRUE; adhoc = TRUE; } else if (!strcmp(mode, NM_SETTING_WIRELESS_MODE_MESH)) { - if (ap_mode == NM_802_11_MODE_MESH) + if (ap_mode == _NM_802_11_MODE_MESH) valid = TRUE; mesh = TRUE; } @@ -600,10 +604,10 @@ nm_wifi_utils_complete_connection(GBytes * ap_ssid, } } else { mode = NM_SETTING_WIRELESS_MODE_INFRA; - if (ap_mode == NM_802_11_MODE_ADHOC) { + if (ap_mode == _NM_802_11_MODE_ADHOC) { mode = NM_SETTING_WIRELESS_MODE_ADHOC; adhoc = TRUE; - } else if (ap_mode == NM_802_11_MODE_MESH) { + } else if (ap_mode == _NM_802_11_MODE_MESH) { mode = NM_SETTING_WIRELESS_MODE_MESH; mesh = TRUE; } @@ -810,15 +814,24 @@ nm_wifi_utils_complete_connection(GBytes * ap_ssid, * setting. Since there's so much configuration required for it, there's * no way it can be automatically completed. */ - } else if ((key_mgmt && !strcmp(key_mgmt, "sae")) - || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE)) { + } else if (nm_streq0(key_mgmt, "wpa-psk") + || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE + && (ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK + || ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK))) { + g_object_set(s_wsec, + NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, + "wpa-psk", + NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, + "open", + NULL); + } else if (nm_streq0(key_mgmt, "sae") || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE)) { g_object_set(s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "sae", NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", NULL); - } else if ((key_mgmt && !strcmp(key_mgmt, "owe")) + } else if (nm_streq0(key_mgmt, "owe") || NM_FLAGS_ANY(ap_rsn_flags, NM_802_11_AP_SEC_KEY_MGMT_OWE | NM_802_11_AP_SEC_KEY_MGMT_OWE_TM)) { g_object_set(s_wsec, @@ -827,9 +840,8 @@ nm_wifi_utils_complete_connection(GBytes * ap_ssid, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", NULL); - } else if ((key_mgmt && !strcmp(key_mgmt, "wpa-psk")) - || (ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) - || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)) { + } else if (ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK + || ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) { g_object_set(s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", @@ -839,7 +851,7 @@ nm_wifi_utils_complete_connection(GBytes * ap_ssid, /* Leave proto/pairwise/group as client set them; if they are unset the * supplicant will figure out the best combination at connect time. */ - } else if ((key_mgmt && !strcmp(key_mgmt, "wpa-eap-suite-b-192")) + } else if (nm_streq0(key_mgmt, "wpa-eap-suite-b-192") || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_EAP_SUITE_B_192)) { g_object_set(s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, @@ -943,3 +955,865 @@ nm_wifi_connection_get_iwd_ssid_and_security(NMConnection * connection, return TRUE; } + +/*****************************************************************************/ + +/* Builds the IWD network configuration file name for a given SSID + * and security type pair. The SSID should be valid UTF-8 and in + * any case must contain no NUL-bytes. If @ssid is NUL-terminated, + * @ssid_len can be -1 instead of actual SSID length. + */ +char * +nm_wifi_utils_get_iwd_config_filename(const char * ssid, + gssize ssid_len, + NMIwdNetworkSecurity security) +{ + const char *security_suffix; + const char *ptr; + gboolean alnum_ssid = TRUE; + + for (ptr = ssid; ssid_len != 0 && *ptr != '\0'; ptr++, ssid_len--) + if (!g_ascii_isalnum(*ptr) && !strchr("-_ ", *ptr)) + alnum_ssid = FALSE; + + g_return_val_if_fail(ptr != ssid && ptr - ssid <= NM_IW_ESSID_MAX_SIZE, NULL); + + switch (security) { + case NM_IWD_NETWORK_SECURITY_OPEN: + security_suffix = "open"; + break; + case NM_IWD_NETWORK_SECURITY_PSK: + security_suffix = "psk"; + break; + case NM_IWD_NETWORK_SECURITY_8021X: + security_suffix = "8021x"; + break; + default: + return NULL; + } + + if (alnum_ssid) { + return g_strdup_printf("%.*s.%s", (int) (ptr - ssid), ssid, security_suffix); + } else { + char ssid_buf[NM_IW_ESSID_MAX_SIZE * 2 + 1]; + + return g_strdup_printf("=%s.%s", + nm_utils_bin2hexstr_full(ssid, ptr - ssid, '\0', FALSE, ssid_buf), + security_suffix); + } +} + +/*****************************************************************************/ + +#define SECRETS_DONT_STORE_FLAGS \ + (NM_SETTING_SECRET_FLAG_AGENT_OWNED | NM_SETTING_SECRET_FLAG_NOT_SAVED) + +static gboolean +psk_setting_to_iwd_config(GKeyFile *file, NMSettingWirelessSecurity *s_wsec, GError **error) +{ + NMSettingSecretFlags psk_flags = nm_setting_wireless_security_get_psk_flags(s_wsec); + const char * psk = nm_setting_wireless_security_get_psk(s_wsec); + gsize psk_len; + guint8 buffer[32]; + const char * key_mgmt = nm_setting_wireless_security_get_key_mgmt(s_wsec); + + if (!psk || NM_FLAGS_ANY(psk_flags, SECRETS_DONT_STORE_FLAGS)) { + if (NM_FLAGS_ANY(psk_flags, SECRETS_DONT_STORE_FLAGS)) { + nm_log_info( + LOGD_WIFI, + "IWD network config is being created wihout the PSK but IWD will save the PSK on " + "successful activation not honoring the psk-flags property"); + } + return TRUE; + } + + psk_len = strlen(psk); + if (nm_streq0(key_mgmt, "sae")) { + g_key_file_set_string(file, "Security", "Passphrase", psk); + } else if (psk_len >= 8 && psk_len <= 63) { + g_key_file_set_string(file, "Security", "Passphrase", psk); + } else if (psk_len == 64 && nm_utils_hexstr2bin_buf(psk, FALSE, FALSE, NULL, buffer)) { + g_key_file_set_string(file, "Security", "PreSharedKey", psk); + } else { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "Unknown PSK format"); + return FALSE; + } + + return TRUE; +} + +static gboolean +eap_certs_to_iwd_config(GKeyFile * file, + NMSetting8021x *s_8021x, + bool phase2, + char * iwd_prefix, + GError ** error) +{ + NMSetting8021xCKScheme ca_cert_scheme = + phase2 ? nm_setting_802_1x_get_phase2_ca_cert_scheme(s_8021x) + : nm_setting_802_1x_get_ca_cert_scheme(s_8021x); + NMSetting8021xCKScheme client_cert_scheme = + phase2 ? nm_setting_802_1x_get_phase2_client_cert_scheme(s_8021x) + : nm_setting_802_1x_get_client_cert_scheme(s_8021x); + NMSetting8021xCKScheme key_scheme; + NMSettingSecretFlags key_password_flags; + const char * ca_path = phase2 ? nm_setting_802_1x_get_phase2_ca_path(s_8021x) + : nm_setting_802_1x_get_ca_path(s_8021x); + const char * cert_path; + const char * key_path = NULL; + const char * key_password; + const char * domain_suffix_match; + const char * domain_match; + char setting_buf[128]; + + /* TODO: should check that all certificates and the key are RSA */ + /* Note: up to IWD 1.9 only the PEM encoding was supported for certificates + * and only PKCS#8 PEM for keys but we don't know the IWD version here. + * From IWD 1.10 raw (DER) X.509 certificates and PKCS#12 are also supported + * for certificates but a certificate list or chain still has to be PEM + * (i.e. if it contains more than one certificate.) Raw PKCS#12 and + * old-style OpenSSL PEM formats are also supported for keys. Hopefully + * this is in practice the same set of file:// formats as supported by + * nm_crypto_* / wpa_supplicant so we need no conversions here. + */ + + if (nm_setting_802_1x_get_system_ca_certs(s_8021x)) { + /* Either overrides or is added to the certificates in (phase2-)ca-cert + * and ca-path depending on whether it points to a file or a directory. + * We can't ignore this property so it's an error if it is set. + * Fortunately not used by nm-connection-editor. + */ + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "The system-ca-certs property is not supported"); + return FALSE; + } + + if (ca_path) { + /* To support this (and this could be applied to system-ca-certs as + * well) we'd have to scan the directory, parse the certificates and + * write a new certificate-list file to point to in the IWD config. + * This is going to create issues of where to store these files, for + * how long and with what permission bits. Fortunately this doesn't + * seem to be used by nm-connection-editor either. + * + * That file would also have to contain whatever the (phase2-)ca-cert + * propterty points to because IWD has only one CACert setting per + * phase. + */ + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "The (phase2-)ca-path property is not supported"); + return FALSE; + } + + if (ca_cert_scheme != NM_SETTING_802_1X_CK_SCHEME_UNKNOWN) { + if (ca_cert_scheme != NM_SETTING_802_1X_CK_SCHEME_PATH) { + /* To support the blob scheme we'd have to either convert the + * certificate data into a PEM payload and embed the PEM file in + * the IWD config file, which is not supported by GKeyFile, or write + * it into a new file to point to in the IWD config. This is again + * is going to create issues of where to store these files, for how + * long and with what permission bits. Fortunately this scheme isn't + * used in nm-connection-editor either. + * + * PKCS#11 is not supported by IWD in any way so we don't need to + * support the PKCS#11 URI scheme. + * + * If scheme is unknown, assume no value is set. + */ + g_set_error_literal( + error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "(phase2-)ca-cert property schemes other than file:// not supported"); + return FALSE; + } + + cert_path = phase2 ? nm_setting_802_1x_get_phase2_ca_cert_path(s_8021x) + : nm_setting_802_1x_get_ca_cert_path(s_8021x); + if (cert_path) + g_key_file_set_string(file, + "Security", + nm_sprintf_buf(setting_buf, "%s%s", iwd_prefix, "CACert"), + cert_path); + } + + if (client_cert_scheme == NM_SETTING_802_1X_CK_SCHEME_UNKNOWN) + goto private_key_done; + + if (client_cert_scheme != NM_SETTING_802_1X_CK_SCHEME_PATH) { + g_set_error_literal( + error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "(phase2-)client-cert property schemes other than file:// not supported"); + return FALSE; + } + + cert_path = phase2 ? nm_setting_802_1x_get_phase2_client_cert_path(s_8021x) + : nm_setting_802_1x_get_client_cert_path(s_8021x); + if (!cert_path) + goto private_key_done; + g_key_file_set_string(file, + "Security", + nm_sprintf_buf(setting_buf, "%s%s", iwd_prefix, "ClientCert"), + cert_path); + + key_scheme = phase2 ? nm_setting_802_1x_get_phase2_private_key_scheme(s_8021x) + : nm_setting_802_1x_get_private_key_scheme(s_8021x); + if (key_scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) + key_path = phase2 ? nm_setting_802_1x_get_phase2_private_key_path(s_8021x) + : nm_setting_802_1x_get_private_key_path(s_8021x); + if (key_scheme != NM_SETTING_802_1X_CK_SCHEME_PATH || !key_path) { + /* The same comments apply to writing the key into a temporary file + * as for the certificates (above), except this is even more + * sensitive. + */ + g_set_error_literal( + error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "(phase2-)private-key property schemes other than file:// not supported"); + return FALSE; + } + g_key_file_set_string(file, + "Security", + nm_sprintf_buf(setting_buf, "%s%s", iwd_prefix, "ClientKey"), + key_path); + + key_password = phase2 ? nm_setting_802_1x_get_phase2_private_key_password(s_8021x) + : nm_setting_802_1x_get_private_key_password(s_8021x); + key_password_flags = phase2 ? nm_setting_802_1x_get_phase2_private_key_password_flags(s_8021x) + : nm_setting_802_1x_get_private_key_password_flags(s_8021x); + if (!key_password || NM_FLAGS_ANY(key_password_flags, SECRETS_DONT_STORE_FLAGS)) { + g_key_file_set_comment( + file, + "Security", + setting_buf, + "ClientKeyPassphrase not to be saved, will be queried through the agent if needed", + NULL); + goto private_key_done; + } + g_key_file_set_string(file, + "Security", + nm_sprintf_buf(setting_buf, "%s%s", iwd_prefix, "ClientKeyPassphrase"), + key_password); + +private_key_done: + if (phase2 ? nm_setting_802_1x_get_phase2_subject_match(s_8021x) + : nm_setting_802_1x_get_subject_match(s_8021x)) { + g_set_error_literal( + error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "(phase2-)subject-match not supported, use domain-match or domain-suffix-match"); + return FALSE; + } + + if (phase2 ? nm_setting_802_1x_get_num_phase2_altsubject_matches(s_8021x) + : nm_setting_802_1x_get_num_altsubject_matches(s_8021x)) { + /* We could convert the "DNS:" entries into a ServerDomainMask but we'd + * have to leave out the "EMAIL:" and "URI:" types or report error. + * The interpretation still wouldn't be exactly the same as in + * wpa_supplicant. + */ + g_set_error_literal( + error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "(phase2-)altsubject-matches not supported, use domain-match or domain-suffix-match"); + return FALSE; + } + + domain_suffix_match = phase2 ? nm_setting_802_1x_get_phase2_domain_suffix_match(s_8021x) + : nm_setting_802_1x_get_domain_suffix_match(s_8021x); + domain_match = phase2 ? nm_setting_802_1x_get_phase2_domain_match(s_8021x) + : nm_setting_802_1x_get_domain_match(s_8021x); + + if (domain_suffix_match || domain_match) { + GString * s = g_string_sized_new(128); + const char *ptr; + const char *end; + + for (ptr = domain_suffix_match; ptr; ptr = *end == ';' ? end + 1 : NULL) { + if (s->len) + g_string_append_c(s, ';'); + end = strchrnul(ptr, ';'); + /* Use *. to get the suffix match effect */ + g_string_append(s, "*."); + g_string_append_len(s, ptr, end - ptr); + } + + /* domain-match can be appended as-is */ + if (domain_match) { + if (s->len) + g_string_append_c(s, ';'); + g_string_append(s, domain_match); + } + + g_key_file_set_string(file, + "Security", + nm_sprintf_buf(setting_buf, "%s%s", iwd_prefix, "ServerDomainMask"), + s->str); + g_string_free(s, TRUE); + } + + return TRUE; +} + +static void +eap_method_name_to_iwd_config(GKeyFile *file, const char *iwd_prefix, const char *method) +{ + char setting_buf[128]; + + g_key_file_set_string(file, + "Security", + nm_sprintf_buf(setting_buf, "%s%s", iwd_prefix, "Method"), + method); +} + +static void +eap_optional_identity_to_iwd_config(GKeyFile *file, const char *iwd_prefix, const char *identity) +{ + char setting_buf[128]; + + /* The identity is optional for some methods where an authenticator may + * in theory not ask for it. For our usage here we treat it as always + * optional because it can be omitted in the config file if the user + * wants IWD to query for it on every connection. + */ + if (identity) { + g_key_file_set_string(file, + "Security", + nm_sprintf_buf(setting_buf, "%s%s", iwd_prefix, "Identity"), + identity); + } else { + g_key_file_set_comment( + file, + "Security", + nm_sprintf_buf(setting_buf, "%s%s", iwd_prefix, "Method"), + "Identity not to be saved, will be queried through the agent if needed", + NULL); + } +} + +static gboolean +eap_optional_password_to_iwd_config(GKeyFile * file, + const char * iwd_prefix, + NMSetting8021x *s_8021x, + GError ** error) +{ + char setting_buf[128]; + const char * password = nm_setting_802_1x_get_password(s_8021x); + NMSettingSecretFlags flags = nm_setting_802_1x_get_password_flags(s_8021x); + + if (!password && nm_setting_802_1x_get_password_raw(s_8021x)) { + /* IWD doesn't support passwords that can't be encoded in the config + * file, i.e. containing NUL characters. Those that don't have NULs + * could in theory be written to the config file but GKeyFile may not + * like that if they're no UTF-8, and the password-raw property is + * not written by nm-connection-editor anyway. + */ + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "Non-UTF-8 passwords are not supported, if the password is UTF-8 set " + "the \"password\" property"); + return FALSE; + } + if (!password || NM_FLAGS_ANY(flags, SECRETS_DONT_STORE_FLAGS)) { + return g_key_file_set_comment(file, + "Security", + nm_sprintf_buf(setting_buf, "%s%s", iwd_prefix, "Method"), + "Password not to be saved, will be queried through the agent", + error); + } else { + g_key_file_set_string(file, + "Security", + nm_sprintf_buf(setting_buf, "%s%s", iwd_prefix, "Password"), + password); + return TRUE; + } +} + +static void +eap_phase1_identity_to_iwd_config(GKeyFile *file, const char *iwd_prefix, NMSetting8021x *s_8021x) +{ + const char *phase1_identity = nm_setting_802_1x_get_anonymous_identity(s_8021x); + + if (!phase1_identity) { + phase1_identity = nm_setting_802_1x_get_identity(s_8021x); + + if (phase1_identity) { + nm_log_info(LOGD_WIFI, + "IWD network config will send the same EAP Identity string in " + "plaintext in phase 1 as in phase 2 (encrypted) to mimic legacy " + "behavior, set [%s].%s=anonymous to prevent exposing the value", + NM_SETTING_802_1X_SETTING_NAME, + NM_SETTING_802_1X_ANONYMOUS_IDENTITY); + } + } + + eap_optional_identity_to_iwd_config(file, iwd_prefix, phase1_identity); +} + +static gboolean +eap_method_config_to_iwd_config(GKeyFile * file, + NMSetting8021x *s_8021x, + gboolean phase2, + const char * method, + const char * iwd_prefix, + GError ** error) +{ + char prefix_buf[128]; + + if (nm_streq0(method, "tls")) { + eap_method_name_to_iwd_config(file, iwd_prefix, "TLS"); + eap_optional_identity_to_iwd_config(file, + iwd_prefix, + nm_setting_802_1x_get_identity(s_8021x)); + + return eap_certs_to_iwd_config(file, + s_8021x, + phase2, + nm_sprintf_buf(prefix_buf, "%s%s", iwd_prefix, "TLS-"), + error); + } else if (nm_streq0(method, "ttls") && !phase2) { + const char *noneap_method = nm_setting_802_1x_get_phase2_auth(s_8021x); + + eap_method_name_to_iwd_config(file, iwd_prefix, "TTLS"); + eap_phase1_identity_to_iwd_config(file, iwd_prefix, s_8021x); + + if (!eap_certs_to_iwd_config(file, + s_8021x, + phase2, + nm_sprintf_buf(prefix_buf, "%s%s", iwd_prefix, "TTLS-"), + error)) + return FALSE; + + nm_sprintf_buf(prefix_buf, "%s%s", iwd_prefix, "TTLS-Phase2-"); + + if (nm_setting_802_1x_get_phase2_autheap(s_8021x)) { + if (noneap_method) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "Only one TTLS phase 2 method can be set"); + return FALSE; + } + return eap_method_config_to_iwd_config(file, + s_8021x, + TRUE, + nm_setting_802_1x_get_phase2_autheap(s_8021x), + prefix_buf, + error); + } + + if (NM_IN_STRSET(noneap_method, "chap", "mschap", "mschapv2", "pap")) { + const char *iwd_method; + + if (nm_streq0(noneap_method, "chap")) { + iwd_method = "Tunneled-CHAP"; + } else if (nm_streq0(noneap_method, "mschap")) { + iwd_method = "Tunneled-MSCHAP"; + } else if (nm_streq0(noneap_method, "mschapv2")) { + iwd_method = "Tunneled-MSCHAPv2"; + } else { + iwd_method = "Tunneled-PAP"; + } + + eap_method_name_to_iwd_config(file, prefix_buf, iwd_method); + eap_optional_identity_to_iwd_config(file, + prefix_buf, + nm_setting_802_1x_get_identity(s_8021x)); + return eap_optional_password_to_iwd_config(file, prefix_buf, s_8021x, error); + } + + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "Unsupported TTLS non-EAP inner method"); + return FALSE; + } else if (nm_streq0(method, "peap") && !phase2) { + eap_method_name_to_iwd_config(file, iwd_prefix, "PEAP"); + eap_phase1_identity_to_iwd_config(file, iwd_prefix, s_8021x); + + if (!eap_certs_to_iwd_config(file, + s_8021x, + phase2, + nm_sprintf_buf(prefix_buf, "%s%s", iwd_prefix, "PEAP-"), + error)) + return FALSE; + + if (nm_setting_802_1x_get_phase1_peapver(s_8021x) + || nm_setting_802_1x_get_phase1_peaplabel(s_8021x)) + nm_log_info(LOGD_WIFI, + "IWD network config will not honour the PEAP version and label properties " + "in the 802.1x setting (unsupported)"); + + if (!nm_setting_802_1x_get_phase2_auth(s_8021x)) { + /* Apparently PEAP can be used without a phase 2 but this is not + * supported by either NM or IWD. + */ + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "PEAP without an inner method is unsupported"); + return FALSE; + } + + return eap_method_config_to_iwd_config( + file, + s_8021x, + TRUE, + nm_setting_802_1x_get_phase2_auth(s_8021x), + nm_sprintf_buf(prefix_buf, "%s%s", iwd_prefix, "PEAP-Phase2-"), + error); + } else if (nm_streq0(method, "md5") && phase2) { + eap_method_name_to_iwd_config(file, iwd_prefix, "MD5"); + eap_optional_identity_to_iwd_config(file, + iwd_prefix, + nm_setting_802_1x_get_identity(s_8021x)); + return eap_optional_password_to_iwd_config(file, iwd_prefix, s_8021x, error); + } else if (nm_streq0(method, "gtc") && phase2) { + eap_method_name_to_iwd_config(file, iwd_prefix, "GTC"); + eap_optional_identity_to_iwd_config(file, + iwd_prefix, + nm_setting_802_1x_get_identity(s_8021x)); + return eap_optional_password_to_iwd_config(file, iwd_prefix, s_8021x, error); + } else if (nm_streq0(method, "pwd")) { + eap_method_name_to_iwd_config(file, iwd_prefix, "PWD"); + eap_optional_identity_to_iwd_config(file, + iwd_prefix, + nm_setting_802_1x_get_identity(s_8021x)); + return eap_optional_password_to_iwd_config(file, iwd_prefix, s_8021x, error); + } else if (nm_streq0(method, "mschapv2")) { + eap_method_name_to_iwd_config(file, iwd_prefix, "MSCHAPV2"); + eap_optional_identity_to_iwd_config(file, + iwd_prefix, + nm_setting_802_1x_get_identity(s_8021x)); + /* In this case we can support password-raw but would have to + * MD4-hash it and set as Password-Hash + */ + return eap_optional_password_to_iwd_config(file, iwd_prefix, s_8021x, error); + } else if (nm_streq0(method, "external")) { + /* This may be a connection created by NMIwdManager in whch case there + * may be no need to be convert it back to the IWD format. Ideally we + * would still rewrite the other sections/groups in the IWD settings + * file and preserve the [Security] group -- TODO. Possibly this should + * also not be reported as an error. + */ + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "Connection contains no EAP method configuration"); + return FALSE; + } else { + /* Some methods are only allowed in phase 1 or only phase 2. + * OTP, LEAP and FAST are not supported by IWD at all. + */ + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + phase2 ? "Unsupported phase 2 EAP method" + : "Unsupported phase 1 EAP method"); + return FALSE; + } + + return TRUE; +} + +static gboolean +eap_setting_to_iwd_config(GKeyFile *file, NMSetting8021x *s_8021x, GError **error) +{ + const char *method; + + if (!s_8021x || nm_setting_802_1x_get_num_eap_methods(s_8021x) == 0) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "The 802.1x setting is missing or no EAP method set"); + return FALSE; + } + + if (!nm_setting_verify(NM_SETTING(s_8021x), NULL, error)) + return FALSE; + + method = nm_setting_802_1x_get_eap_method(s_8021x, 0); + + if (nm_setting_802_1x_get_num_eap_methods(s_8021x) > 1) + nm_log_info(LOGD_WIFI, + "IWD network config will only contain the first EAP method: %s", + method); + + if (nm_setting_802_1x_get_phase1_auth_flags(s_8021x)) + nm_log_info(LOGD_WIFI, + "IWD network config will not honour the TLSv1.x-disable flags in the 802.1x " + "setting (unsupported)"); + + if (nm_setting_802_1x_get_auth_timeout(s_8021x)) + nm_log_info(LOGD_WIFI, + "IWD network config will not honour the auth-timeout property in the 802.1x " + "setting (unsupported)"); + + return eap_method_config_to_iwd_config(file, s_8021x, FALSE, method, "EAP-", error); +} + +static gboolean +ip4_config_to_iwd_config(GKeyFile *file, NMSettingIPConfig *s_ip, GError **error) +{ + guint num; + struct in_addr ip; + + /* These settings are not acutally used unless global + * [General].EnableNetworkConfiguration is true, which we don't support. + * We add them for sake of completness, although many NMSettingIPConfig + * configurations can't be mapped to IWD configs and we simply ignore + * them. If they were to be used we'd need to add a few warnings. + */ + + if (!s_ip) + return TRUE; + + num = nm_setting_ip_config_get_num_dns(s_ip); + if (num) { + nm_auto_free_gstring GString *s = g_string_sized_new(128); + guint i; + + for (i = 0; i < num; i++) { + if (s->len) + g_string_append_c(s, ' '); + g_string_append(s, nm_setting_ip_config_get_dns(s_ip, i)); + } + /* It doesn't matter whether we add the DNS under [IPv4] or [IPv6] + * except that with method=auto the list will override the + * DNS addresses received over the DHCP version corresponing to + * v4 or v6. + * Note ignore-auto-dns=false isn't supported, this list always + * overrides the DHCP DNSes. + */ + g_key_file_set_string(file, "IPv4", "DNS", s->str); + } + + if (!nm_streq0(nm_setting_ip_config_get_method(s_ip), NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) + return TRUE; + + num = nm_setting_ip_config_get_num_addresses(s_ip); + if (num) { + NMIPAddress *addr = nm_setting_ip_config_get_address(s_ip, 0); + guint prefix = nm_ip_address_get_prefix(addr); + in_addr_t netmask = _nm_utils_ip4_prefix_to_netmask(prefix); + char buf[INET_ADDRSTRLEN]; + + nm_ip_address_get_address_binary(addr, &ip); + g_key_file_set_string(file, "IPv4", "Address", nm_ip_address_get_address(addr)); + g_key_file_set_string(file, "IPv4", "Netmask", _nm_utils_inet4_ntop(netmask, buf)); + } else { + inet_pton(AF_INET, "10.42.0.100", &ip); + g_key_file_set_string(file, "IPv4", "Address", "10.42.0.100"); + } + + if (nm_setting_ip_config_get_gateway(s_ip)) { + g_key_file_set_string(file, "IPv4", "Gateway", nm_setting_ip_config_get_gateway(s_ip)); + } else { + uint32_t val; + char buf[INET_ADDRSTRLEN]; + + /* IWD won't enable static IP unless both Address and Gateway are + * set so generate a gateway address if not known. + */ + val = (ntohl(ip.s_addr) & 0xfffffff0) + 1; + if (val == ntohl(ip.s_addr)) + val += 1; + g_key_file_set_string(file, "IPv4", "Gateway", _nm_utils_inet4_ntop(htonl(val), buf)); + } + + return TRUE; +} + +static gboolean +ip6_config_to_iwd_config(GKeyFile *file, NMSettingIPConfig *s_ip, GError **error) +{ + guint num; + NMIPAddress *addr; + char buf[INET6_ADDRSTRLEN + 10]; + + if (!s_ip) + return TRUE; + + num = nm_setting_ip_config_get_num_dns(s_ip); + if (num) { + nm_auto_free_gstring GString *s = g_string_sized_new(128); + guint i; + + for (i = 0; i < num; i++) { + if (s->len) + g_string_append_c(s, ' '); + g_string_append(s, nm_setting_ip_config_get_dns(s_ip, i)); + } + g_key_file_set_string(file, "IPv6", "DNS", s->str); + } + + if (!NM_IN_STRSET(nm_setting_ip_config_get_method(s_ip), + NM_SETTING_IP6_CONFIG_METHOD_AUTO, + NM_SETTING_IP6_CONFIG_METHOD_DHCP, + NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) + return TRUE; + + g_key_file_set_boolean(file, "IPv6", "Enabled", TRUE); + + if (!nm_streq0(nm_setting_ip_config_get_method(s_ip), NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) + return TRUE; + + if (!nm_setting_ip_config_get_num_addresses(s_ip)) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "IP address required for IPv6 manual config"); + return FALSE; + } + + addr = nm_setting_ip_config_get_address(s_ip, 0); + g_key_file_set_string(file, + "IPv6", + "Address", + nm_sprintf_buf(buf, + "%s/%u", + nm_ip_address_get_address(addr), + nm_ip_address_get_prefix(addr))); + if (nm_setting_ip_config_get_gateway(s_ip)) + g_key_file_set_string(file, "IPv6", "Gateway", nm_setting_ip_config_get_gateway(s_ip)); + return TRUE; +} + +GKeyFile * +nm_wifi_utils_connection_to_iwd_config(NMConnection *connection, + char ** out_filename, + GError ** error) +{ + NMSettingConnection * s_conn = nm_connection_get_setting_connection(connection); + NMSettingWireless * s_wifi = nm_connection_get_setting_wireless(connection); + GBytes * ssid; + const guint8 * ssid_data; + gsize ssid_len; + NMIwdNetworkSecurity security; + const char * cloned_mac_addr; + gs_free char * comment = NULL; + nm_auto_unref_keyfile GKeyFile *file = NULL; + + if (!s_conn || !s_wifi + || !nm_streq(nm_setting_connection_get_connection_type(s_conn), + NM_SETTING_WIRELESS_SETTING_NAME)) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "Connection and/or wireless settings are missing"); + return NULL; + } + + if (!NM_IN_STRSET(nm_setting_wireless_get_mode(s_wifi), NULL, NM_SETTING_WIRELESS_MODE_INFRA)) { + g_set_error_literal( + error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "Non-infrastructure-mode connections don't have IWD profiles (or aren't supported)"); + return NULL; + } + + ssid = nm_setting_wireless_get_ssid(s_wifi); + ssid_data = ssid ? g_bytes_get_data(ssid, &ssid_len) : NULL; + if (!ssid_data || ssid_len <= 0 || ssid_len > NM_IW_ESSID_MAX_SIZE + || !g_utf8_validate((const char *) ssid_data, ssid_len, NULL)) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "Empty or non-UTF-8 SSIDs not supported by IWD"); + return NULL; + } + + if (!nm_wifi_connection_get_iwd_ssid_and_security(connection, NULL, &security)) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "Connection's security type unrecognised"); + return NULL; + } + + file = g_key_file_new(); + + comment = g_strdup_printf(" Auto-generated from NetworkManager connection \"%s\"\n" + " Changes to that connection overwrite this file when " + "enabled by NM's [%s].%s value", + nm_setting_connection_get_id(s_conn), + NM_CONFIG_KEYFILE_GROUP_MAIN, + NM_CONFIG_KEYFILE_KEY_MAIN_IWD_CONFIG_PATH); + g_key_file_set_comment(file, NULL, NULL, comment, NULL); + + if (!nm_setting_connection_get_autoconnect(s_conn)) + g_key_file_set_boolean(file, "Settings", "AutoConnect", FALSE); + + if (nm_setting_wireless_get_hidden(s_wifi)) + g_key_file_set_boolean(file, "Settings", "Hidden", TRUE); + + /* Only effective if IWD's global [General].AddressRandomization is set + * to "network". "random" maps to [Settings].AlwaysRandomizeAddress=true, + * "stable" is the default, specific address maps to + * [Settings].AddressOverride set to that address. "permanent" is not + * supported and "preserve" can only be achieved using the global + * [General].AddressRandomization=disabled setting. We don't print + * warnings when we can't map the value here because we don't know what + * IWD's [General].AddressRandomization is set to. + */ + cloned_mac_addr = nm_setting_wireless_get_cloned_mac_address(s_wifi); + if (nm_streq0(cloned_mac_addr, NM_CLONED_MAC_RANDOM)) + g_key_file_set_boolean(file, "Settings", "AlwaysRandomizeAddress", TRUE); + else if (cloned_mac_addr && nm_utils_hwaddr_valid(cloned_mac_addr, ETH_ALEN)) + g_key_file_set_string(file, "Settings", "AddressOverride", cloned_mac_addr); + + if (!ip4_config_to_iwd_config( + file, + NM_SETTING_IP_CONFIG(nm_connection_get_setting_ip4_config(connection)), + error)) + return NULL; + + if (!ip6_config_to_iwd_config( + file, + NM_SETTING_IP_CONFIG(nm_connection_get_setting_ip6_config(connection)), + error)) + return NULL; + + switch (security) { + case NM_IWD_NETWORK_SECURITY_OPEN: + break; + case NM_IWD_NETWORK_SECURITY_PSK: + if (!psk_setting_to_iwd_config(file, + nm_connection_get_setting_wireless_security(connection), + error)) + return NULL; + + break; + case NM_IWD_NETWORK_SECURITY_8021X: + if (!eap_setting_to_iwd_config(file, nm_connection_get_setting_802_1x(connection), error)) + return NULL; + + break; + default: + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + "Connection security type is not supported"); + return NULL; + } + + if (out_filename) + *out_filename = + nm_wifi_utils_get_iwd_config_filename((const char *) ssid_data, ssid_len, security); + + return g_steal_pointer(&file); +} diff --git a/src/core/devices/wifi/nm-wifi-utils.h b/src/core/devices/wifi/nm-wifi-utils.h index 474bea41..2664c03e 100644 --- a/src/core/devices/wifi/nm-wifi-utils.h +++ b/src/core/devices/wifi/nm-wifi-utils.h @@ -11,6 +11,7 @@ #include "nm-setting-wireless.h" #include "nm-setting-wireless-security.h" #include "nm-setting-8021x.h" +#include "libnm-base/nm-base.h" typedef enum { NM_IWD_NETWORK_SECURITY_OPEN, @@ -21,7 +22,7 @@ typedef enum { gboolean nm_wifi_utils_complete_connection(GBytes * ssid, const char * bssid, - NM80211Mode mode, + _NM80211Mode mode, guint32 ap_freq, guint32 flags, guint32 wpa_flags, @@ -35,5 +36,11 @@ gboolean nm_wifi_utils_is_manf_default_ssid(GBytes *ssid); gboolean nm_wifi_connection_get_iwd_ssid_and_security(NMConnection * connection, char ** ssid, NMIwdNetworkSecurity *security); +char * nm_wifi_utils_get_iwd_config_filename(const char * ssid, + gssize ssid_len, + NMIwdNetworkSecurity security); + +GKeyFile * +nm_wifi_utils_connection_to_iwd_config(NMConnection *conn, char **out_filename, GError **error); #endif /* __NM_WIFI_UTILS_H__ */ diff --git a/src/core/devices/wifi/tests/test-devices-wifi.c b/src/core/devices/wifi/tests/test-devices-wifi.c index bc0ba126..dc278c94 100644 --- a/src/core/devices/wifi/tests/test-devices-wifi.c +++ b/src/core/devices/wifi/tests/test-devices-wifi.c @@ -7,7 +7,7 @@ #include "devices/wifi/nm-wifi-utils.h" #include "devices/wifi/nm-device-wifi.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-test-utils-core.h" @@ -49,7 +49,7 @@ static gboolean complete_connection(const char * ssid, const char * bssid, - NM80211Mode mode, + _NM80211Mode mode, guint32 flags, guint32 wpa_flags, guint32 rsn_flags, @@ -197,7 +197,7 @@ fill_8021x(NMConnection *connection, const KeyData items[]) } static NMConnection * -create_basic(const char *ssid, const char *bssid, NM80211Mode mode) +create_basic(const char *ssid, const char *bssid, _NM80211Mode mode) { NMConnection * connection; NMSettingWireless *s_wifi = NULL; @@ -217,9 +217,9 @@ create_basic(const char *ssid, const char *bssid, NM80211Mode mode) if (bssid) g_object_set(G_OBJECT(s_wifi), NM_SETTING_WIRELESS_BSSID, bssid, NULL); - if (mode == NM_802_11_MODE_INFRA) + if (mode == _NM_802_11_MODE_INFRA) g_object_set(G_OBJECT(s_wifi), NM_SETTING_WIRELESS_MODE, "infrastructure", NULL); - else if (mode == NM_802_11_MODE_ADHOC) + else if (mode == _NM_802_11_MODE_ADHOC) g_object_set(G_OBJECT(s_wifi), NM_SETTING_WIRELESS_MODE, "adhoc", NULL); else g_assert_not_reached(); @@ -241,14 +241,14 @@ test_lock_bssid(void) src = nm_simple_connection_new(); success = complete_connection(ssid, bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_NONE, NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, TRUE, src, &error); - expected = create_basic(ssid, bssid, NM_802_11_MODE_INFRA); + expected = create_basic(ssid, bssid, _NM_802_11_MODE_INFRA); COMPARE(src, expected, success, error, 0, 0); g_object_unref(src); @@ -273,14 +273,14 @@ test_open_ap_empty_connection(void) src = nm_simple_connection_new(); success = complete_connection(ssid, bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_NONE, NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, FALSE, src, &error); - expected = create_basic(ssid, NULL, NM_802_11_MODE_INFRA); + expected = create_basic(ssid, NULL, _NM_802_11_MODE_INFRA); COMPARE(src, expected, success, error, 0, 0); g_object_unref(src); @@ -311,7 +311,7 @@ test_open_ap_leap_connection_1(gconstpointer add_wifi) success = complete_connection("blahblah", bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_NONE, NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, @@ -345,7 +345,7 @@ test_open_ap_leap_connection_2(void) success = complete_connection("blahblah", bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_NONE, NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, @@ -383,7 +383,7 @@ test_open_ap_wep_connection(gconstpointer add_wifi) fill_wsec(src, src_wsec); success = complete_connection("blahblah", bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_NONE, NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, @@ -427,7 +427,7 @@ test_ap_wpa_psk_connection_base(const char * key_mgmt, fill_wsec(src, both_wsec); success = complete_connection(ssid, bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, flags, wpa_flags, rsn_flags, @@ -553,7 +553,7 @@ test_ap_wpa_eap_connection_base(const char *key_mgmt, fill_8021x(src, src_empty); success = complete_connection("blahblah", bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, flags, wpa_flags, rsn_flags, @@ -751,7 +751,7 @@ test_priv_ap_empty_connection(void) src = nm_simple_connection_new(); success = complete_connection(ssid, bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, @@ -760,7 +760,7 @@ test_priv_ap_empty_connection(void) &error); /* Static WEP connection expected */ - expected = create_basic(ssid, NULL, NM_802_11_MODE_INFRA); + expected = create_basic(ssid, NULL, _NM_802_11_MODE_INFRA); fill_wsec(expected, exp_wsec); COMPARE(src, expected, success, error, 0, 0); @@ -798,7 +798,7 @@ test_priv_ap_leap_connection_1(gconstpointer add_wifi) fill_wsec(src, src_wsec); success = complete_connection(ssid, bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, @@ -809,7 +809,7 @@ test_priv_ap_leap_connection_1(gconstpointer add_wifi) * there's no way to determine from the AP's beacon whether it's static WEP, * dynamic WEP, or LEAP. */ - expected = create_basic(ssid, NULL, NM_802_11_MODE_INFRA); + expected = create_basic(ssid, NULL, _NM_802_11_MODE_INFRA); fill_wsec(expected, exp_wsec); COMPARE(src, expected, success, error, 0, 0); @@ -840,7 +840,7 @@ test_priv_ap_leap_connection_2(void) fill_wsec(src, src_wsec); success = complete_connection("blahblah", bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, @@ -885,7 +885,7 @@ test_priv_ap_dynamic_wep_1(void) fill_8021x(src, both_8021x); success = complete_connection(ssid, bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, @@ -894,7 +894,7 @@ test_priv_ap_dynamic_wep_1(void) &error); /* We expect a completed Dynamic WEP connection */ - expected = create_basic(ssid, NULL, NM_802_11_MODE_INFRA); + expected = create_basic(ssid, NULL, _NM_802_11_MODE_INFRA); fill_wsec(expected, exp_wsec); fill_8021x(expected, both_8021x); COMPARE(src, expected, success, error, 0, 0); @@ -933,7 +933,7 @@ test_priv_ap_dynamic_wep_2(void) fill_8021x(src, both_8021x); success = complete_connection(ssid, bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, @@ -942,7 +942,7 @@ test_priv_ap_dynamic_wep_2(void) &error); /* We expect a completed Dynamic WEP connection */ - expected = create_basic(ssid, NULL, NM_802_11_MODE_INFRA); + expected = create_basic(ssid, NULL, _NM_802_11_MODE_INFRA); fill_wsec(expected, exp_wsec); fill_8021x(expected, both_8021x); COMPARE(src, expected, success, error, 0, 0); @@ -976,7 +976,7 @@ test_priv_ap_dynamic_wep_3(void) fill_8021x(src, src_8021x); success = complete_connection("blahblah", bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, NM_802_11_AP_SEC_NONE, NM_802_11_AP_SEC_NONE, @@ -1102,7 +1102,7 @@ test_wpa_ap_empty_connection(gconstpointer data) src = nm_simple_connection_new(); success = complete_connection(ssid, bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, wpa_flags_for_idx(idx), rsn_flags_for_idx(idx), @@ -1111,7 +1111,7 @@ test_wpa_ap_empty_connection(gconstpointer data) &error); /* WPA connection expected */ - expected = create_basic(ssid, NULL, NM_802_11_MODE_INFRA); + expected = create_basic(ssid, NULL, _NM_802_11_MODE_INFRA); fill_wsec(expected, exp_wsec); COMPARE(src, expected, success, error, 0, 0); @@ -1144,7 +1144,7 @@ test_wpa_ap_leap_connection_1(gconstpointer data) fill_wsec(src, src_wsec); success = complete_connection(ssid, bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, wpa_flags_for_idx(idx), rsn_flags_for_idx(idx), @@ -1180,7 +1180,7 @@ test_wpa_ap_leap_connection_2(gconstpointer data) fill_wsec(src, src_wsec); success = complete_connection("blahblah", bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, wpa_flags_for_idx(idx), rsn_flags_for_idx(idx), @@ -1214,7 +1214,7 @@ test_wpa_ap_dynamic_wep_connection(gconstpointer data) fill_wsec(src, src_wsec); success = complete_connection("blahblah", bssid, - NM_802_11_MODE_INFRA, + _NM_802_11_MODE_INFRA, NM_802_11_AP_FLAGS_PRIVACY, wpa_flags_for_idx(idx), rsn_flags_for_idx(idx), diff --git a/src/core/devices/wwan/meson.build b/src/core/devices/wwan/meson.build index 87af0429..37ef738c 100644 --- a/src/core/devices/wwan/meson.build +++ b/src/core/devices/wwan/meson.build @@ -17,7 +17,6 @@ libnm_wwan = shared_module( libsystemd_dep, mm_glib_dep, ], - c_args: daemon_c_flags, link_args: '-Wl,--version-script,@0@'.format(linker_script), link_depends: linker_script, install: true, @@ -51,7 +50,6 @@ libnm_device_plugin_wwan = shared_module( libsystemd_dep, mm_glib_dep, ], - c_args: daemon_c_flags, link_with: libnm_wwan, link_args: ldflags_linker_script_devices, link_depends: linker_script_devices, diff --git a/src/core/devices/wwan/nm-device-modem.c b/src/core/devices/wwan/nm-device-modem.c index 3ea89d2c..a8d2a161 100644 --- a/src/core/devices/wwan/nm-device-modem.c +++ b/src/core/devices/wwan/nm-device-modem.c @@ -14,7 +14,7 @@ #include "settings/nm-settings-connection.h" #include "nm-modem-broadband.h" #include "NetworkManagerUtils.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #define _NMLOG_DEVICE_TYPE NMDeviceModem #include "devices/nm-device-logging.h" @@ -357,7 +357,6 @@ modem_state_cb(NMModem *modem, int new_state_i, int old_state_i, gpointer user_d nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER); - return; } if (new_state > NM_MODEM_STATE_LOCKED && old_state == NM_MODEM_STATE_LOCKED) { @@ -856,14 +855,13 @@ dispose(GObject *object) static const NMDBusInterfaceInfoExtended interface_info_device_modem = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DEVICE_MODEM, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("ModemCapabilities", - "u", - NM_DEVICE_MODEM_CAPABILITIES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("CurrentCapabilities", - "u", - NM_DEVICE_MODEM_CURRENT_CAPABILITIES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("ModemCapabilities", + "u", + NM_DEVICE_MODEM_CAPABILITIES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("CurrentCapabilities", + "u", + NM_DEVICE_MODEM_CURRENT_CAPABILITIES), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("DeviceId", "s", NM_DEVICE_MODEM_DEVICE_ID), @@ -871,7 +869,6 @@ static const NMDBusInterfaceInfoExtended interface_info_device_modem = { "s", NM_DEVICE_MODEM_OPERATOR_CODE), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Apn", "s", NM_DEVICE_MODEM_APN), ), ), - .legacy_property_changed = TRUE, }; static void diff --git a/src/core/devices/wwan/nm-modem-broadband.c b/src/core/devices/wwan/nm-modem-broadband.c index ca028804..0872a8a1 100644 --- a/src/core/devices/wwan/nm-modem-broadband.c +++ b/src/core/devices/wwan/nm-modem-broadband.c @@ -11,10 +11,10 @@ #include #include -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "NetworkManagerUtils.h" #include "devices/nm-device-private.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" @@ -369,10 +369,10 @@ static void connect_ready(MMModemSimple *simple_iface, GAsyncResult *res, NMModemBroadband *self) { ConnectContext *ctx; - GError * error = NULL; - NMModemIPMethod ip4_method = NM_MODEM_IP_METHOD_UNKNOWN; - NMModemIPMethod ip6_method = NM_MODEM_IP_METHOD_UNKNOWN; - MMBearer * bearer; + GError * error = NULL; + NMModemIPMethod ip4_method = NM_MODEM_IP_METHOD_UNKNOWN; + NMModemIPMethod ip6_method = NM_MODEM_IP_METHOD_UNKNOWN; + gs_unref_object MMBearer *bearer = NULL; bearer = mm_modem_simple_connect_finish(simple_iface, res, &error); @@ -386,7 +386,7 @@ connect_ready(MMModemSimple *simple_iface, GAsyncResult *res, NMModemBroadband * if (!ctx) return; - self->_priv.bearer = bearer; + self->_priv.bearer = g_steal_pointer(&bearer); if (!self->_priv.bearer) { if (g_error_matches(error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN) diff --git a/src/core/devices/wwan/nm-modem-manager.c b/src/core/devices/wwan/nm-modem-manager.c index 598c6898..4fb9a378 100644 --- a/src/core/devices/wwan/nm-modem-manager.c +++ b/src/core/devices/wwan/nm-modem-manager.c @@ -17,7 +17,7 @@ #define sd_booted() FALSE #endif -#include "nm-std-aux/nm-dbus-compat.h" +#include "libnm-std-aux/nm-dbus-compat.h" #include "nm-modem.h" #include "nm-modem-broadband.h" diff --git a/src/core/devices/wwan/nm-modem-ofono.c b/src/core/devices/wwan/nm-modem-ofono.c index 21734cee..78ad7b68 100644 --- a/src/core/devices/wwan/nm-modem-ofono.c +++ b/src/core/devices/wwan/nm-modem-ofono.c @@ -7,10 +7,10 @@ #include "nm-modem-ofono.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "devices/nm-device-private.h" #include "nm-modem.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-ip4-config.h" #define VARIANT_IS_OF_TYPE_BOOLEAN(v) \ @@ -316,10 +316,9 @@ handle_sim_property(GDBusProxy *proxy, const char *property, GVariant *v, gpoint static void sim_property_changed(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data) { - GVariant *v_child = g_variant_get_child_value(v, 0); + gs_unref_variant GVariant *v_child = g_variant_get_child_value(v, 0); handle_sim_property(proxy, property, v_child, user_data); - g_variant_unref(v_child); } static void @@ -330,7 +329,7 @@ sim_get_properties_done(GObject *source, GAsyncResult *result, gpointer user_dat gs_free_error GError *error = NULL; gs_unref_variant GVariant *v_properties = NULL; gs_unref_variant GVariant *v_dict = NULL; - GVariant * v; + gs_unref_variant GVariant *v = NULL; GVariantIter i; const char * property; @@ -370,9 +369,8 @@ sim_get_properties_done(GObject *source, GAsyncResult *result, gpointer user_dat */ g_variant_iter_init(&i, v_dict); - while (g_variant_iter_next(&i, "{&sv}", &property, &v)) { + while (g_variant_iter_loop(&i, "{&sv}", &property, &v)) { handle_sim_property(NULL, property, v, self); - g_variant_unref(v); } } @@ -477,10 +475,9 @@ handle_connman_property(GDBusProxy *proxy, const char *property, GVariant *v, gp static void connman_property_changed(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data) { - GVariant *v_child = g_variant_get_child_value(v, 0); + gs_unref_variant GVariant *v_child = g_variant_get_child_value(v, 0); handle_connman_property(proxy, property, v_child, user_data); - g_variant_unref(v_child); } static void @@ -491,7 +488,7 @@ connman_get_properties_done(GObject *source, GAsyncResult *result, gpointer user gs_free_error GError *error = NULL; gs_unref_variant GVariant *v_properties = NULL; gs_unref_variant GVariant *v_dict = NULL; - GVariant * v; + gs_unref_variant GVariant *v = NULL; GVariantIter i; const char * property; @@ -523,9 +520,8 @@ connman_get_properties_done(GObject *source, GAsyncResult *result, gpointer user */ g_variant_iter_init(&i, v_dict); - while (g_variant_iter_next(&i, "{&sv}", &property, &v)) { + while (g_variant_iter_loop(&i, "{&sv}", &property, &v)) { handle_connman_property(NULL, property, v, self); - g_variant_unref(v); } } @@ -700,9 +696,8 @@ modem_get_properties_done(GObject *source, GAsyncResult *result, gpointer user_d */ g_variant_iter_init(&i, v_dict); - while (g_variant_iter_next(&i, "{&sv}", &property, &v)) { + while (g_variant_iter_loop(&i, "{&sv}", &property, &v)) { handle_modem_property(NULL, property, v, self); - g_variant_unref(v); } } @@ -726,35 +721,30 @@ stage1_prepare_done(GObject *source, GAsyncResult *result, gpointer user_data) nm_clear_pointer(&priv->connect_properties, g_hash_table_destroy); if (error) { - _LOGW("connection failed: %s", error->message); - - nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, NM_DEVICE_STATE_REASON_MODEM_BUSY); - /* - * FIXME: add code to check for InProgress so that the - * connection doesn't continue to try and activate, - * leading to the connection being disabled, and a 5m - * timeout... - */ + if (!g_strstr_len(error->message, + NM_STRLEN(OFONO_ERROR_IN_PROGRESS), + OFONO_ERROR_IN_PROGRESS)) { + nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, NM_DEVICE_STATE_REASON_MODEM_BUSY); + } } } static void -context_property_changed(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data) +handle_settings(GVariant *v_dict, gpointer user_data) { NMModemOfono * self = NM_MODEM_OFONO(user_data); NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); NMPlatformIP4Address addr; - gboolean ret = FALSE; - gs_unref_variant GVariant *v_dict = NULL; - const char * interface; - const char * s; - const char ** array, **iter; - guint32 address_network, gateway_network; - guint32 ip4_route_table, ip4_route_metric; - int ifindex; - GError * error = NULL; + gboolean ret = FALSE; + const char * interface; + const char * s; + const char ** array, **iter; + guint32 address_network, gateway_network; + guint32 ip4_route_table, ip4_route_metric; + int ifindex; + GError * error = NULL; - _LOGD("PropertyChanged: %s", property); + //_LOGD("PropertyChanged: %s", property); /* * TODO: might be a good idea and re-factor this to mimic bluez-device, @@ -762,15 +752,6 @@ context_property_changed(GDBusProxy *proxy, const char *property, GVariant *v, g * handle the action. */ - if (g_strcmp0(property, "Settings") != 0) - return; - - v_dict = g_variant_get_child_value(v, 0); - if (!v_dict) { - _LOGW("error getting IPv4 Settings: no v_dict"); - goto out; - } - _LOGI("IPv4 static Settings:"); if (!g_variant_lookup(v_dict, "Interface", "&s", &interface)) { @@ -909,6 +890,28 @@ out: } } +static void +context_property_changed(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data) +{ + NMModemOfono * self = NM_MODEM_OFONO(user_data); + gs_unref_variant GVariant *v_dict = NULL; + + _LOGD("PropertyChanged: %s", property); + + if (g_strcmp0(property, "Settings") != 0) + return; + + v_dict = g_variant_get_child_value(v, 0); + if (!v_dict) { + _LOGW("ofono: (%s): error getting IPv4 Settings", nm_modem_get_uid(NM_MODEM(self))); + return; + } + + g_assert(g_variant_is_of_type(v_dict, G_VARIANT_TYPE_VARDICT)); + + handle_settings(v_dict, user_data); +} + static NMActStageReturn static_stage3_ip4_config_start(NMModem * modem, NMActRequest * req, @@ -935,6 +938,72 @@ static_stage3_ip4_config_start(NMModem * modem, return NM_ACT_STAGE_RETURN_POSTPONE; } +static void +context_properties_cb(GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +{ + NMModemOfono * self; + NMModemOfonoPrivate *priv; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *properties = NULL; + gs_unref_variant GVariant *settings = NULL; + gs_unref_variant GVariant *v_dict = NULL; + gboolean active; + + self = NM_MODEM_OFONO(user_data); + priv = NM_MODEM_OFONO_GET_PRIVATE(self); + + properties = g_dbus_proxy_call_finish(proxy, result, &error); + + if (!properties) { + _LOGW("ofono: connection failed: no context properties returned %s", error->message); + g_clear_error(&error); + goto error; + } + + v_dict = g_variant_get_child_value(properties, 0); + if (!v_dict || !g_variant_is_of_type(v_dict, G_VARIANT_TYPE_VARDICT)) { + _LOGW("ofono: connection failed; could not read connection properties"); + goto error; + } + + if (!g_variant_lookup(v_dict, "Active", "b", &active)) { + _LOGW("ofono: connection failed; can not read 'Active' property"); + goto error; + } + + /* Watch for custom ofono PropertyChanged signals */ + _nm_dbus_signal_connect(priv->context_proxy, + "PropertyChanged", + G_VARIANT_TYPE("(sv)"), + G_CALLBACK(context_property_changed), + self); + + if (active) { + _LOGD("ofono: connection is already Active"); + + settings = g_variant_lookup_value(v_dict, "Settings", G_VARIANT_TYPE_VARDICT); + if (settings == NULL) { + _LOGW("ofono: connection failed; can not read 'Settings' property"); + goto error; + } + + handle_settings(settings, user_data); + } else { + g_dbus_proxy_call(priv->context_proxy, + "SetProperty", + g_variant_new("(sv)", "Active", g_variant_new("b", TRUE)), + G_DBUS_CALL_FLAGS_NONE, + 20000, + NULL, + (GAsyncReadyCallback) stage1_prepare_done, + self); + } + return; + +error: + nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, NM_DEVICE_STATE_REASON_MODEM_BUSY); +} + static void context_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) { @@ -973,19 +1042,15 @@ context_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) */ g_clear_object(&priv->ip4_config); - _nm_dbus_signal_connect(priv->context_proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(context_property_changed), - self); - + /* We need to directly query ConnectionContextinteface to get the current + * property values */ g_dbus_proxy_call(priv->context_proxy, - "SetProperty", - g_variant_new("(sv)", "Active", g_variant_new("b", TRUE)), + "GetProperties", + NULL, G_DBUS_CALL_FLAGS_NONE, 20000, - priv->context_proxy_cancellable, - stage1_prepare_done, + NULL, + (GAsyncReadyCallback) context_properties_cb, self); } @@ -1069,6 +1134,7 @@ modem_act_stage1_prepare(NMModem * modem, _LOGI("activating context %s", priv->context_path); + update_modem_state(self); if (nm_modem_get_state(modem) == NM_MODEM_STATE_REGISTERED) { do_context_activate(self); } else { diff --git a/src/core/devices/wwan/nm-modem-ofono.h b/src/core/devices/wwan/nm-modem-ofono.h index 260e3954..ebe21023 100644 --- a/src/core/devices/wwan/nm-modem-ofono.h +++ b/src/core/devices/wwan/nm-modem-ofono.h @@ -25,6 +25,8 @@ #define OFONO_DBUS_INTERFACE_CONNECTION_CONTEXT "org.ofono.ConnectionContext" #define OFONO_DBUS_INTERFACE_SIM_MANAGER "org.ofono.SimManager" +#define OFONO_ERROR_IN_PROGRESS "org.ofono.Error.InProgress" + typedef struct _NMModemOfono NMModemOfono; typedef struct _NMModemOfonoClass NMModemOfonoClass; diff --git a/src/core/devices/wwan/nm-modem.c b/src/core/devices/wwan/nm-modem.c index 0d334fa4..15baa677 100644 --- a/src/core/devices/wwan/nm-modem.c +++ b/src/core/devices/wwan/nm-modem.c @@ -10,10 +10,11 @@ #include #include +#include #include -#include "nm-core-internal.h" -#include "platform/nm-platform.h" +#include "libnm-core-intern/nm-core-internal.h" +#include "libnm-platform/nm-platform.h" #include "nm-setting-connection.h" #include "NetworkManagerUtils.h" #include "devices/nm-device-private.h" @@ -799,8 +800,10 @@ nm_modem_ip4_pre_commit(NMModem *modem, NMDevice *device, NMIP4Config *config) g_assert(address); if (address->plen == 32) - nm_platform_link_set_noarp(nm_device_get_platform(device), - nm_device_get_ip_ifindex(device)); + nm_platform_link_change_flags(nm_device_get_platform(device), + nm_device_get_ip_ifindex(device), + IFF_NOARP, + TRUE); } } @@ -1199,7 +1202,7 @@ deactivate_cleanup(NMModem *self, NMDevice *device, gboolean stop_ppp_manager) nm_platform_ip_route_flush(platform, AF_UNSPEC, ifindex); nm_platform_ip_address_flush(platform, AF_UNSPEC, ifindex); - nm_platform_link_set_down(platform, ifindex); + nm_platform_link_change_flags(platform, ifindex, IFF_UP, FALSE); } } } diff --git a/src/core/devices/wwan/nm-wwan-factory.c b/src/core/devices/wwan/nm-wwan-factory.c index 5d2ce2b3..0d802ae1 100644 --- a/src/core/devices/wwan/nm-wwan-factory.c +++ b/src/core/devices/wwan/nm-wwan-factory.c @@ -12,7 +12,7 @@ #include "nm-setting-cdma.h" #include "nm-modem-manager.h" #include "nm-device-modem.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" /*****************************************************************************/ diff --git a/src/core/dhcp/meson.build b/src/core/dhcp/meson.build index 1bb004cd..ddaa32fb 100644 --- a/src/core/dhcp/meson.build +++ b/src/core/dhcp/meson.build @@ -3,10 +3,11 @@ executable( 'nm-dhcp-helper', 'nm-dhcp-helper.c', - dependencies: glib_nm_default_dep, - c_args: [ - '-DG_LOG_DOMAIN="nm-dhcp-helper"', + include_directories: [ + src_inc, + top_inc, ], + dependencies: glib_dep, link_args: ldflags_linker_script_binary, link_depends: linker_script_binary, install: true, diff --git a/src/core/dhcp/nm-dhcp-client.c b/src/core/dhcp/nm-dhcp-client.c index c38c814e..ab8243d0 100644 --- a/src/core/dhcp/nm-dhcp-client.c +++ b/src/core/dhcp/nm-dhcp-client.c @@ -13,15 +13,16 @@ #include #include #include +#include -#include "nm-glib-aux/nm-dedup-multi.h" -#include "nm-glib-aux/nm-random-utils.h" +#include "libnm-glib-aux/nm-dedup-multi.h" +#include "libnm-glib-aux/nm-random-utils.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" #include "nm-dhcp-utils.h" #include "nm-dhcp-options.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-dhcp-client-logging.h" @@ -33,6 +34,7 @@ static guint signals[LAST_SIGNAL] = {0}; NM_GOBJECT_PROPERTIES_DEFINE(NMDhcpClient, PROP_ADDR_FAMILY, + PROP_ANYCAST_ADDRESS, PROP_FLAGS, PROP_HWADDR, PROP_BROADCAST_HWADDR, @@ -61,6 +63,7 @@ typedef struct _NMDhcpClientPrivate { char * hostname; const char ** reject_servers; char * mud_url; + char * anycast_address; GBytes * vendor_class_identifier; pid_t pid; guint timeout_id; @@ -73,8 +76,7 @@ typedef struct _NMDhcpClientPrivate { guint32 iaid; NMDhcpState state; NMDhcpHostnameFlags hostname_flags; - bool info_only : 1; - bool use_fqdn : 1; + NMDhcpClientFlags client_flags; bool iaid_explicit : 1; } NMDhcpClientPrivate; @@ -84,6 +86,11 @@ G_DEFINE_ABSTRACT_TYPE(NMDhcpClient, nm_dhcp_client, G_TYPE_OBJECT) /*****************************************************************************/ +/* we use pid=-1 for invalid PIDs. Ensure that pid_t can hold negative values. */ +G_STATIC_ASSERT(!(((pid_t) -1) > 0)); + +/*****************************************************************************/ + pid_t nm_dhcp_client_get_pid(NMDhcpClient *self) { @@ -276,6 +283,14 @@ nm_dhcp_client_set_client_id_bin(NMDhcpClient *self, _set_client_id(self, b, TRUE); } +const char * +nm_dhcp_client_get_anycast_address(NMDhcpClient *self) +{ + g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); + + return NM_DHCP_CLIENT_GET_PRIVATE(self)->anycast_address; +} + const char * nm_dhcp_client_get_hostname(NMDhcpClient *self) { @@ -292,20 +307,12 @@ nm_dhcp_client_get_hostname_flags(NMDhcpClient *self) return NM_DHCP_CLIENT_GET_PRIVATE(self)->hostname_flags; } -gboolean -nm_dhcp_client_get_info_only(NMDhcpClient *self) +NMDhcpClientFlags +nm_dhcp_client_get_client_flags(NMDhcpClient *self) { - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); + g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NM_DHCP_CLIENT_FLAGS_NONE); - return NM_DHCP_CLIENT_GET_PRIVATE(self)->info_only; -} - -gboolean -nm_dhcp_client_get_use_fqdn(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->use_fqdn; + return NM_DHCP_CLIENT_GET_PRIVATE(self)->client_flags; } const char * @@ -334,29 +341,25 @@ nm_dhcp_client_get_reject_servers(NMDhcpClient *self) /*****************************************************************************/ -static const char *state_table[NM_DHCP_STATE_MAX + 1] = { - [NM_DHCP_STATE_UNKNOWN] = "unknown", - [NM_DHCP_STATE_BOUND] = "bound", - [NM_DHCP_STATE_EXTENDED] = "extended", - [NM_DHCP_STATE_TIMEOUT] = "timeout", - [NM_DHCP_STATE_EXPIRE] = "expire", - [NM_DHCP_STATE_DONE] = "done", - [NM_DHCP_STATE_FAIL] = "fail", - [NM_DHCP_STATE_TERMINATED] = "terminated", -}; - -static const char * -state_to_string(NMDhcpState state) -{ - if ((gsize) state < G_N_ELEMENTS(state_table)) - return state_table[state]; - return NULL; -} +NM_UTILS_LOOKUP_STR_DEFINE(nm_dhcp_state_to_string, + NMDhcpState, + NM_UTILS_LOOKUP_DEFAULT(NULL), + NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_STATE_BOUND, "bound"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_STATE_DONE, "done"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_STATE_EXPIRE, "expire"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_STATE_EXTENDED, "extended"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_STATE_FAIL, "fail"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_STATE_NOOP, "noop"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_STATE_TERMINATED, "terminated"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_STATE_TIMEOUT, "timeout"), + NM_UTILS_LOOKUP_STR_ITEM(NM_DHCP_STATE_UNKNOWN, "unknown"), + NM_UTILS_LOOKUP_ITEM_IGNORE(__NM_DHCP_STATE_MAX), ); static NMDhcpState reason_to_state(NMDhcpClient *self, const char *iface, const char *reason) { - if (g_ascii_strcasecmp(reason, "bound") == 0 || g_ascii_strcasecmp(reason, "bound6") == 0) + if (g_ascii_strcasecmp(reason, "bound") == 0 || g_ascii_strcasecmp(reason, "bound6") == 0 + || g_ascii_strcasecmp(reason, "static") == 0) return NM_DHCP_STATE_BOUND; else if (g_ascii_strcasecmp(reason, "renew") == 0 || g_ascii_strcasecmp(reason, "renew6") == 0 || g_ascii_strcasecmp(reason, "reboot") == 0 @@ -488,8 +491,8 @@ nm_dhcp_client_set_state(NMDhcpClient *self, const char *addr = nm_g_hash_table_lookup(options, req_str); _LOGI("state changed %s -> %s%s%s%s", - state_to_string(priv->state), - state_to_string(new_state), + nm_dhcp_state_to_string(priv->state), + nm_dhcp_state_to_string(new_state), NM_PRINT_FMT_QUOTED(addr, ", address=", addr, "", "")); } @@ -514,20 +517,12 @@ daemon_watch_cb(GPid pid, int status, gpointer user_data) { NMDhcpClient * self = NM_DHCP_CLIENT(user_data); NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + gs_free char * desc = NULL; g_return_if_fail(priv->watch_id); priv->watch_id = 0; - if (WIFEXITED(status)) - _LOGI("client pid %d exited with status %d", pid, WEXITSTATUS(status)); - else if (WIFSIGNALED(status)) - _LOGI("client pid %d killed by signal %d", pid, WTERMSIG(status)); - else if (WIFSTOPPED(status)) - _LOGI("client pid %d stopped by signal %d", pid, WSTOPSIG(status)); - else if (WIFCONTINUED(status)) - _LOGI("client pid %d resumed (by SIGCONT)", pid); - else - _LOGW("client died abnormally"); + _LOGI("client pid %d %s", pid, (desc = nm_utils_get_process_exit_status_desc(status))); priv->pid = -1; @@ -578,7 +573,6 @@ nm_dhcp_client_stop_watch_child(NMDhcpClient *self, pid_t pid) gboolean nm_dhcp_client_start_ip4(NMDhcpClient *self, GBytes * client_id, - const char * dhcp_anycast_addr, const char * last_ip4_address, GError ** error) { @@ -598,10 +592,7 @@ nm_dhcp_client_start_ip4(NMDhcpClient *self, nm_dhcp_client_set_client_id(self, client_id); - return NM_DHCP_CLIENT_GET_CLASS(self)->ip4_start(self, - dhcp_anycast_addr, - last_ip4_address, - error); + return NM_DHCP_CLIENT_GET_CLASS(self)->ip4_start(self, last_ip4_address, error); } gboolean @@ -638,7 +629,6 @@ gboolean nm_dhcp_client_start_ip6(NMDhcpClient * self, GBytes * client_id, gboolean enforce_duid, - const char * dhcp_anycast_addr, const struct in6_addr * ll_addr, NMSettingIP6ConfigPrivacy privacy, guint needed_prefixes, @@ -667,8 +657,11 @@ nm_dhcp_client_start_ip6(NMDhcpClient * self, else _LOGI("activation: beginning transaction (timeout in %u seconds)", (guint) priv->timeout); - return NM_DHCP_CLIENT_GET_CLASS(self) - ->ip6_start(self, dhcp_anycast_addr, ll_addr, privacy, needed_prefixes, error); + return NM_DHCP_CLIENT_GET_CLASS(self)->ip6_start(self, + ll_addr, + privacy, + needed_prefixes, + error); } void @@ -749,7 +742,7 @@ nm_dhcp_client_stop(NMDhcpClient *self, gboolean release) _LOGI("canceled DHCP transaction"); nm_assert(priv->pid == -1); - nm_dhcp_client_set_state(self, NM_DHCP_STATE_DONE, NULL, NULL); + nm_dhcp_client_set_state(self, NM_DHCP_STATE_TERMINATED, NULL, NULL); } /*****************************************************************************/ @@ -898,8 +891,8 @@ nm_dhcp_client_handle_event(gpointer unused, old_state = priv->state; new_state = reason_to_state(self, priv->iface, reason); _LOGD("DHCP state '%s' -> '%s' (reason: '%s')", - state_to_string(old_state), - state_to_string(new_state), + nm_dhcp_state_to_string(old_state), + nm_dhcp_state_to_string(new_state), reason); if (new_state == NM_DHCP_STATE_NOOP) @@ -930,12 +923,12 @@ nm_dhcp_client_handle_event(gpointer unused, priv->route_metric)); } else { prefix = nm_dhcp_utils_ip6_prefix_from_options(str_options); - ip_config = NM_IP_CONFIG_CAST( - nm_dhcp_utils_ip6_config_from_options(nm_dhcp_client_get_multi_idx(self), - priv->ifindex, - priv->iface, - str_options, - priv->info_only)); + ip_config = NM_IP_CONFIG_CAST(nm_dhcp_utils_ip6_config_from_options( + nm_dhcp_client_get_multi_idx(self), + priv->ifindex, + priv->iface, + str_options, + NM_FLAGS_HAS(priv->client_flags, NM_DHCP_CLIENT_FLAGS_INFO_ONLY))); } } else g_warn_if_reached(); @@ -1052,11 +1045,8 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps case PROP_FLAGS: /* construct-only */ flags = g_value_get_uint(value); - nm_assert( - (flags & ~((guint)(NM_DHCP_CLIENT_FLAGS_INFO_ONLY | NM_DHCP_CLIENT_FLAGS_USE_FQDN))) - == 0); - priv->info_only = NM_FLAGS_HAS(flags, NM_DHCP_CLIENT_FLAGS_INFO_ONLY); - priv->use_fqdn = NM_FLAGS_HAS(flags, NM_DHCP_CLIENT_FLAGS_USE_FQDN); + nm_assert(!NM_FLAGS_ANY(flags, ~((guint) NM_DHCP_CLIENT_FLAGS_ALL))); + priv->client_flags = flags; break; case PROP_MULTI_IDX: /* construct-only */ @@ -1080,6 +1070,10 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps /* construct-only */ priv->hwaddr = g_value_dup_boxed(value); break; + case PROP_ANYCAST_ADDRESS: + /* construct-only */ + priv->anycast_address = g_value_dup_string(value); + break; case PROP_BROADCAST_HWADDR: /* construct-only */ priv->bcast_hwaddr = g_value_dup_boxed(value); @@ -1153,6 +1147,28 @@ nm_dhcp_client_init(NMDhcpClient *self) priv->pid = -1; } +#if NM_MORE_ASSERTS +static void +constructed(GObject *object) +{ + NMDhcpClient * self = NM_DHCP_CLIENT(object); + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + /* certain flags only make sense with certain address family. Assert + * for that. */ + if (NM_IS_IPv4(priv->addr_family)) + nm_assert(!NM_FLAGS_ANY(priv->client_flags, NM_DHCP_CLIENT_FLAGS_INFO_ONLY)); + else { + nm_assert(NM_FLAGS_HAS(priv->client_flags, NM_DHCP_CLIENT_FLAGS_USE_FQDN)); + nm_assert(!NM_FLAGS_ANY(priv->client_flags, NM_DHCP_CLIENT_FLAGS_REQUEST_BROADCAST)); + } + + nm_assert(!priv->anycast_address || nm_utils_hwaddr_valid(priv->anycast_address, ETH_ALEN)); + + G_OBJECT_CLASS(nm_dhcp_client_parent_class)->constructed(object); +} +#endif + static void dispose(GObject *object) { @@ -1172,6 +1188,7 @@ dispose(GObject *object) nm_clear_g_free(&priv->iface); nm_clear_g_free(&priv->hostname); nm_clear_g_free(&priv->uuid); + nm_clear_g_free(&priv->anycast_address); nm_clear_g_free(&priv->mud_url); nm_clear_g_free(&priv->reject_servers); nm_clear_pointer(&priv->client_id, g_bytes_unref); @@ -1191,6 +1208,9 @@ nm_dhcp_client_class_init(NMDhcpClientClass *client_class) g_type_class_add_private(client_class, sizeof(NMDhcpClientPrivate)); +#if NM_MORE_ASSERTS + object_class->constructed = constructed; +#endif object_class->dispose = dispose; object_class->get_property = get_property; object_class->set_property = set_property; @@ -1243,6 +1263,13 @@ nm_dhcp_client_class_init(NMDhcpClientClass *client_class) AF_UNSPEC, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_ANYCAST_ADDRESS] = + g_param_spec_string(NM_DHCP_CLIENT_ANYCAST_ADDRESS, + "", + "", + NULL, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_UUID] = g_param_spec_string(NM_DHCP_CLIENT_UUID, "", diff --git a/src/core/dhcp/nm-dhcp-client.h b/src/core/dhcp/nm-dhcp-client.h index 72ab477d..3fe1b34e 100644 --- a/src/core/dhcp/nm-dhcp-client.h +++ b/src/core/dhcp/nm-dhcp-client.h @@ -25,6 +25,7 @@ (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DHCP_CLIENT, NMDhcpClientClass)) #define NM_DHCP_CLIENT_ADDR_FAMILY "addr-family" +#define NM_DHCP_CLIENT_ANYCAST_ADDRESS "anycast-address" #define NM_DHCP_CLIENT_FLAGS "flags" #define NM_DHCP_CLIENT_HWADDR "hwaddr" #define NM_DHCP_CLIENT_BROADCAST_HWADDR "broadcast-hwaddr" @@ -51,7 +52,7 @@ typedef enum { NM_DHCP_STATE_BOUND, /* new lease */ NM_DHCP_STATE_EXTENDED, /* lease extended */ NM_DHCP_STATE_TIMEOUT, /* timed out contacting server */ - NM_DHCP_STATE_DONE, /* client quit or stopped */ + NM_DHCP_STATE_DONE, /* client reported it's stopping */ NM_DHCP_STATE_EXPIRE, /* lease expired or NAKed */ NM_DHCP_STATE_FAIL, /* failed for some reason */ NM_DHCP_STATE_TERMINATED, /* client is no longer running */ @@ -60,6 +61,8 @@ typedef enum { NM_DHCP_STATE_MAX = __NM_DHCP_STATE_MAX - 1, } NMDhcpState; +const char *nm_dhcp_state_to_string(NMDhcpState state); + struct _NMDhcpClientPrivate; typedef struct { @@ -68,25 +71,27 @@ typedef struct { CList dhcp_client_lst; } NMDhcpClient; -typedef enum { - NM_DHCP_CLIENT_FLAGS_INFO_ONLY = (1LL << 0), - NM_DHCP_CLIENT_FLAGS_USE_FQDN = (1LL << 1), +typedef enum _nm_packed { + NM_DHCP_CLIENT_FLAGS_NONE = 0, + + NM_DHCP_CLIENT_FLAGS_INFO_ONLY = (1LL << 0), + NM_DHCP_CLIENT_FLAGS_USE_FQDN = (1LL << 1), + NM_DHCP_CLIENT_FLAGS_REQUEST_BROADCAST = (1LL << 2), + + _NM_DHCP_CLIENT_FLAGS_LAST, + NM_DHCP_CLIENT_FLAGS_ALL = ((_NM_DHCP_CLIENT_FLAGS_LAST - 1) << 1) - 1, } NMDhcpClientFlags; typedef struct { GObjectClass parent; - gboolean (*ip4_start)(NMDhcpClient *self, - const char * anycast_addr, - const char * last_ip4_address, - GError ** error); + gboolean (*ip4_start)(NMDhcpClient *self, const char *last_ip4_address, GError **error); gboolean (*accept)(NMDhcpClient *self, GError **error); gboolean (*decline)(NMDhcpClient *self, const char *error_message, GError **error); gboolean (*ip6_start)(NMDhcpClient * self, - const char * anycast_addr, const struct in6_addr * ll_addr, NMSettingIP6ConfigPrivacy privacy, guint needed_prefixes, @@ -126,6 +131,8 @@ GBytes *nm_dhcp_client_get_hw_addr(NMDhcpClient *self); GBytes *nm_dhcp_client_get_broadcast_hw_addr(NMDhcpClient *self); +const char *nm_dhcp_client_get_anycast_address(NMDhcpClient *self); + guint32 nm_dhcp_client_get_route_table(NMDhcpClient *self); void nm_dhcp_client_set_route_table(NMDhcpClient *self, guint32 route_table); @@ -148,22 +155,18 @@ const char *const *nm_dhcp_client_get_reject_servers(NMDhcpClient *self); NMDhcpHostnameFlags nm_dhcp_client_get_hostname_flags(NMDhcpClient *self); -gboolean nm_dhcp_client_get_info_only(NMDhcpClient *self); - -gboolean nm_dhcp_client_get_use_fqdn(NMDhcpClient *self); +NMDhcpClientFlags nm_dhcp_client_get_client_flags(NMDhcpClient *self); GBytes *nm_dhcp_client_get_vendor_class_identifier(NMDhcpClient *self); gboolean nm_dhcp_client_start_ip4(NMDhcpClient *self, GBytes * client_id, - const char * dhcp_anycast_addr, const char * last_ip4_address, GError ** error); gboolean nm_dhcp_client_start_ip6(NMDhcpClient * self, GBytes * client_id, gboolean enforce_duid, - const char * dhcp_anycast_addr, const struct in6_addr * ll_addr, NMSettingIP6ConfigPrivacy privacy, guint needed_prefixes, diff --git a/src/core/dhcp/nm-dhcp-dhclient-utils.c b/src/core/dhcp/nm-dhcp-dhclient-utils.c index ad1e097f..4284a852 100644 --- a/src/core/dhcp/nm-dhcp-dhclient-utils.c +++ b/src/core/dhcp/nm-dhcp-dhclient-utils.c @@ -12,12 +12,12 @@ #include #include -#include "nm-glib-aux/nm-dedup-multi.h" +#include "libnm-glib-aux/nm-dedup-multi.h" #include "nm-dhcp-utils.h" #include "nm-ip4-config.h" #include "nm-utils.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "NetworkManagerUtils.h" #define TIMEOUT_TAG "timeout " @@ -291,7 +291,7 @@ char * nm_dhcp_dhclient_create_config(const char * interface, int addr_family, GBytes * client_id, - const char * anycast_addr, + const char * anycast_address, const char * hostname, guint32 timeout, gboolean use_fqdn, @@ -308,7 +308,8 @@ nm_dhcp_dhclient_create_config(const char * interface, gboolean reset_reqlist = FALSE; int i; - g_return_val_if_fail(!anycast_addr || nm_utils_hwaddr_valid(anycast_addr, ETH_ALEN), NULL); + g_return_val_if_fail(!anycast_address || nm_utils_hwaddr_valid(anycast_address, ETH_ALEN), + NULL); g_return_val_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6), NULL); g_return_val_if_fail(!reject_servers || addr_family == AF_INET, NULL); nm_assert(!out_new_client_id || !*out_new_client_id); @@ -508,14 +509,14 @@ nm_dhcp_dhclient_create_config(const char * interface, g_string_append_c(new_contents, '\n'); - if (anycast_addr) { + if (anycast_address) { g_string_append_printf(new_contents, "interface \"%s\" {\n" " initial-interval 1; \n" " anycast-mac ethernet %s;\n" "}\n", interface, - anycast_addr); + anycast_address); } return g_string_free(g_steal_pointer(&new_contents), FALSE); diff --git a/src/core/dhcp/nm-dhcp-dhclient.c b/src/core/dhcp/nm-dhcp-dhclient.c index c42a0ba5..4a11250f 100644 --- a/src/core/dhcp/nm-dhcp-dhclient.c +++ b/src/core/dhcp/nm-dhcp-dhclient.c @@ -21,7 +21,7 @@ #include #include - #include "nm-glib-aux/nm-dedup-multi.h" + #include "libnm-glib-aux/nm-dedup-multi.h" #include "nm-utils.h" #include "nm-dhcp-dhclient-utils.h" @@ -151,7 +151,7 @@ merge_dhclient_config(NMDhcpDhclient * self, const char * iface, const char * conf_file, GBytes * client_id, - const char * anycast_addr, + const char * anycast_address, const char * hostname, guint32 timeout, gboolean use_fqdn, @@ -180,7 +180,7 @@ merge_dhclient_config(NMDhcpDhclient * self, new = nm_dhcp_dhclient_create_config(iface, addr_family, client_id, - anycast_addr, + anycast_address, hostname, timeout, use_fqdn, @@ -280,7 +280,7 @@ create_dhclient_config(NMDhcpDhclient * self, const char * iface, const char * uuid, GBytes * client_id, - const char * dhcp_anycast_addr, + const char * anycast_address, const char * hostname, guint32 timeout, gboolean use_fqdn, @@ -312,7 +312,7 @@ create_dhclient_config(NMDhcpDhclient * self, iface, new, client_id, - dhcp_anycast_addr, + anycast_address, hostname, timeout, use_fqdn, @@ -435,6 +435,12 @@ dhclient_start(NMDhcpClient *client, if (release) g_ptr_array_add(argv, (gpointer) "-r"); + if (!release + && NM_FLAGS_HAS(nm_dhcp_client_get_client_flags(NM_DHCP_CLIENT(self)), + NM_DHCP_CLIENT_FLAGS_REQUEST_BROADCAST)) { + g_ptr_array_add(argv, (gpointer) "-B"); + } + if (addr_family == AF_INET6) { g_ptr_array_add(argv, (gpointer) "-6"); @@ -508,10 +514,7 @@ dhclient_start(NMDhcpClient *client, } static gboolean -ip4_start(NMDhcpClient *client, - const char * dhcp_anycast_addr, - const char * last_ip4_address, - GError ** error) +ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) { NMDhcpDhclient * self = NM_DHCP_DHCLIENT(client); NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE(self); @@ -520,19 +523,20 @@ ip4_start(NMDhcpClient *client, client_id = nm_dhcp_client_get_client_id(client); - priv->conf_file = create_dhclient_config(self, - AF_INET, - nm_dhcp_client_get_iface(client), - nm_dhcp_client_get_uuid(client), - client_id, - dhcp_anycast_addr, - nm_dhcp_client_get_hostname(client), - nm_dhcp_client_get_timeout(client), - nm_dhcp_client_get_use_fqdn(client), - nm_dhcp_client_get_hostname_flags(client), - nm_dhcp_client_get_mud_url(client), - nm_dhcp_client_get_reject_servers(client), - &new_client_id); + priv->conf_file = create_dhclient_config( + self, + AF_INET, + nm_dhcp_client_get_iface(client), + nm_dhcp_client_get_uuid(client), + client_id, + nm_dhcp_client_get_anycast_address(client), + nm_dhcp_client_get_hostname(client), + nm_dhcp_client_get_timeout(client), + NM_FLAGS_HAS(nm_dhcp_client_get_client_flags(client), NM_DHCP_CLIENT_FLAGS_USE_FQDN), + nm_dhcp_client_get_hostname_flags(client), + nm_dhcp_client_get_mud_url(client), + nm_dhcp_client_get_reject_servers(client), + &new_client_id); if (!priv->conf_file) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, @@ -549,7 +553,6 @@ ip4_start(NMDhcpClient *client, static gboolean ip6_start(NMDhcpClient * client, - const char * dhcp_anycast_addr, const struct in6_addr * ll_addr, NMSettingIP6ConfigPrivacy privacy, guint needed_prefixes, @@ -566,7 +569,7 @@ ip6_start(NMDhcpClient * client, nm_dhcp_client_get_iface(client), nm_dhcp_client_get_uuid(client), NULL, - dhcp_anycast_addr, + nm_dhcp_client_get_anycast_address(client), nm_dhcp_client_get_hostname(client), nm_dhcp_client_get_timeout(client), TRUE, @@ -582,7 +585,10 @@ ip6_start(NMDhcpClient * client, } return dhclient_start(client, - nm_dhcp_client_get_info_only(NM_DHCP_CLIENT(self)) ? "-S" : "-N", + NM_FLAGS_HAS(nm_dhcp_client_get_client_flags(NM_DHCP_CLIENT(self)), + NM_DHCP_CLIENT_FLAGS_INFO_ONLY) + ? "-S" + : "-N", FALSE, NULL, needed_prefixes, diff --git a/src/core/dhcp/nm-dhcp-dhcpcanon.c b/src/core/dhcp/nm-dhcp-dhcpcanon.c index 3504a048..f3a52ea9 100644 --- a/src/core/dhcp/nm-dhcp-dhcpcanon.c +++ b/src/core/dhcp/nm-dhcp-dhcpcanon.c @@ -161,10 +161,7 @@ dhcpcanon_start(NMDhcpClient *client, } static gboolean -ip4_start(NMDhcpClient *client, - const char * dhcp_anycast_addr, - const char * last_ip4_address, - GError ** error) +ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) { return dhcpcanon_start(client, NULL, NULL, FALSE, NULL, 0, error); } diff --git a/src/core/dhcp/nm-dhcp-dhcpcd.c b/src/core/dhcp/nm-dhcp-dhcpcd.c index cf9fe5c2..605fb84d 100644 --- a/src/core/dhcp/nm-dhcp-dhcpcd.c +++ b/src/core/dhcp/nm-dhcp-dhcpcd.c @@ -65,10 +65,7 @@ nm_dhcp_dhcpcd_get_path(void) } static gboolean -ip4_start(NMDhcpClient *client, - const char * dhcp_anycast_addr, - const char * last_ip4_address, - GError ** error) +ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) { NMDhcpDhcpcd * self = NM_DHCP_DHCPCD(client); gs_unref_ptrarray GPtrArray *argv = NULL; @@ -122,7 +119,7 @@ ip4_start(NMDhcpClient *client, hostname = nm_dhcp_client_get_hostname(client); if (hostname) { - if (nm_dhcp_client_get_use_fqdn(client)) { + if (NM_FLAGS_HAS(nm_dhcp_client_get_client_flags(client), NM_DHCP_CLIENT_FLAGS_USE_FQDN)) { g_ptr_array_add(argv, (gpointer) "-h"); g_ptr_array_add(argv, (gpointer) hostname); g_ptr_array_add(argv, (gpointer) "-F"); @@ -169,27 +166,29 @@ stop(NMDhcpClient *client, gboolean release) int sig, errsv; pid = nm_dhcp_client_get_pid(client); - sig = release ? SIGALRM : SIGTERM; - _LOGD("sending %s to dhcpcd pid %d", sig == SIGALRM ? "SIGALRM" : "SIGTERM", pid); - - /* dhcpcd-9.x features privilege separation. - * It's not our job to track all these processes so we rely on dhcpcd - * to always cleanup after itself. - * Because it also re-parents itself to PID 1, the process cannot be - * reaped or waited for. - * As such, just send the correct signal. - */ - if (kill(pid, sig) == -1) { - errsv = errno; - _LOGE("failed to kill dhcpcd %d:%s", errsv, strerror(errsv)); - } + if (pid > 1) { + sig = release ? SIGALRM : SIGTERM; + _LOGD("sending %s to dhcpcd pid %d", sig == SIGALRM ? "SIGALRM" : "SIGTERM", pid); + + /* dhcpcd-9.x features privilege separation. + * It's not our job to track all these processes so we rely on dhcpcd + * to always cleanup after itself. + * Because it also re-parents itself to PID 1, the process cannot be + * reaped or waited for. + * As such, just send the correct signal. + */ + if (kill(pid, sig) == -1) { + errsv = errno; + _LOGE("failed to kill dhcpcd %d:%s", errsv, strerror(errsv)); + } - /* When this function exits NM expects the PID to be -1. - * This means we also need to stop watching the pid. - * If we need to know the exit status then we need to refactor NM - * to allow a non -1 to mean we're waiting to exit still. - */ - nm_dhcp_client_stop_watch_child(client, pid); + /* When this function exits NM expects the PID to be -1. + * This means we also need to stop watching the pid. + * If we need to know the exit status then we need to refactor NM + * to allow a non -1 to mean we're waiting to exit still. + */ + nm_dhcp_client_stop_watch_child(client, pid); + } } /*****************************************************************************/ diff --git a/src/core/dhcp/nm-dhcp-helper.c b/src/core/dhcp/nm-dhcp-helper.c index 0f98add1..56d20101 100644 --- a/src/core/dhcp/nm-dhcp-helper.c +++ b/src/core/dhcp/nm-dhcp-helper.c @@ -3,13 +3,13 @@ * Copyright (C) 2007 - 2013 Red Hat, Inc. */ -#include "nm-glib-aux/nm-default-glib.h" +#include "libnm-glib-aux/nm-default-glib.h" #include #include #include -#include "nm-utils/nm-vpn-plugin-macros.h" +#include "libnm-glib-aux/nm-logging-syslog.h" #include "nm-dhcp-helper-api.h" @@ -92,7 +92,7 @@ build_signal_parameters(void) g_variant_builder_add(&builder, "{sv}", name, - g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, val, strlen(val), 1)); + nm_g_variant_new_ay((const guint8 *) val, strlen(val))); next:; } @@ -154,7 +154,7 @@ do_connect: error->message, try_count, (long long) (time_end - time_remaining - time_start) / 1000); - interval = NM_CLAMP((gint64)(100L * (1L << NM_MIN(try_count, 31))), 5000, 100000); + interval = NM_CLAMP((gint64) (100L * (1L << NM_MIN(try_count, 31))), 5000, 100000); g_usleep(NM_MIN(interval, time_remaining)); g_clear_error(&error); goto do_connect; @@ -199,7 +199,7 @@ do_notify: * do some retry. */ if (remaining_time > 0) { _LOGi("failure to call notify: %s (retry %u)", error->message, try_count); - interval = NM_CLAMP((gint64)(100L * (1L << NM_MIN(try_count, 31))), 5000, 25000); + interval = NM_CLAMP((gint64) (100L * (1L << NM_MIN(try_count, 31))), 5000, 25000); g_usleep(NM_MIN(interval, remaining_time)); g_clear_error(&error); goto do_notify; diff --git a/src/core/dhcp/nm-dhcp-listener.c b/src/core/dhcp/nm-dhcp-listener.c index 1673bbb7..b8bb3c33 100644 --- a/src/core/dhcp/nm-dhcp-listener.c +++ b/src/core/dhcp/nm-dhcp-listener.c @@ -16,7 +16,7 @@ #include "nm-dhcp-helper-api.h" #include "nm-dhcp-client.h" #include "nm-dhcp-manager.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-dbus-manager.h" #include "NetworkManagerUtils.h" diff --git a/src/core/dhcp/nm-dhcp-manager.c b/src/core/dhcp/nm-dhcp-manager.c index bc114ad8..44b8ede2 100644 --- a/src/core/dhcp/nm-dhcp-manager.c +++ b/src/core/dhcp/nm-dhcp-manager.c @@ -16,8 +16,8 @@ #include #include -#include "nm-glib-aux/nm-dedup-multi.h" -#include "systemd/nm-sd-utils-shared.h" +#include "libnm-glib-aux/nm-dedup-multi.h" +#include "libnm-systemd-shared/nm-sd-utils-shared.h" #include "nm-config.h" #include "NetworkManagerUtils.h" @@ -213,12 +213,11 @@ client_start(NMDhcpManager * self, guint32 iaid, gboolean iaid_explicit, guint32 timeout, - const char * dhcp_anycast_addr, + NMDhcpClientFlags client_flags, + const char * anycast_address, const char * hostname, - gboolean hostname_use_fqdn, NMDhcpHostnameFlags hostname_flags, const char * mud_url, - gboolean info_only, NMSettingIP6ConfigPrivacy privacy, const char * last_ip4_address, guint needed_prefixes, @@ -241,6 +240,7 @@ client_start(NMDhcpManager * self, || g_bytes_get_size(vendor_class_identifier) <= 255, NULL); g_return_val_if_fail(!error || !*error, NULL); + nm_assert(!NM_FLAGS_ANY(client_flags, ~NM_DHCP_CLIENT_FLAGS_ALL)); if (addr_family == AF_INET) { if (!hwaddr || !bcast_hwaddr) { @@ -252,7 +252,7 @@ client_start(NMDhcpManager * self, } hwaddr_len = g_bytes_get_size(hwaddr); - if (hwaddr_len == 0 || hwaddr_len > NM_UTILS_HWADDR_LEN_MAX) { + if (hwaddr_len == 0 || hwaddr_len > _NM_UTILS_HWADDR_LEN_MAX) { nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "invalid MAC address"); g_return_val_if_reached(NULL); } @@ -263,12 +263,14 @@ client_start(NMDhcpManager * self, } if (hostname) { - if ((hostname_use_fqdn && !nm_sd_dns_name_is_valid(hostname)) - || (!hostname_use_fqdn && !nm_sd_hostname_is_valid(hostname, FALSE))) { + gboolean use_fqdn = NM_FLAGS_HAS(client_flags, NM_DHCP_CLIENT_FLAGS_USE_FQDN); + + if ((use_fqdn && !nm_sd_dns_name_is_valid(hostname)) + || (!use_fqdn && !nm_sd_hostname_is_valid(hostname, FALSE))) { nm_log_warn(LOGD_DHCP, "dhcp%c: %s '%s' is invalid, will be ignored", nm_utils_addr_family_to_char(addr_family), - hostname_use_fqdn ? "FQDN" : "hostname", + use_fqdn ? "FQDN" : "hostname", hostname); hostname = NULL; } @@ -334,8 +336,9 @@ client_start(NMDhcpManager * self, NM_DHCP_CLIENT_REJECT_SERVERS, reject_servers, NM_DHCP_CLIENT_FLAGS, - (guint)(0 | (hostname_use_fqdn ? NM_DHCP_CLIENT_FLAGS_USE_FQDN : 0) - | (info_only ? NM_DHCP_CLIENT_FLAGS_INFO_ONLY : 0)), + (guint) client_flags, + NM_DHCP_CLIENT_ANYCAST_ADDRESS, + anycast_address, NULL); nm_assert(client && c_list_is_empty(&client->dhcp_client_lst)); c_list_link_tail(&priv->dhcp_client_lst_head, &client->dhcp_client_lst); @@ -371,16 +374,11 @@ client_start(NMDhcpManager * self, */ if (addr_family == AF_INET) { - success = nm_dhcp_client_start_ip4(client, - dhcp_client_id, - dhcp_anycast_addr, - last_ip4_address, - error); + success = nm_dhcp_client_start_ip4(client, dhcp_client_id, last_ip4_address, error); } else { success = nm_dhcp_client_start_ip6(client, dhcp_client_id, enforce_duid, - dhcp_anycast_addr, ipv6_ll_addr, privacy, needed_prefixes, @@ -406,6 +404,7 @@ nm_dhcp_manager_start_ip4(NMDhcpManager * self, const char * uuid, guint32 route_table, guint32 route_metric, + NMDhcpClientFlags client_flags, gboolean send_hostname, const char * dhcp_hostname, const char * dhcp_fqdn, @@ -413,7 +412,7 @@ nm_dhcp_manager_start_ip4(NMDhcpManager * self, const char * mud_url, GBytes * dhcp_client_id, guint32 timeout, - const char * dhcp_anycast_addr, + const char * anycast_address, const char * last_ip_address, GBytes * vendor_class_identifier, const char *const * reject_servers, @@ -425,6 +424,10 @@ nm_dhcp_manager_start_ip4(NMDhcpManager * self, gboolean use_fqdn = FALSE; char * dot; + /* these flags are set automatically/prohibited, and not free to set to the caller. */ + nm_assert(!NM_FLAGS_ANY(client_flags, + NM_DHCP_CLIENT_FLAGS_USE_FQDN | NM_DHCP_CLIENT_FLAGS_INFO_ONLY)); + g_return_val_if_fail(NM_IS_DHCP_MANAGER(self), NULL); priv = NM_DHCP_MANAGER_GET_PRIVATE(self); @@ -451,34 +454,34 @@ nm_dhcp_manager_start_ip4(NMDhcpManager * self, } } - return client_start(self, - AF_INET, - multi_idx, - iface, - ifindex, - hwaddr, - bcast_hwaddr, - uuid, - route_table, - route_metric, - NULL, - dhcp_client_id, - FALSE, - 0, - FALSE, - timeout, - dhcp_anycast_addr, - hostname, - use_fqdn, - hostname_flags, - mud_url, - FALSE, - 0, - last_ip_address, - 0, - vendor_class_identifier, - reject_servers, - error); + return client_start( + self, + AF_INET, + multi_idx, + iface, + ifindex, + hwaddr, + bcast_hwaddr, + uuid, + route_table, + route_metric, + NULL, + dhcp_client_id, + FALSE, + 0, + FALSE, + timeout, + client_flags | (use_fqdn ? NM_DHCP_CLIENT_FLAGS_USE_FQDN : NM_DHCP_CLIENT_FLAGS_NONE), + anycast_address, + hostname, + hostname_flags, + mud_url, + 0, + last_ip_address, + 0, + vendor_class_identifier, + reject_servers, + error); } /* Caller owns a reference to the NMDhcpClient on return */ @@ -491,6 +494,7 @@ nm_dhcp_manager_start_ip6(NMDhcpManager * self, const char * uuid, guint32 route_table, guint32 route_metric, + NMDhcpClientFlags client_flags, gboolean send_hostname, const char * dhcp_hostname, NMDhcpHostnameFlags hostname_flags, @@ -500,8 +504,7 @@ nm_dhcp_manager_start_ip6(NMDhcpManager * self, guint32 iaid, gboolean iaid_explicit, guint32 timeout, - const char * dhcp_anycast_addr, - gboolean info_only, + const char * anycast_address, NMSettingIP6ConfigPrivacy privacy, guint needed_prefixes, GError ** error) @@ -509,6 +512,9 @@ nm_dhcp_manager_start_ip6(NMDhcpManager * self, NMDhcpManagerPrivate *priv; const char * hostname = NULL; + /* this flag is set automatically, and not free to set to the caller. */ + nm_assert(!NM_FLAGS_ANY(client_flags, NM_DHCP_CLIENT_FLAGS_USE_FQDN)); + g_return_val_if_fail(NM_IS_DHCP_MANAGER(self), NULL); priv = NM_DHCP_MANAGER_GET_PRIVATE(self); @@ -532,12 +538,11 @@ nm_dhcp_manager_start_ip6(NMDhcpManager * self, iaid, iaid_explicit, timeout, - dhcp_anycast_addr, + client_flags | NM_DHCP_CLIENT_FLAGS_USE_FQDN, + anycast_address, hostname, - TRUE, hostname_flags, mud_url, - info_only, privacy, NULL, needed_prefixes, diff --git a/src/core/dhcp/nm-dhcp-manager.h b/src/core/dhcp/nm-dhcp-manager.h index f7aba8a0..ce160437 100644 --- a/src/core/dhcp/nm-dhcp-manager.h +++ b/src/core/dhcp/nm-dhcp-manager.h @@ -41,6 +41,7 @@ NMDhcpClient *nm_dhcp_manager_start_ip4(NMDhcpManager * manager, const char * uuid, guint32 route_table, guint32 route_metric, + NMDhcpClientFlags client_flags, gboolean send_hostname, const char * dhcp_hostname, const char * dhcp_fqdn, @@ -48,7 +49,7 @@ NMDhcpClient *nm_dhcp_manager_start_ip4(NMDhcpManager * manager, const char * mud_url, GBytes * dhcp_client_id, guint32 timeout, - const char * dhcp_anycast_addr, + const char * anycast_address, const char * last_ip_address, GBytes * vendor_class_identifier, const char *const * reject_servers, @@ -62,6 +63,7 @@ NMDhcpClient *nm_dhcp_manager_start_ip6(NMDhcpManager * manager, const char * uuid, guint32 route_table, guint32 route_metric, + NMDhcpClientFlags client_flags, gboolean send_hostname, const char * dhcp_hostname, NMDhcpHostnameFlags hostname_flags, @@ -71,8 +73,7 @@ NMDhcpClient *nm_dhcp_manager_start_ip6(NMDhcpManager * manager, guint32 iaid, gboolean iaid_explicit, guint32 timeout, - const char * dhcp_anycast_addr, - gboolean info_only, + const char * anycast_address, NMSettingIP6ConfigPrivacy privacy, guint needed_prefixes, GError ** error); diff --git a/src/core/dhcp/nm-dhcp-nettools.c b/src/core/dhcp/nm-dhcp-nettools.c index 116e1bdb..fe71f587 100644 --- a/src/core/dhcp/nm-dhcp-nettools.c +++ b/src/core/dhcp/nm-dhcp-nettools.c @@ -13,9 +13,9 @@ #include #include -#include "nm-glib-aux/nm-dedup-multi.h" -#include "nm-std-aux/unaligned.h" -#include "nm-glib-aux/nm-str-buf.h" +#include "libnm-glib-aux/nm-dedup-multi.h" +#include "libnm-std-aux/unaligned.h" +#include "libnm-glib-aux/nm-str-buf.h" #include "nm-utils.h" #include "nm-config.h" @@ -23,11 +23,11 @@ #include "nm-dhcp-options.h" #include "nm-core-utils.h" #include "NetworkManagerUtils.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-dhcp-client-logging.h" #include "n-dhcp4/src/n-dhcp4.h" -#include "systemd/nm-sd-utils-shared.h" -#include "systemd/nm-sd-utils-dhcp.h" +#include "libnm-systemd-shared/nm-sd-utils-shared.h" +#include "libnm-systemd-core/nm-sd-utils-dhcp.h" /*****************************************************************************/ @@ -342,16 +342,16 @@ lease_parse_routes(NDhcp4ClientLease *lease, const guint8 *l_data; gsize l_data_len; int r; + guint i; - r = _client_lease_query(lease, - NM_DHCP_OPTION_DHCP4_CLASSLESS_STATIC_ROUTE, - &l_data, - &l_data_len); - if (r == 0) { - nm_str_buf_reset(sbuf); + for (i = 0; i < 2; i++) { + const guint8 option_code = (i == 0) ? NM_DHCP_OPTION_DHCP4_CLASSLESS_STATIC_ROUTE + : NM_DHCP_OPTION_DHCP4_PRIVATE_CLASSLESS_STATIC_ROUTE; - has_classless = TRUE; + if (_client_lease_query(lease, option_code, &l_data, &l_data_len) != 0) + continue; + nm_str_buf_reset(sbuf); while (lease_option_consume_route(&l_data, &l_data_len, TRUE, &dest, &plen, &gateway)) { _nm_utils_inet4_ntop(dest, dest_str); _nm_utils_inet4_ntop(gateway, gateway_str); @@ -359,6 +359,11 @@ lease_parse_routes(NDhcp4ClientLease *lease, nm_str_buf_append_required_delimiter(sbuf, ' '); nm_str_buf_append_printf(sbuf, "%s/%d %s", dest_str, (int) plen, gateway_str); + if (has_classless) { + /* Ignore private option if the standard one is present */ + continue; + } + if (plen == 0) { /* if there are multiple default routes, we add them with differing * metrics. */ @@ -384,10 +389,8 @@ lease_parse_routes(NDhcp4ClientLease *lease, NULL); } - nm_dhcp_option_add_option(options, - AF_INET, - NM_DHCP_OPTION_DHCP4_CLASSLESS_STATIC_ROUTE, - nm_str_buf_get_str(sbuf)); + has_classless = TRUE; + nm_dhcp_option_add_option(options, AF_INET, option_code, nm_str_buf_get_str(sbuf)); } r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_STATIC_ROUTE, &l_data, &l_data_len); @@ -693,8 +696,8 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, v_str = nm_utils_buf_utf8safe_escape((char *) l_data, l_data_len, 0, &to_free); - nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NIS_DOMAIN, v_str); - nm_ip4_config_set_nis_domain(ip4_config, v_str); + nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NIS_DOMAIN, v_str ?: ""); + nm_ip4_config_set_nis_domain(ip4_config, v_str ?: ""); } lease_parse_address_list(lease, ip4_config, NM_DHCP_OPTION_DHCP4_NIS_SERVERS, options, &sbuf); @@ -871,7 +874,7 @@ dhcp4_event_cb(int fd, GIOCondition condition, gpointer user_data) } static gboolean -nettools_create(NMDhcpNettools *self, const char *dhcp_anycast_addr, GError **error) +nettools_create(NMDhcpNettools *self, GError **error) { NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); nm_auto(n_dhcp4_client_config_freep) NDhcp4ClientConfig *config = NULL; @@ -890,6 +893,8 @@ nettools_create(NMDhcpNettools *self, const char *dhcp_anycast_addr, GError **er g_return_val_if_fail(!priv->client, FALSE); + /* TODO: honor nm_dhcp_client_get_anycast_address() */ + hwaddr = nm_dhcp_client_get_hw_addr(NM_DHCP_CLIENT(self)); if (!hwaddr || !(hwaddr_arr = g_bytes_get_data(hwaddr, &hwaddr_len)) || (arp_type = nm_utils_arp_type_detect_from_hwaddrlen(hwaddr_len)) < 0) { @@ -938,9 +943,13 @@ nettools_create(NMDhcpNettools *self, const char *dhcp_anycast_addr, GError **er n_dhcp4_client_config_set_transport(config, transport); n_dhcp4_client_config_set_mac(config, hwaddr_arr, hwaddr_len); n_dhcp4_client_config_set_broadcast_mac(config, bcast_hwaddr_arr, bcast_hwaddr_len); + n_dhcp4_client_config_set_request_broadcast( + config, + NM_FLAGS_HAS(nm_dhcp_client_get_client_flags(NM_DHCP_CLIENT(self)), + NM_DHCP_CLIENT_FLAGS_REQUEST_BROADCAST)); r = n_dhcp4_client_config_set_client_id(config, client_id_arr, - NM_MIN(client_id_len, 1 + _NM_SD_MAX_CLIENT_ID_LEN)); + NM_MIN(client_id_len, 1 + _NM_MAX_CLIENT_ID_LEN)); if (r) { set_error_nettools(error, r, "failed to set client-id"); return FALSE; @@ -1028,10 +1037,7 @@ fqdn_flags_to_wire(NMDhcpHostnameFlags flags) } static gboolean -ip4_start(NMDhcpClient *client, - const char * dhcp_anycast_addr, - const char * last_ip4_address, - GError ** error) +ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) { nm_auto(n_dhcp4_client_probe_config_freep) NDhcp4ClientProbeConfig *config = NULL; NMDhcpNettools * self = NM_DHCP_NETTOOLS(client); @@ -1045,7 +1051,7 @@ ip4_start(NMDhcpClient *client, g_return_val_if_fail(!priv->probe, FALSE); - if (!nettools_create(self, dhcp_anycast_addr, error)) + if (!nettools_create(self, error)) return FALSE; r = n_dhcp4_client_probe_config_new(&config); @@ -1110,7 +1116,7 @@ ip4_start(NMDhcpClient *client, } hostname = nm_dhcp_client_get_hostname(client); if (hostname) { - if (nm_dhcp_client_get_use_fqdn(client)) { + if (NM_FLAGS_HAS(nm_dhcp_client_get_client_flags(client), NM_DHCP_CLIENT_FLAGS_USE_FQDN)) { uint8_t buffer[255]; NMDhcpHostnameFlags flags; size_t fqdn_len; diff --git a/src/core/dhcp/nm-dhcp-options.c b/src/core/dhcp/nm-dhcp-options.c index 3537cd14..8f0d7408 100644 --- a/src/core/dhcp/nm-dhcp-options.c +++ b/src/core/dhcp/nm-dhcp-options.c @@ -7,7 +7,7 @@ #include "nm-dhcp-options.h" -#include "nm-glib-aux/nm-str-buf.h" +#include "libnm-glib-aux/nm-str-buf.h" /*****************************************************************************/ diff --git a/src/core/dhcp/nm-dhcp-systemd.c b/src/core/dhcp/nm-dhcp-systemd.c index b92a9073..c789aaee 100644 --- a/src/core/dhcp/nm-dhcp-systemd.c +++ b/src/core/dhcp/nm-dhcp-systemd.c @@ -13,18 +13,18 @@ #include #include -#include "nm-glib-aux/nm-dedup-multi.h" -#include "nm-std-aux/unaligned.h" +#include "libnm-glib-aux/nm-dedup-multi.h" +#include "libnm-std-aux/unaligned.h" #include "nm-utils.h" #include "nm-dhcp-utils.h" #include "nm-dhcp-options.h" #include "nm-core-utils.h" #include "NetworkManagerUtils.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-dhcp-client-logging.h" -#include "systemd/nm-sd.h" -#include "systemd/nm-sd-utils-dhcp.h" +#include "libnm-systemd-core/nm-sd.h" +#include "libnm-systemd-core/nm-sd-utils-dhcp.h" /*****************************************************************************/ @@ -85,29 +85,29 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, const struct in_addr * addr_list; char addr_str[NM_UTILS_INET_ADDRSTRLEN]; const char * s; - nm_auto_free_gstring GString *str = NULL; - gs_free sd_dhcp_route **routes = NULL; - const char *const * search_domains = NULL; - guint16 mtu; - int i, num; - const void * data; - gsize data_len; - gboolean metered = FALSE; - gboolean has_router_from_classless = FALSE; - gboolean has_classless_route = FALSE; - gboolean has_static_route = FALSE; - const gint32 ts = nm_utils_get_monotonic_timestamp_sec(); - gint64 ts_time = time(NULL); - struct in_addr a_address; - struct in_addr a_netmask; - struct in_addr a_next_server; - struct in_addr server_id; - struct in_addr broadcast; - const struct in_addr * a_router; - guint32 a_plen; - guint32 a_lifetime; - guint32 renewal; - guint32 rebinding; + nm_auto_free_gstring GString *str = NULL; + nm_auto_free sd_dhcp_route **routes = NULL; + const char *const * search_domains = NULL; + guint16 mtu; + int i, num; + const void * data; + gsize data_len; + gboolean metered = FALSE; + gboolean has_router_from_classless = FALSE; + gboolean has_classless_route = FALSE; + gboolean has_static_route = FALSE; + const gint32 ts = nm_utils_get_monotonic_timestamp_sec(); + gint64 ts_time = time(NULL); + struct in_addr a_address; + struct in_addr a_netmask; + struct in_addr a_next_server; + struct in_addr server_id; + struct in_addr broadcast; + const struct in_addr * a_router; + guint32 a_plen; + guint32 a_lifetime; + guint32 renewal; + guint32 rebinding; gs_free nm_sd_dhcp_option *private_options = NULL; nm_assert(lease != NULL); @@ -153,7 +153,7 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, nm_dhcp_option_add_option_u64(options, AF_INET, NM_DHCP_OPTION_DHCP4_NM_EXPIRY, - (guint64)(ts_time + a_lifetime)); + (guint64) (ts_time + a_lifetime)); if (sd_dhcp_lease_get_next_server(lease, &a_next_server) == 0) { _nm_utils_inet4_ntop(a_next_server.s_addr, addr_str); @@ -429,18 +429,33 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, num = nm_sd_dhcp_lease_get_private_options(lease, &private_options); if (num > 0) { for (i = 0; i < num; i++) { - char *option_string; - - option_string = nm_utils_bin2hexstr_full(private_options[i].data, - private_options[i].data_len, - ':', - FALSE, - NULL); - if (!options) { - g_free(option_string); + guint8 code = private_options[i].code; + const guint8 *l_data = private_options[i].data; + gsize l_data_len = private_options[i].data_len; + char * option_string; + + if (code == NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY) { + if (nm_dhcp_lease_data_parse_cstr(l_data, l_data_len, &l_data_len)) { + nm_dhcp_option_add_option_utf8safe_escape( + options, + AF_INET, + NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY, + l_data, + l_data_len); + } continue; } - nm_dhcp_option_take_option(options, AF_INET, private_options[i].code, option_string); + if (code == NM_DHCP_OPTION_DHCP4_PRIVATE_CLASSLESS_STATIC_ROUTE) { + /* nettools and dhclient parse option 249 (Microsoft Classless Static Route) + * as fallback for routes and ignores them from private options. + * + * The systemd plugin does not, and for consistency with nettools we + * also don't expose it as private option either. */ + continue; + } + + option_string = nm_utils_bin2hexstr_full(l_data, l_data_len, ':', FALSE, NULL); + nm_dhcp_option_take_option(options, AF_INET, code, option_string); } } NM_SET_OUT(out_options, g_steal_pointer(&options)); @@ -543,10 +558,7 @@ dhcp_event_cb(sd_dhcp_client *client, int event, gpointer user_data) } static gboolean -ip4_start(NMDhcpClient *client, - const char * dhcp_anycast_addr, - const char * last_ip4_address, - GError ** error) +ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) { nm_auto(sd_dhcp_client_unrefp) sd_dhcp_client *sd_client = NULL; NMDhcpSystemd * self = NM_DHCP_SYSTEMD(client); @@ -572,6 +584,8 @@ ip4_start(NMDhcpClient *client, g_return_val_if_fail(!priv->client4, FALSE); g_return_val_if_fail(!priv->client6, FALSE); + /* TODO: honor nm_dhcp_client_get_anycast_address() */ + r = sd_dhcp_client_new(&sd_client, FALSE); if (r < 0) { nm_utils_error_set_errno(error, r, "failed to create dhcp-client: %s"); @@ -632,6 +646,11 @@ ip4_start(NMDhcpClient *client, sd_dhcp_lease_get_address(lease, &last_addr); } + r = sd_dhcp_client_set_request_broadcast(sd_client, + NM_FLAGS_HAS(nm_dhcp_client_get_client_flags(client), + NM_DHCP_CLIENT_FLAGS_REQUEST_BROADCAST)); + nm_assert(r >= 0); + if (last_addr.s_addr) { r = sd_dhcp_client_set_request_address(sd_client, &last_addr); if (r < 0) { @@ -659,7 +678,7 @@ ip4_start(NMDhcpClient *client, r = sd_dhcp_client_set_client_id(sd_client, client_id_arr[0], client_id_arr + 1, - NM_MIN(client_id_len - 1, _NM_SD_MAX_CLIENT_ID_LEN)); + NM_MIN(client_id_len - 1, _NM_MAX_CLIENT_ID_LEN)); if (r < 0) { nm_utils_error_set_errno(error, r, "failed to set IPv4 client-id: %s"); return FALSE; @@ -844,14 +863,16 @@ bound6_handle(NMDhcpSystemd *self) _LOGD("lease available"); - ip6_config = lease_to_ip6_config(nm_dhcp_client_get_multi_idx(NM_DHCP_CLIENT(self)), - iface, - nm_dhcp_client_get_ifindex(NM_DHCP_CLIENT(self)), - lease, - nm_dhcp_client_get_info_only(NM_DHCP_CLIENT(self)), - &options, - ts, - &error); + ip6_config = + lease_to_ip6_config(nm_dhcp_client_get_multi_idx(NM_DHCP_CLIENT(self)), + iface, + nm_dhcp_client_get_ifindex(NM_DHCP_CLIENT(self)), + lease, + NM_FLAGS_HAS(nm_dhcp_client_get_client_flags(NM_DHCP_CLIENT(self)), + NM_DHCP_CLIENT_FLAGS_INFO_ONLY), + &options, + ts, + &error); if (!ip6_config) { _LOGW("%s", error->message); @@ -905,7 +926,6 @@ 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, NMSettingIP6ConfigPrivacy privacy, guint needed_prefixes, @@ -924,6 +944,8 @@ ip6_start(NMDhcpClient * client, g_return_val_if_fail(!priv->client4, FALSE); g_return_val_if_fail(!priv->client6, FALSE); + /* TODO: honor nm_dhcp_client_get_anycast_address() */ + if (!(duid = nm_dhcp_client_get_client_id(client)) || !(duid_arr = g_bytes_get_data(duid, &duid_len)) || duid_len < 2) { nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "missing DUID"); @@ -938,7 +960,7 @@ ip6_start(NMDhcpClient * client, _LOGT("dhcp-client6: set %p", sd_client); - if (nm_dhcp_client_get_info_only(client)) { + if (NM_FLAGS_HAS(nm_dhcp_client_get_client_flags(client), NM_DHCP_CLIENT_FLAGS_INFO_ONLY)) { sd_dhcp6_client_set_address_request(sd_client, 0); if (needed_prefixes == 0) sd_dhcp6_client_set_information_request(sd_client, 1); diff --git a/src/core/dhcp/nm-dhcp-utils.c b/src/core/dhcp/nm-dhcp-utils.c index 646411e2..7fd18b0a 100644 --- a/src/core/dhcp/nm-dhcp-utils.c +++ b/src/core/dhcp/nm-dhcp-utils.c @@ -8,18 +8,18 @@ #include #include -#include "nm-std-aux/unaligned.h" -#include "nm-glib-aux/nm-dedup-multi.h" -#include "nm-glib-aux/nm-str-buf.h" -#include "systemd/nm-sd-utils-shared.h" +#include "libnm-std-aux/unaligned.h" +#include "libnm-glib-aux/nm-dedup-multi.h" +#include "libnm-glib-aux/nm-str-buf.h" +#include "libnm-systemd-shared/nm-sd-utils-shared.h" #include "nm-dhcp-utils.h" #include "nm-utils.h" #include "nm-config.h" #include "NetworkManagerUtils.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-dhcp-client-logging.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" /*****************************************************************************/ @@ -880,7 +880,7 @@ nm_dhcp_lease_data_parse_cstr(const guint8 *data, gsize n_data, gsize *out_new_l n_data--; if (n_data > 0) { - if (memchr(data, n_data, '\0')) { + if (memchr(data, '\0', n_data)) { /* we accept trailing NUL, but none in between. * * https://tools.ietf.org/html/rfc2132#section-2 @@ -989,7 +989,7 @@ lease_option_print_label(NMStrBuf *sbuf, size_t n_label, const uint8_t **datap, break; case '.': case '\\': - nm_str_buf_append_c2(sbuf, '\\', c); + nm_str_buf_append_c(sbuf, '\\', c); break; default: nm_str_buf_append_printf(sbuf, "\\%3d", c); diff --git a/src/core/dhcp/tests/test-dhcp-dhclient.c b/src/core/dhcp/tests/test-dhcp-dhclient.c index 77626f69..e9a62096 100644 --- a/src/core/dhcp/tests/test-dhcp-dhclient.c +++ b/src/core/dhcp/tests/test-dhcp-dhclient.c @@ -9,14 +9,14 @@ #include #include -#include "nm-glib-aux/nm-dedup-multi.h" +#include "libnm-glib-aux/nm-dedup-multi.h" #include "NetworkManagerUtils.h" #include "dhcp/nm-dhcp-dhclient-utils.h" #include "dhcp/nm-dhcp-utils.h" #include "nm-utils.h" #include "nm-ip4-config.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-test-utils-core.h" diff --git a/src/core/dhcp/tests/test-dhcp-utils.c b/src/core/dhcp/tests/test-dhcp-utils.c index 9b54e2cd..4d47e7e2 100644 --- a/src/core/dhcp/tests/test-dhcp-utils.c +++ b/src/core/dhcp/tests/test-dhcp-utils.c @@ -9,12 +9,12 @@ #include #include -#include "nm-glib-aux/nm-dedup-multi.h" +#include "libnm-glib-aux/nm-dedup-multi.h" #include "nm-utils.h" #include "dhcp/nm-dhcp-utils.h" #include "dhcp/nm-dhcp-options.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-test-utils-core.h" diff --git a/src/core/dns/nm-dns-dnsmasq.c b/src/core/dns/nm-dns-dnsmasq.c index dcff98e9..126e0a21 100644 --- a/src/core/dns/nm-dns-dnsmasq.c +++ b/src/core/dns/nm-dns-dnsmasq.c @@ -15,9 +15,9 @@ #include #include -#include "nm-glib-aux/nm-dbus-aux.h" -#include "nm-core-internal.h" -#include "platform/nm-platform.h" +#include "libnm-glib-aux/nm-dbus-aux.h" +#include "libnm-core-intern/nm-core-internal.h" +#include "libnm-platform/nm-platform.h" #include "nm-utils.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" diff --git a/src/core/dns/nm-dns-dnsmasq.h b/src/core/dns/nm-dns-dnsmasq.h index bd6d4c60..575b0b26 100644 --- a/src/core/dns/nm-dns-dnsmasq.h +++ b/src/core/dns/nm-dns-dnsmasq.h @@ -7,6 +7,7 @@ #define __NETWORKMANAGER_DNS_DNSMASQ_H__ #include "nm-dns-plugin.h" +#include "nm-dns-manager.h" #define NM_TYPE_DNS_DNSMASQ (nm_dns_dnsmasq_get_type()) #define NM_DNS_DNSMASQ(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DNS_DNSMASQ, NMDnsDnsmasq)) diff --git a/src/core/dns/nm-dns-manager.c b/src/core/dns/nm-dns-manager.c index f318b9b8..4c498c82 100644 --- a/src/core/dns/nm-dns-manager.c +++ b/src/core/dns/nm-dns-manager.c @@ -22,8 +22,9 @@ #include #endif +#include "libnm-glib-aux/nm-str-buf.h" #include "nm-utils.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-dns-manager.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" @@ -83,13 +84,10 @@ typedef struct { GHashTable *configs_dict; CList configs_lst_head; - CList ip_configs_lst_head; + CList ip_config_lst_head; GVariant *config_variant; - NMDnsConfigIPData *best_ip_config_4; - NMDnsConfigIPData *best_ip_config_6; - - bool ip_configs_lst_need_sort : 1; + bool ip_config_lst_need_sort : 1; bool configs_lst_need_sort : 1; @@ -266,9 +264,11 @@ _dns_config_ip_data_new(NMDnsConfigData * data, .ip_config_type = ip_config_type, }; c_list_link_tail(&data->data_lst_head, &ip_data->data_lst); - c_list_link_tail(&NM_DNS_MANAGER_GET_PRIVATE(data->self)->ip_configs_lst_head, + c_list_link_tail(&NM_DNS_MANAGER_GET_PRIVATE(data->self)->ip_config_lst_head, &ip_data->ip_config_lst); + /* We also need to set priv->ip_config_lst_need_sort, but the caller will do that! */ + g_signal_connect(ip_config, NM_IS_IP4_CONFIG(ip_config) ? "notify::" NM_IP4_CONFIG_DNS_PRIORITY : "notify::" NM_IP6_CONFIG_DNS_PRIORITY, @@ -325,7 +325,7 @@ _dns_config_data_free(NMDnsConfigData *data) } static int -_mgr_get_ip_configs_lst_cmp(const CList *a_lst, const CList *b_lst, const void *user_data) +_mgr_get_ip_config_lst_cmp(const CList *a_lst, const CList *b_lst, const void *user_data) { const NMDnsConfigIPData *a = c_list_entry(a_lst, NMDnsConfigIPData, ip_config_lst); const NMDnsConfigIPData *b = c_list_entry(b_lst, NMDnsConfigIPData, ip_config_lst); @@ -341,16 +341,16 @@ _mgr_get_ip_configs_lst_cmp(const CList *a_lst, const CList *b_lst, const void * } static CList * -_mgr_get_ip_configs_lst_head(NMDnsManager *self) +_mgr_get_ip_config_lst_head(NMDnsManager *self) { NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE(self); - if (G_UNLIKELY(priv->ip_configs_lst_need_sort)) { - priv->ip_configs_lst_need_sort = FALSE; - c_list_sort(&priv->ip_configs_lst_head, _mgr_get_ip_configs_lst_cmp, NULL); + if (G_UNLIKELY(priv->ip_config_lst_need_sort)) { + priv->ip_config_lst_need_sort = FALSE; + c_list_sort(&priv->ip_config_lst_head, _mgr_get_ip_config_lst_cmp, NULL); } - return &priv->ip_configs_lst_head; + return &priv->ip_config_lst_head; } static int @@ -378,11 +378,11 @@ _mgr_get_configs_lst_head(NMDnsManager *self) /*****************************************************************************/ -gboolean -nm_dns_manager_has_systemd_resolved(NMDnsManager *self) +NMDnsPlugin * +nm_dns_manager_get_systemd_resolved(NMDnsManager *self) { - NMDnsManagerPrivate * priv; - NMDnsSystemdResolved *plugin = NULL; + NMDnsManagerPrivate *priv; + NMDnsPlugin * plugin = NULL; g_return_val_if_fail(NM_IS_DNS_MANAGER(self), FALSE); @@ -390,11 +390,14 @@ nm_dns_manager_has_systemd_resolved(NMDnsManager *self) if (priv->sd_resolve_plugin) { nm_assert(!NM_IS_DNS_SYSTEMD_RESOLVED(priv->plugin)); - plugin = NM_DNS_SYSTEMD_RESOLVED(priv->sd_resolve_plugin); + plugin = priv->sd_resolve_plugin; } else if (NM_IS_DNS_SYSTEMD_RESOLVED(priv->plugin)) - plugin = NM_DNS_SYSTEMD_RESOLVED(priv->plugin); + plugin = priv->plugin; - return plugin && nm_dns_systemd_resolved_is_running(plugin); + if (plugin && nm_dns_systemd_resolved_is_running(NM_DNS_SYSTEMD_RESOLVED(plugin))) + return plugin; + + return NULL; } /*****************************************************************************/ @@ -1104,7 +1107,7 @@ update_resolv_conf(NMDnsManager * self, } static void -compute_hash(NMDnsManager *self, const NMGlobalDnsConfig *global, guint8 buffer[HASH_LEN]) +compute_hash(NMDnsManager *self, const NMGlobalDnsConfig *global, guint8 buffer[static HASH_LEN]) { nm_auto_free_checksum GChecksum *sum = NULL; NMDnsConfigIPData * ip_data; @@ -1119,7 +1122,7 @@ compute_hash(NMDnsManager *self, const NMGlobalDnsConfig *global, guint8 buffer[ /* FIXME(ip-config-checksum): this relies on the fact that an IP * configuration without DNS parameters gives a zero checksum. */ - head = _mgr_get_ip_configs_lst_head(self); + head = _mgr_get_ip_config_lst_head(self); c_list_for_each_entry (ip_data, head, ip_config_lst) nm_ip_config_hash(ip_data->ip_config, sum, TRUE); } @@ -1169,27 +1172,26 @@ merge_global_dns_config(NMResolvConfData *rc, NMGlobalDnsConfig *global_conf) } static const char * -get_nameserver_list(const NMIPConfig *config, GString **str) +get_nameserver_list(const NMIPConfig *config, NMStrBuf *tmp_strbuf) { - guint num, i; char buf[NM_UTILS_INET_ADDRSTRLEN]; int addr_family; + guint num; + guint i; - if (*str) - g_string_truncate(*str, 0); - else - *str = g_string_sized_new(64); + nm_str_buf_reset(tmp_strbuf); addr_family = nm_ip_config_get_addr_family(config); num = nm_ip_config_get_num_nameservers(config); for (i = 0; i < num; i++) { nm_utils_inet_ntop(addr_family, nm_ip_config_get_nameserver(config, i), buf); if (i > 0) - g_string_append_c(*str, ' '); - g_string_append(*str, buf); + nm_str_buf_append_c(tmp_strbuf, ' '); + nm_str_buf_append(tmp_strbuf, buf); } - return (*str)->str; + nm_str_buf_maybe_expand(tmp_strbuf, 1, FALSE); + return nm_str_buf_get_str(tmp_strbuf); } static char ** @@ -1224,13 +1226,14 @@ _collect_resolv_conf_data(NMDnsManager * self, if (global_config) merge_global_dns_config(&rc, global_config); else { - nm_auto_free_gstring GString *tmp_gstring = NULL; - int prio, first_prio = 0; - const NMDnsConfigIPData * ip_data; - const CList * head; - gboolean is_first = TRUE; - - head = _mgr_get_ip_configs_lst_head(self); + nm_auto_str_buf NMStrBuf tmp_strbuf = NM_STR_BUF_INIT(0, FALSE); + int prio; + int first_prio = 0; + const NMDnsConfigIPData *ip_data; + const CList * head; + gboolean is_first = TRUE; + + head = _mgr_get_ip_config_lst_head(self); c_list_for_each_entry (ip_data, head, ip_config_lst) { gboolean skip = FALSE; @@ -1244,16 +1247,13 @@ _collect_resolv_conf_data(NMDnsManager * self, } else if (first_prio < 0 && first_prio != prio) skip = TRUE; - if (nm_ip_config_get_num_nameservers(ip_data->ip_config)) { - _LOGT( - "config: %8d %-7s v%c %-5d %s: %s", - prio, - _config_type_to_string(ip_data->ip_config_type), - nm_utils_addr_family_to_char(nm_ip_config_get_addr_family(ip_data->ip_config)), - ip_data->data->ifindex, - skip ? "" : "", - get_nameserver_list(ip_data->ip_config, &tmp_gstring)); - } + _LOGT("config: %8d %-7s v%c %-5d %s: %s", + prio, + _config_type_to_string(ip_data->ip_config_type), + nm_utils_addr_family_to_char(nm_ip_config_get_addr_family(ip_data->ip_config)), + ip_data->data->ifindex, + skip ? "" : "", + get_nameserver_list(ip_data->ip_config, &tmp_strbuf)); if (!skip) merge_one_ip_config(&rc, ip_data->data->ifindex, ip_data->ip_config); @@ -1394,7 +1394,7 @@ _mgr_configs_data_construct(NMDnsManager *self) CList * head; int prev_priority = G_MININT; - head = _mgr_get_ip_configs_lst_head(self); + head = _mgr_get_ip_config_lst_head(self); #if NM_MORE_ASSERTS /* we call _mgr_configs_data_clear() at the end of update. We @@ -1611,7 +1611,7 @@ _mgr_configs_data_clear(NMDnsManager *self) NMDnsConfigIPData *ip_data; CList * head; - head = _mgr_get_ip_configs_lst_head(self); + head = _mgr_get_ip_config_lst_head(self); c_list_for_each_entry (ip_data, head, ip_config_lst) { nm_clear_g_free(&ip_data->domains.search); nm_clear_pointer(&ip_data->domains.reverse, g_strfreev); @@ -1624,7 +1624,7 @@ _mgr_configs_data_clear(NMDnsManager *self) /*****************************************************************************/ static gboolean -update_dns(NMDnsManager *self, gboolean no_caching, GError **error) +update_dns(NMDnsManager *self, gboolean no_caching, gboolean force_emit, GError **error) { NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE(self); const char * nis_domain = NULL; @@ -1680,7 +1680,7 @@ update_dns(NMDnsManager *self, gboolean no_caching, GError **error) if (priv->sd_resolve_plugin) { nm_dns_plugin_update(priv->sd_resolve_plugin, global_config, - _mgr_get_ip_configs_lst_head(self), + _mgr_get_ip_config_lst_head(self), priv->hostname, NULL); } @@ -1702,7 +1702,7 @@ update_dns(NMDnsManager *self, gboolean no_caching, GError **error) _LOGD("update-dns: updating plugin %s", plugin_name); if (!nm_dns_plugin_update(plugin, global_config, - _mgr_get_ip_configs_lst_head(self), + _mgr_get_ip_config_lst_head(self), priv->hostname, &plugin_error)) { _LOGW("update-dns: plugin %s update failed: %s", plugin_name, plugin_error->message); @@ -1815,8 +1815,8 @@ plugin_skip:; NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED); } - /* signal that resolv.conf was changed */ - if (do_update && result == SR_SUCCESS) + /* signal that DNS resolution configs were changed */ + if ((do_update || caching || force_emit) && result == SR_SUCCESS) g_signal_emit(self, signals[CONFIG_CHANGED], 0); nm_clear_pointer(&priv->config_variant, g_variant_unref); @@ -1839,7 +1839,7 @@ _ip_config_dns_priority_changed(gpointer config, GParamSpec *pspec, NMDnsConfigI { _ASSERT_dns_config_ip_data(ip_data); - NM_DNS_MANAGER_GET_PRIVATE(ip_data->data->self)->ip_configs_lst_need_sort = TRUE; + NM_DNS_MANAGER_GET_PRIVATE(ip_data->data->self)->ip_config_lst_need_sort = TRUE; } gboolean @@ -1851,7 +1851,6 @@ nm_dns_manager_set_ip_config(NMDnsManager * self, NMDnsConfigIPData * ip_data; NMDnsConfigData * data; int ifindex; - NMDnsConfigIPData ** p_best; g_return_val_if_fail(NM_IS_DNS_MANAGER(self), FALSE); g_return_val_if_fail(NM_IS_IP_CONFIG(ip_config), FALSE); @@ -1870,10 +1869,6 @@ nm_dns_manager_set_ip_config(NMDnsManager * self, if (ip_config_type == NM_DNS_IP_CONFIG_TYPE_REMOVED) { if (!ip_data) return FALSE; - if (priv->best_ip_config_4 == ip_data) - priv->best_ip_config_4 = NULL; - if (priv->best_ip_config_6 == ip_data) - priv->best_ip_config_6 = NULL; /* deleting a config doesn't invalidate the configs' sort order. */ _dns_config_ip_data_free(ip_data); if (c_list_is_empty(&data->data_lst_head)) @@ -1904,27 +1899,13 @@ nm_dns_manager_set_ip_config(NMDnsManager * self, else ip_data->ip_config_type = ip_config_type; - priv->ip_configs_lst_need_sort = TRUE; - - p_best = NM_IS_IP4_CONFIG(ip_config) ? &priv->best_ip_config_4 : &priv->best_ip_config_6; - - if (ip_config_type == NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE) { - /* Only one best-device per IP version is allowed */ - if (*p_best != ip_data) { - if (*p_best) - (*p_best)->ip_config_type = NM_DNS_IP_CONFIG_TYPE_DEFAULT; - *p_best = ip_data; - } - } else { - if (*p_best == ip_data) - *p_best = NULL; - } + priv->ip_config_lst_need_sort = TRUE; changed: if (!priv->updates_queue) { gs_free_error GError *error = NULL; - if (!update_dns(self, FALSE, &error)) + if (!update_dns(self, FALSE, FALSE, &error)) _LOGW("could not commit DNS changes: %s", error->message); } @@ -1965,7 +1946,7 @@ nm_dns_manager_set_hostname(NMDnsManager *self, const char *hostname, gboolean s if (!priv->updates_queue) { gs_free_error GError *error = NULL; - if (!update_dns(self, FALSE, &error)) + if (!update_dns(self, FALSE, FALSE, &error)) _LOGW("could not commit DNS changes: %s", error->message); } } @@ -2012,7 +1993,7 @@ nm_dns_manager_end_updates(NMDnsManager *self, const char *func) /* Commit all the outstanding changes */ _LOGD("(%s): committing DNS changes (%d)", func, priv->updates_queue); - if (!update_dns(self, FALSE, &error)) + if (!update_dns(self, FALSE, FALSE, &error)) _LOGW("could not commit DNS changes: %s", error->message); memset(priv->prev_hash, 0, sizeof(priv->prev_hash)); @@ -2038,7 +2019,7 @@ nm_dns_manager_stop(NMDnsManager *self) if (priv->dns_touched && priv->plugin && NM_IS_DNS_DNSMASQ(priv->plugin)) { gs_free_error GError *error = NULL; - if (!update_dns(self, TRUE, &error)) + if (!update_dns(self, TRUE, FALSE, &error)) _LOGW("could not commit DNS changes on shutdown: %s", error->message); priv->dns_touched = FALSE; @@ -2363,7 +2344,7 @@ config_changed_cb(NMConfig * config, | NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG)) { gs_free_error GError *error = NULL; - if (!update_dns(self, FALSE, &error)) + if (!update_dns(self, FALSE, TRUE, &error)) _LOGW("could not commit DNS changes: %s", error->message); } } @@ -2440,7 +2421,7 @@ _get_config_variant(NMDnsManager *self) g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}")); - head = _mgr_get_ip_configs_lst_head(self); + head = _mgr_get_ip_config_lst_head(self); c_list_for_each_entry (ip_data, head, ip_config_lst) { const NMIPConfig *ip_config = ip_data->ip_config; GVariantBuilder entry_builder; @@ -2546,13 +2527,13 @@ nm_dns_manager_init(NMDnsManager *self) _LOGT("creating..."); c_list_init(&priv->configs_lst_head); - c_list_init(&priv->ip_configs_lst_head); + c_list_init(&priv->ip_config_lst_head); priv->config = g_object_ref(nm_config_get()); G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(NMDnsConfigData, ifindex) == 0); priv->configs_dict = g_hash_table_new_full(nm_pint_hash, - nm_pint_equals, + nm_pint_equal, (GDestroyNotify) _dns_config_data_free, NULL); @@ -2584,10 +2565,7 @@ dispose(GObject *object) g_clear_object(&priv->sd_resolve_plugin); _clear_plugin(self); - priv->best_ip_config_4 = NULL; - priv->best_ip_config_6 = NULL; - - c_list_for_each_entry_safe (ip_data, ip_data_safe, &priv->ip_configs_lst_head, ip_config_lst) + c_list_for_each_entry_safe (ip_data, ip_data_safe, &priv->ip_config_lst_head, ip_config_lst) _dns_config_ip_data_free(ip_data); nm_clear_pointer(&priv->configs_dict, g_hash_table_destroy); @@ -2618,13 +2596,13 @@ static const NMDBusInterfaceInfoExtended interface_info_dns_manager = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DNS_MANAGER, .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Mode", "s", NM_DNS_MANAGER_MODE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("RcManager", - "s", - NM_DNS_MANAGER_RC_MANAGER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Configuration", - "aa{sv}", - NM_DNS_MANAGER_CONFIGURATION), ), ), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Mode", "s", NM_DNS_MANAGER_MODE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("RcManager", + "s", + NM_DNS_MANAGER_RC_MANAGER), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Configuration", + "aa{sv}", + NM_DNS_MANAGER_CONFIGURATION), ), ), }; static void diff --git a/src/core/dns/nm-dns-manager.h b/src/core/dns/nm-dns-manager.h index 937ba62a..501085f7 100644 --- a/src/core/dns/nm-dns-manager.h +++ b/src/core/dns/nm-dns-manager.h @@ -11,6 +11,7 @@ #include "nm-ip4-config.h" #include "nm-ip6-config.h" #include "nm-setting-connection.h" +#include "nm-dns-plugin.h" typedef enum { NM_DNS_IP_CONFIG_TYPE_REMOVED = -1, @@ -148,7 +149,7 @@ typedef enum { void nm_dns_manager_stop(NMDnsManager *self); -gboolean nm_dns_manager_has_systemd_resolved(NMDnsManager *self); +NMDnsPlugin *nm_dns_manager_get_systemd_resolved(NMDnsManager *self); /*****************************************************************************/ diff --git a/src/core/dns/nm-dns-plugin.c b/src/core/dns/nm-dns-plugin.c index 74d4eb2b..e5035f06 100644 --- a/src/core/dns/nm-dns-plugin.c +++ b/src/core/dns/nm-dns-plugin.c @@ -12,7 +12,7 @@ #include #include -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "NetworkManagerUtils.h" /*****************************************************************************/ diff --git a/src/core/dns/nm-dns-plugin.h b/src/core/dns/nm-dns-plugin.h index 644d01e5..82ca7d6b 100644 --- a/src/core/dns/nm-dns-plugin.h +++ b/src/core/dns/nm-dns-plugin.h @@ -6,7 +6,8 @@ #ifndef __NM_DNS_PLUGIN_H__ #define __NM_DNS_PLUGIN_H__ -#include "nm-dns-manager.h" +#include "c-list/src/c-list.h" + #include "nm-config-data.h" #define NM_TYPE_DNS_PLUGIN (nm_dns_plugin_get_type()) diff --git a/src/core/dns/nm-dns-systemd-resolved.c b/src/core/dns/nm-dns-systemd-resolved.c index f6e116f3..4b8c4f94 100644 --- a/src/core/dns/nm-dns-systemd-resolved.c +++ b/src/core/dns/nm-dns-systemd-resolved.c @@ -16,10 +16,10 @@ #include #include -#include "nm-glib-aux/nm-c-list.h" -#include "nm-glib-aux/nm-dbus-aux.h" -#include "nm-core-internal.h" -#include "platform/nm-platform.h" +#include "libnm-glib-aux/nm-c-list.h" +#include "libnm-glib-aux/nm-dbus-aux.h" +#include "libnm-core-intern/nm-core-internal.h" +#include "libnm-platform/nm-platform.h" #include "nm-utils.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" @@ -28,7 +28,7 @@ #include "nm-setting-connection.h" #include "devices/nm-device.h" #include "NetworkManagerUtils.h" -#include "nm-std-aux/nm-dbus-compat.h" +#include "libnm-std-aux/nm-dbus-compat.h" #define SYSTEMD_RESOLVED_DBUS_SERVICE "org.freedesktop.resolve1" #define SYSTEMD_RESOLVED_MANAGER_IFACE "org.freedesktop.resolve1.Manager" @@ -52,19 +52,40 @@ typedef struct { int ifindex; } RequestItem; +struct _NMDnsSystemdResolvedResolveHandle { + CList handle_lst; + NMDnsSystemdResolved *self; + GSource * timeout_source; + GCancellable * handle_cancellable; + gpointer callback_user_data; + guint timeout_msec; + bool is_failing_on_idle; + union { + struct { + NMDnsSystemdResolvedResolveAddressCallback callback; + guint64 flags; + int ifindex; + int addr_family; + NMIPAddr addr; + } r_address; + }; +}; + /*****************************************************************************/ typedef struct { GDBusConnection *dbus_connection; GHashTable * dirty_interfaces; GCancellable * cancellable; + GSource * try_start_timeout_source; CList request_queue_lst_head; + char * dbus_owner; + CList handle_lst_head; guint name_owner_changed_id; bool send_updates_warn_ratelimited : 1; bool try_start_blocked : 1; - bool dbus_has_owner : 1; bool dbus_initied : 1; - bool request_queue_to_send : 1; + bool send_updates_waiting : 1; NMTernary has_link_default_route : 3; } NMDnsSystemdResolvedPrivate; @@ -84,9 +105,39 @@ G_DEFINE_TYPE(NMDnsSystemdResolved, nm_dns_systemd_resolved, NM_TYPE_DNS_PLUGIN) /*****************************************************************************/ -#define _NMLOG_DOMAIN LOGD_DNS +#define _NMLOG_DOMAIN LOGD_DNS +#define _NMLOG_PREFIX_NAME "dns-sd-resolved" + #define _NMLOG(level, ...) \ - __NMLOG_DEFAULT_WITH_ADDR(level, _NMLOG_DOMAIN, "dns-sd-resolved", __VA_ARGS__) + __NMLOG_DEFAULT_WITH_ADDR(level, _NMLOG_DOMAIN, _NMLOG_PREFIX_NAME, __VA_ARGS__) + +#define _NMLOG2(level, handle, ...) \ + G_STMT_START \ + { \ + const NMLogLevel _level = (level); \ + \ + if (nm_logging_enabled(_level, (_NMLOG_DOMAIN))) { \ + const NMDnsSystemdResolvedResolveHandle *const _handle = (handle); \ + \ + _nm_log(_level, \ + (_NMLOG_DOMAIN), \ + 0, \ + NULL, \ + NULL, \ + "%s[" NM_HASH_OBFUSCATE_PTR_FMT "]: request[" NM_HASH_OBFUSCATE_PTR_FMT \ + "]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + _NMLOG_PREFIX_NAME, \ + NM_HASH_OBFUSCATE_PTR(self), \ + NM_HASH_OBFUSCATE_PTR(_handle) _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } \ + G_STMT_END + +/*****************************************************************************/ + +static void _resolve_complete_error(NMDnsSystemdResolvedResolveHandle *handle, GError *error); + +static void _resolve_start(NMDnsSystemdResolved *self, NMDnsSystemdResolvedResolveHandle *handle); /*****************************************************************************/ @@ -201,10 +252,7 @@ update_add_ip_config(NMDnsSystemdResolved *self, g_variant_builder_add(dns, "i", addr_family); g_variant_builder_add_value( dns, - g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, - nm_ip_config_get_nameserver(data->ip_config, i), - addr_size, - 1)); + nm_g_variant_new_ay(nm_ip_config_get_nameserver(data->ip_config, i), addr_size)); g_variant_builder_close(dns); has_config = TRUE; } @@ -326,57 +374,105 @@ prepare_one_interface(NMDnsSystemdResolved *self, InterfaceConfig *ic) return has_config; } -static void -send_updates(NMDnsSystemdResolved *self) +static gboolean +_ensure_resolved_running_timeout(gpointer user_data) { - NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); - RequestItem * request_item; + NMDnsSystemdResolved * self = user_data; + NMDnsSystemdResolvedPrivate * priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); + NMDnsSystemdResolvedResolveHandle *handle; - if (!priv->request_queue_to_send) { - /* nothing to do. */ - return; - } + nm_clear_g_source_inst(&priv->try_start_timeout_source); - if (!priv->dbus_initied) { - _LOGT("send-updates: D-Bus connection not ready"); - return; + _LOGT("timeout waiting to D-Bus activate systemd-resolved. Systemd-resolved won't be " + "used until it appears on the bus"); + +again: + c_list_for_each_entry (handle, &priv->handle_lst_head, handle_lst) { + gs_free_error GError *error = NULL; + + if (handle->is_failing_on_idle) + continue; + + nm_utils_error_set_literal(&error, + NM_UTILS_ERROR_NOT_READY, + "timeout waiting for systemd-resolved to start"); + _resolve_complete_error(handle, error); + goto again; } - if (!priv->dbus_has_owner) { + return G_SOURCE_CONTINUE; +} + +static NMTernary +ensure_resolved_running(NMDnsSystemdResolved *self) +{ + NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); + + if (!priv->dbus_initied) + return NM_TERNARY_DEFAULT; + + if (!priv->dbus_owner) { if (priv->try_start_blocked) { /* we have no name owner and we already tried poking the service to * autostart. */ - _LOGT("send-updates: no name owner"); - return; + return NM_TERNARY_FALSE; } - _LOGT("send-updates: no name owner. Try start service..."); + _LOGT("try D-Bus activating systemd-resolved..."); priv->try_start_blocked = TRUE; + priv->try_start_timeout_source = + nm_g_source_attach(nm_g_timeout_source_new(4000, + G_PRIORITY_DEFAULT, + _ensure_resolved_running_timeout, + self, + NULL), + NULL); + nm_dbus_connection_call_start_service_by_name(priv->dbus_connection, SYSTEMD_RESOLVED_DBUS_SERVICE, -1, NULL, NULL, NULL); + return NM_TERNARY_DEFAULT; + } + + return NM_TERNARY_TRUE; +} + +static void +send_updates(NMDnsSystemdResolved *self) +{ + NMDnsSystemdResolvedPrivate * priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); + RequestItem * request_item; + NMDnsSystemdResolvedResolveHandle *handle; + + if (!priv->send_updates_waiting) { + /* nothing to do. */ return; } + if (ensure_resolved_running(self) != NM_TERNARY_TRUE) + return; + nm_clear_g_cancellable(&priv->cancellable); if (c_list_is_empty(&priv->request_queue_lst_head)) { _LOGT("send-updates: no requests to send"); - priv->request_queue_to_send = FALSE; - return; + priv->send_updates_waiting = FALSE; + goto start_resolve; } - _LOGT("send-updates: start %lu requests", c_list_length(&priv->request_queue_lst_head)); - priv->cancellable = g_cancellable_new(); - priv->request_queue_to_send = FALSE; + priv->send_updates_waiting = FALSE; + + _LOGT("send-updates: start %lu requests", c_list_length(&priv->request_queue_lst_head)); c_list_for_each_entry (request_item, &priv->request_queue_lst_head, request_queue_lst) { + gs_free char *ss = NULL; + if (request_item->operation == DBUS_OP_SET_LINK_DEFAULT_ROUTE && priv->has_link_default_route == NM_TERNARY_FALSE) { /* The "SetLinkDefaultRoute" API is only supported since v240. @@ -386,16 +482,12 @@ send_updates(NMDnsSystemdResolved *self) continue; } - /* Above we explicitly call "StartServiceByName" trying to avoid D-Bus activating systmd-resolved - * multiple times. There is still a race, were we might hit this line although actually - * the service just quit this very moment. In that case, we would try to D-Bus activate the - * service multiple times during each call (something we wanted to avoid). - * - * But this is hard to avoid, because we'd have to check the error failure to detect the reason - * and retry. The race is not critical, because at worst it results in logging a warning - * about failure to start systemd.resolved. */ + _LOGT("send-updates: %s ( %s )", + request_item->operation, + (ss = g_variant_print(request_item->argument, FALSE))); + g_dbus_connection_call(priv->dbus_connection, - SYSTEMD_RESOLVED_DBUS_SERVICE, + priv->dbus_owner, SYSTEMD_RESOLVED_DBUS_PATH, SYSTEMD_RESOLVED_MANAGER_IFACE, request_item->operation, @@ -407,6 +499,15 @@ send_updates(NMDnsSystemdResolved *self) call_done, request_item); } + +start_resolve: + c_list_for_each_entry (handle, &priv->handle_lst_head, handle_lst) { + if (handle->handle_cancellable) + continue; + if (handle->is_failing_on_idle) + continue; + _resolve_start(self, handle); + } } static gboolean @@ -479,7 +580,7 @@ update(NMDnsPlugin * plugin, } } - priv->request_queue_to_send = TRUE; + priv->send_updates_waiting = TRUE; send_updates(self); return TRUE; } @@ -498,10 +599,13 @@ name_owner_changed(NMDnsSystemdResolved *self, const char *owner) else _LOGT("D-Bus name for systemd-resolved has owner %s", owner); - priv->dbus_has_owner = !!owner; + nm_clear_g_source_inst(&priv->try_start_timeout_source); + + nm_utils_strdup_reset(&priv->dbus_owner, owner); + if (owner) { - priv->try_start_blocked = FALSE; - priv->request_queue_to_send = TRUE; + priv->try_start_blocked = FALSE; + priv->send_updates_waiting = TRUE; } else priv->has_link_default_route = NM_TERNARY_DEFAULT; @@ -531,6 +635,7 @@ name_owner_changed_cb(GDBusConnection *connection, * returns. */ priv->dbus_initied = TRUE; nm_clear_g_cancellable(&priv->cancellable); + _LOGT("D-Bus connection is ready"); } name_owner_changed(user_data, new_owner); @@ -551,6 +656,7 @@ get_name_owner_cb(const char *name_owner, GError *error, gpointer user_data) g_clear_object(&priv->cancellable); priv->dbus_initied = TRUE; + _LOGT("D-Bus connection is ready"); name_owner_changed(self, name_owner); } @@ -566,7 +672,253 @@ nm_dns_systemd_resolved_is_running(NMDnsSystemdResolved *self) priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); - return priv->dbus_initied && (priv->dbus_has_owner || !priv->try_start_blocked); + return priv->dbus_initied && (priv->dbus_owner || !priv->try_start_blocked); +} + +/*****************************************************************************/ + +static void +_resolve_complete(NMDnsSystemdResolvedResolveHandle * handle, + const NMDnsSystemdResolvedAddressResult *names, + guint names_len, + guint64 flags, + GError * error) +{ + NMDnsSystemdResolved * self; + NMDnsSystemdResolvedPrivate *priv; + + g_return_if_fail(handle && NM_IS_DNS_SYSTEMD_RESOLVED(handle->self)); + + self = handle->self; + priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); + + nm_assert(c_list_contains(&priv->handle_lst_head, &handle->handle_lst)); + + c_list_unlink(&handle->handle_lst); + + handle->self = NULL; + + nm_clear_g_source_inst(&handle->timeout_source); + nm_clear_g_cancellable(&handle->handle_cancellable); + + handle->r_address + .callback(self, handle, names, names_len, flags, error, handle->callback_user_data); + + nm_g_slice_free(handle); +} + +static void +_resolve_complete_error(NMDnsSystemdResolvedResolveHandle *handle, GError *error) +{ + NMDnsSystemdResolved *self = handle->self; + + nm_assert(error); + _LOG2T(handle, "request failed: %s", error->message); + _resolve_complete(handle, NULL, 0, 0, error); +} + +static void +_resolve_handle_call_cb(GObject *source, GAsyncResult *result, gpointer user_data) +{ + gs_unref_variant GVariant *v = NULL; + gs_free_error GError * error = NULL; + NMDnsSystemdResolvedResolveHandle *handle; + NMDnsSystemdResolved * self; + GVariantIter * v_names_iter; + guint64 v_flags; + int v_ifindex; + char * v_name; + gs_unref_array GArray *v_names = NULL; + gs_free char * ss = NULL; + + v = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error); + if (nm_utils_error_is_cancelled(error)) + return; + + handle = user_data; + self = handle->self; + + if (error) { + gs_free char *remote_error = NULL; + + remote_error = g_dbus_error_get_remote_error(error); + if (nm_streq0(remote_error, "org.freedesktop.DBus.Error.ServiceUnknown")) { + _LOG2T(handle, "request failed due to service stop. Retry"); + g_clear_object(&handle->handle_cancellable); + _resolve_start(self, handle); + return; + } + + _resolve_complete_error(handle, error); + return; + } + + _LOG2T(handle, "request completed: %s", (ss = g_variant_print(v, FALSE))); + + v_names = g_array_new(FALSE, FALSE, sizeof(NMDnsSystemdResolvedAddressResult)); + + G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(NMDnsSystemdResolvedAddressResult, name) == 0); + g_array_set_clear_func(v_names, nm_indirect_g_free); + + g_variant_get(v, "(a(is)t)", &v_names_iter, &v_flags); + + while (g_variant_iter_next(v_names_iter, "(is)", &v_ifindex, &v_name)) { + NMDnsSystemdResolvedAddressResult *n; + + n = nm_g_array_append_new(v_names, NMDnsSystemdResolvedAddressResult); + *n = (NMDnsSystemdResolvedAddressResult){ + .name = g_steal_pointer(&v_name), + .ifindex = v_ifindex, + }; + } + g_variant_iter_free(v_names_iter); + + _resolve_complete(handle, + &g_array_index(v_names, NMDnsSystemdResolvedAddressResult, 0), + v_names->len, + v_flags, + NULL); +} + +static gboolean +_resolve_failing_on_idle(gpointer user_data) +{ + NMDnsSystemdResolvedResolveHandle *handle = user_data; + gs_free_error GError *error = NULL; + + nm_utils_error_set_literal(&error, + NM_UTILS_ERROR_NOT_READY, + "systemd-resolved is not available"); + _resolve_complete_error(handle, error); + return G_SOURCE_CONTINUE; +} + +static gboolean +_resolve_handle_timeout(gpointer user_data) +{ + NMDnsSystemdResolvedResolveHandle *handle = user_data; + gs_free_error GError *error = NULL; + + nm_utils_error_set_literal(&error, NM_UTILS_ERROR_UNKNOWN, "timeout for request"); + _resolve_complete_error(handle, error); + return G_SOURCE_CONTINUE; +} + +static void +_resolve_start(NMDnsSystemdResolved *self, NMDnsSystemdResolvedResolveHandle *handle) +{ + NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); + NMTernary is_running; + + nm_assert(!handle->handle_cancellable); + nm_assert(!handle->is_failing_on_idle); + + is_running = ensure_resolved_running(self); + + if (is_running == NM_TERNARY_FALSE) { + /* Systemd-resolved is not is_running and shall not be used. We fail + * on an idle handler. */ + _LOG2T(handle, "systemd-resolved not running. Failing on idle..."); + nm_assert(!handle->timeout_source); + handle->is_failing_on_idle = TRUE; + handle->timeout_source = nm_g_source_attach( + nm_g_idle_source_new(G_PRIORITY_DEFAULT, _resolve_failing_on_idle, handle, NULL), + NULL); + return; + } + + if (!handle->timeout_source) { + handle->timeout_source = nm_g_source_attach(nm_g_timeout_source_new(handle->timeout_msec, + G_PRIORITY_DEFAULT, + _resolve_handle_timeout, + handle, + NULL), + NULL); + } + + if (is_running == NM_TERNARY_DEFAULT) { + /* we are D-Bus activating systemd-resolved. Wait for it... */ + _LOG2T(handle, "waiting for systemd-resolved to start..."); + return; + } + + nm_assert(!priv->send_updates_waiting); + + handle->handle_cancellable = g_cancellable_new(); + + _LOG2T(handle, "start D-Bus request..."); + g_dbus_connection_call(priv->dbus_connection, + priv->dbus_owner, + SYSTEMD_RESOLVED_DBUS_PATH, + SYSTEMD_RESOLVED_MANAGER_IFACE, + "ResolveAddress", + g_variant_new("(ii@ayt)", + handle->r_address.ifindex, + handle->r_address.addr_family, + nm_g_variant_new_ay_inaddr(handle->r_address.addr_family, + &handle->r_address.addr), + handle->r_address.flags), + G_VARIANT_TYPE("(a(is)t)"), + G_DBUS_CALL_FLAGS_NONE, + handle->timeout_msec + 1000u, + handle->handle_cancellable, + _resolve_handle_call_cb, + handle); +} + +NMDnsSystemdResolvedResolveHandle * +nm_dns_systemd_resolved_resolve_address(NMDnsSystemdResolved * self, + int ifindex, + int addr_family, + const NMIPAddr * addr, + guint64 flags, + guint timeout_msec, + NMDnsSystemdResolvedResolveAddressCallback callback, + gpointer user_data) +{ + NMDnsSystemdResolvedPrivate * priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); + NMDnsSystemdResolvedResolveHandle *handle; + char addr_str[NM_UTILS_INET_ADDRSTRLEN]; + + g_return_val_if_fail(NM_IS_DNS_SYSTEMD_RESOLVED(self), NULL); + nm_assert_addr_family(addr_family); + nm_assert(addr); + nm_assert(callback); + + handle = g_slice_new(NMDnsSystemdResolvedResolveHandle); + *handle = (NMDnsSystemdResolvedResolveHandle){ + .self = self, + .timeout_msec = timeout_msec, + .callback_user_data = user_data, + .r_address = + { + .ifindex = ifindex, + .addr_family = addr_family, + .addr = *addr, + .flags = flags, + .callback = callback, + }, + }; + c_list_link_tail(&priv->handle_lst_head, &handle->handle_lst); + + _LOG2T(handle, + "resolve-address(ifindex=%d, %s, flags=%" G_GINT64_MODIFIER "x): new request", + handle->r_address.ifindex, + nm_utils_inet_ntop(handle->r_address.addr_family, &handle->r_address.addr, addr_str), + handle->r_address.flags); + + _resolve_start(self, handle); + + return handle; +} + +void +nm_dns_systemd_resolved_resolve_cancel(NMDnsSystemdResolvedResolveHandle *handle) +{ + gs_free_error GError *error = NULL; + + nm_utils_error_set_cancelled(&error, FALSE, "NMDnsSystemdResolved"); + _resolve_complete_error(handle, error); } /*****************************************************************************/ @@ -579,6 +931,7 @@ nm_dns_systemd_resolved_init(NMDnsSystemdResolved *self) priv->has_link_default_route = NM_TERNARY_DEFAULT; c_list_init(&priv->request_queue_lst_head); + c_list_init(&priv->handle_lst_head); priv->dirty_interfaces = g_hash_table_new(nm_direct_hash, NULL); priv->dbus_connection = nm_g_object_ref(NM_MAIN_DBUS_CONNECTION_GET); @@ -611,8 +964,18 @@ nm_dns_systemd_resolved_new(void) static void dispose(GObject *object) { - NMDnsSystemdResolved * self = NM_DNS_SYSTEMD_RESOLVED(object); - NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); + NMDnsSystemdResolved * self = NM_DNS_SYSTEMD_RESOLVED(object); + NMDnsSystemdResolvedPrivate * priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); + NMDnsSystemdResolvedResolveHandle *handle; + + while ((handle = c_list_first_entry(&priv->handle_lst_head, + NMDnsSystemdResolvedResolveHandle, + handle_lst))) { + gs_free_error GError *error = NULL; + + nm_utils_error_set_cancelled(&error, TRUE, "NMDnsSystemdResolved"); + _resolve_complete_error(handle, error); + } free_pending_updates(self); @@ -620,10 +983,14 @@ dispose(GObject *object) nm_clear_g_cancellable(&priv->cancellable); + nm_clear_g_source_inst(&priv->try_start_timeout_source); + g_clear_object(&priv->dbus_connection); nm_clear_pointer(&priv->dirty_interfaces, g_hash_table_unref); G_OBJECT_CLASS(nm_dns_systemd_resolved_parent_class)->dispose(object); + + nm_clear_g_free(&priv->dbus_owner); } static void diff --git a/src/core/dns/nm-dns-systemd-resolved.h b/src/core/dns/nm-dns-systemd-resolved.h index 4ab04ab4..9f973318 100644 --- a/src/core/dns/nm-dns-systemd-resolved.h +++ b/src/core/dns/nm-dns-systemd-resolved.h @@ -8,6 +8,7 @@ #define __NETWORKMANAGER_DNS_SYSTEMD_RESOLVED_H__ #include "nm-dns-plugin.h" +#include "nm-dns-manager.h" #define NM_TYPE_DNS_SYSTEMD_RESOLVED (nm_dns_systemd_resolved_get_type()) #define NM_DNS_SYSTEMD_RESOLVED(obj) \ @@ -30,4 +31,34 @@ NMDnsPlugin *nm_dns_systemd_resolved_new(void); gboolean nm_dns_systemd_resolved_is_running(NMDnsSystemdResolved *self); +/*****************************************************************************/ + +typedef struct _NMDnsSystemdResolvedResolveHandle NMDnsSystemdResolvedResolveHandle; + +typedef struct { + const char *name; + int ifindex; +} NMDnsSystemdResolvedAddressResult; + +typedef void (*NMDnsSystemdResolvedResolveAddressCallback)( + NMDnsSystemdResolved * self, + NMDnsSystemdResolvedResolveHandle * handle, + const NMDnsSystemdResolvedAddressResult *names, + guint names_len, + guint64 flags, + GError * error, + gpointer user_data); + +NMDnsSystemdResolvedResolveHandle * +nm_dns_systemd_resolved_resolve_address(NMDnsSystemdResolved * self, + int ifindex, + int addr_family, + const NMIPAddr * addr, + guint64 flags, + guint timeout_msec, + NMDnsSystemdResolvedResolveAddressCallback callback, + gpointer user_data); + +void nm_dns_systemd_resolved_resolve_cancel(NMDnsSystemdResolvedResolveHandle *handle); + #endif /* __NETWORKMANAGER_DNS_SYSTEMD_RESOLVED_H__ */ diff --git a/src/core/dnsmasq/nm-dnsmasq-manager.c b/src/core/dnsmasq/nm-dnsmasq-manager.c index 82c002b0..e8697e81 100644 --- a/src/core/dnsmasq/nm-dnsmasq-manager.c +++ b/src/core/dnsmasq/nm-dnsmasq-manager.c @@ -17,7 +17,7 @@ #include "nm-dnsmasq-utils.h" #include "nm-utils.h" #include "NetworkManagerUtils.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #define CONFDIR NMCONFDIR "/dnsmasq-shared.d" diff --git a/src/core/dnsmasq/nm-dnsmasq-utils.c b/src/core/dnsmasq/nm-dnsmasq-utils.c index ea23a78d..c2791b9e 100644 --- a/src/core/dnsmasq/nm-dnsmasq-utils.c +++ b/src/core/dnsmasq/nm-dnsmasq-utils.c @@ -5,10 +5,11 @@ #include "src/core/nm-default-daemon.h" +#include "nm-dnsmasq-utils.h" + #include -#include "nm-dnsmasq-utils.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-utils.h" gboolean diff --git a/src/core/dnsmasq/nm-dnsmasq-utils.h b/src/core/dnsmasq/nm-dnsmasq-utils.h index 57bbc4c4..1fabc9ba 100644 --- a/src/core/dnsmasq/nm-dnsmasq-utils.h +++ b/src/core/dnsmasq/nm-dnsmasq-utils.h @@ -6,7 +6,7 @@ #ifndef __NETWORKMANAGER_DNSMASQ_UTILS_H__ #define __NETWORKMANAGER_DNSMASQ_UTILS_H__ -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" gboolean nm_dnsmasq_utils_get_range(const NMPlatformIP4Address *addr, char * out_first, diff --git a/src/core/initrd/meson.build b/src/core/initrd/meson.build deleted file mode 100644 index bd590e8c..00000000 --- a/src/core/initrd/meson.build +++ /dev/null @@ -1,31 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later - -libnmi_core = static_library( - 'nmi-core', - sources: files( - 'nmi-cmdline-reader.c', - 'nmi-dt-reader.c', - 'nmi-ibft-reader.c', - ), - dependencies: core_default_dep, - c_args: daemon_c_flags, -) - -executable( - 'nm-initrd-generator', - 'nm-initrd-generator.c', - dependencies: core_default_dep, - c_args: daemon_c_flags, - link_with: [ - libNetworkManagerBase, - libnmi_core, - ], - link_args: ldflags_linker_script_binary, - link_depends: linker_script_binary, - install: true, - install_dir: nm_libexecdir, -) - -if enable_tests - subdir('tests') -endif diff --git a/src/core/initrd/nm-initrd-generator.c b/src/core/initrd/nm-initrd-generator.c deleted file mode 100644 index 18c7258a..00000000 --- a/src/core/initrd/nm-initrd-generator.c +++ /dev/null @@ -1,226 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2018 Red Hat, Inc. - */ - -#include "src/core/nm-default-daemon.h" -#include "nm-core-utils.h" -#include "nm-core-internal.h" -#include "nm-keyfile-internal.h" -#include "nm-initrd-generator.h" -#include "nm-glib-aux/nm-io-utils.h" -#include "nm-config.h" - -/*****************************************************************************/ - -#define _NMLOG(level, domain, ...) \ - nm_log((level), \ - (domain), \ - NULL, \ - NULL, \ - "initrd-generator: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__) \ - _NM_UTILS_MACRO_REST(__VA_ARGS__)) - -/*****************************************************************************/ - -static void -output_conn(gpointer key, gpointer value, gpointer user_data) -{ - const char * basename = key; - NMConnection * connection = value; - char * connections_dir = user_data; - nm_auto_unref_keyfile GKeyFile *file = NULL; - gs_free char * data = NULL; - gs_free_error GError *error = NULL; - gsize len; - - if (!nm_connection_normalize(connection, NULL, NULL, &error)) - goto err_out; - - file = nm_keyfile_write(connection, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error); - if (file == NULL) - goto err_out; - - data = g_key_file_to_data(file, &len, &error); - if (!data) - goto err_out; - - if (connections_dir) { - gs_free char *filename = NULL; - gs_free char *full_filename = NULL; - - filename = nm_keyfile_utils_create_filename(basename, TRUE); - full_filename = g_build_filename(connections_dir, filename, NULL); - - if (!nm_utils_file_set_contents(full_filename, data, len, 0600, NULL, &error)) - goto err_out; - } else - g_print("\n*** Connection '%s' ***\n\n%s", basename, data); - - return; -err_out: - g_print("%s\n", error->message); -} - -#define DEFAULT_SYSFS_DIR "/sys" -#define DEFAULT_INITRD_DATA_DIR NMRUNDIR "/initrd" -#define DEFAULT_RUN_CONFIG_DIR NMRUNDIR "/conf.d" - -int -main(int argc, char *argv[]) -{ - GHashTable * connections; - gs_free char * connections_dir = NULL; - gs_free char * initrd_dir = NULL; - gs_free char * sysfs_dir = NULL; - gs_free char * run_config_dir = NULL; - gboolean dump_to_stdout = FALSE; - gs_strfreev char **remaining = NULL; - GOptionEntry option_entries[] = { - {"connections-dir", - 'c', - 0, - G_OPTION_ARG_FILENAME, - &connections_dir, - "Output connection directory", - NM_KEYFILE_PATH_NAME_RUN}, - {"initrd-data-dir", - 'i', - 0, - G_OPTION_ARG_FILENAME, - &initrd_dir, - "Output initrd data directory", - DEFAULT_INITRD_DATA_DIR}, - {"sysfs-dir", - 'd', - 0, - G_OPTION_ARG_FILENAME, - &sysfs_dir, - "The sysfs mount point", - DEFAULT_SYSFS_DIR}, - {"run-config-dir", - 'r', - 0, - G_OPTION_ARG_FILENAME, - &run_config_dir, - "Output config directory", - DEFAULT_RUN_CONFIG_DIR}, - {"stdout", - 's', - 0, - G_OPTION_ARG_NONE, - &dump_to_stdout, - "Dump connections to standard output", - NULL}, - {G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &remaining, NULL, NULL}, - {NULL}}; - nm_auto_free_option_context GOptionContext *option_context = NULL; - gs_free_error GError *error = NULL; - gs_free char * hostname = NULL; - int errsv; - gint64 carrier_timeout_sec = 0; - - option_context = g_option_context_new( - "-- [ip=...] [rd.route=...] [bridge=...] [bond=...] [team=...] [vlan=...] " - "[bootdev=...] [nameserver=...] [rd.peerdns=...] [rd.bootif=...] [BOOTIF=...] " - "[rd.znet=...] [rd.net.timeout.carrier=...] ... "); - - g_option_context_set_summary(option_context, "Generate early NetworkManager configuration."); - g_option_context_set_description( - option_context, - "This tool scans the command line for options relevant to network\n" - "configuration and creates configuration files for an early instance\n" - "of NetworkManager run from the initial ramdisk during early boot."); - g_option_context_add_main_entries(option_context, option_entries, GETTEXT_PACKAGE); - - if (!g_option_context_parse(option_context, &argc, &argv, &error)) { - _LOGW(LOGD_CORE, "%s", error->message); - return 1; - } - - if (!remaining) { - /* No arguments, no networking. Don't bother. */ - return 0; - } - - if (!connections_dir) - connections_dir = g_strdup(NM_KEYFILE_PATH_NAME_RUN); - if (!sysfs_dir) - sysfs_dir = g_strdup(DEFAULT_SYSFS_DIR); - if (!initrd_dir) - initrd_dir = g_strdup(DEFAULT_INITRD_DATA_DIR); - if (!run_config_dir) - run_config_dir = g_strdup(DEFAULT_RUN_CONFIG_DIR); - - connections = nmi_cmdline_reader_parse(sysfs_dir, - (const char *const *) remaining, - &hostname, - &carrier_timeout_sec); - - if (dump_to_stdout) { - nm_clear_g_free(&connections_dir); - nm_clear_g_free(&initrd_dir); - nm_clear_g_free(&run_config_dir); - if (hostname) - g_print("\n*** Hostname '%s' ***\n", hostname); - if (carrier_timeout_sec != 0) - g_print("\n*** Carrier Wait Timeout %" G_GINT64_FORMAT " sec ***\n", - carrier_timeout_sec); - } else { - if (g_mkdir_with_parents(connections_dir, 0755) != 0) { - errsv = errno; - _LOGW(LOGD_CORE, "%s: %s", connections_dir, nm_strerror_native(errsv)); - return 1; - } - if (g_mkdir_with_parents(initrd_dir, 0755) != 0) { - errsv = errno; - _LOGW(LOGD_CORE, "%s: %s", initrd_dir, nm_strerror_native(errsv)); - return 1; - } - if (g_mkdir_with_parents(run_config_dir, 0755) != 0) { - errsv = errno; - _LOGW(LOGD_CORE, "%s: %s", run_config_dir, nm_strerror_native(errsv)); - return 1; - } - - if (hostname) { - gs_free char *hostname_file = NULL; - gs_free char *data = NULL; - - hostname_file = g_strdup_printf("%s/hostname", initrd_dir); - data = g_strdup_printf("%s\n", hostname); - - if (!g_file_set_contents(hostname_file, data, strlen(data), &error)) { - _LOGW(LOGD_CORE, "%s: %s", hostname_file, error->message); - return 1; - } - } - if (carrier_timeout_sec != 0) { - nm_auto_unref_keyfile GKeyFile *keyfile = NULL; - gs_free char * filename = NULL; - - keyfile = g_key_file_new(); - g_key_file_set_list_separator(keyfile, NM_CONFIG_KEYFILE_LIST_SEPARATOR); - filename = g_strdup_printf("%s/15-carrier-timeout.conf", run_config_dir); - - g_key_file_set_value(keyfile, - NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE "-15-carrier-timeout", - NM_CONFIG_KEYFILE_KEY_MATCH_DEVICE, - "*"); - g_key_file_set_int64(keyfile, - NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE "-15-carrier-timeout", - NM_CONFIG_KEYFILE_KEY_DEVICE_CARRIER_WAIT_TIMEOUT, - carrier_timeout_sec * 1000); - - if (!g_key_file_save_to_file(keyfile, filename, &error)) { - _LOGW(LOGD_CORE, "%s: %s", filename, error->message); - return 1; - } - } - } - - g_hash_table_foreach(connections, output_conn, connections_dir); - g_hash_table_destroy(connections); - - return 0; -} diff --git a/src/core/initrd/nm-initrd-generator.h b/src/core/initrd/nm-initrd-generator.h deleted file mode 100644 index 56dcfd68..00000000 --- a/src/core/initrd/nm-initrd-generator.h +++ /dev/null @@ -1,45 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2014, 2018 Red Hat, Inc. - */ - -#ifndef __NM_INITRD_GENERATOR_H__ -#define __NM_INITRD_GENERATOR_H__ - -#include "nm-connection.h" -#include "nm-utils.h" - -#define NMI_WAIT_DEVICE_TIMEOUT_MS 60000 - -static inline int -get_ip_address_family(const char *str, gboolean with_prefix) -{ - int addr_family; - - if (!str) - return AF_UNSPEC; - - if (with_prefix) { - if (nm_utils_parse_inaddr_prefix_bin(AF_UNSPEC, str, &addr_family, NULL, NULL)) - return addr_family; - } else { - if (nm_utils_parse_inaddr_bin(AF_UNSPEC, str, &addr_family, NULL)) - return addr_family; - } - - return AF_UNSPEC; -} - -GHashTable *nmi_ibft_read(const char *sysfs_dir); - -gboolean -nmi_ibft_update_connection_from_nic(NMConnection *connection, GHashTable *nic, GError **error); - -NMConnection *nmi_dt_reader_parse(const char *sysfs_dir); - -GHashTable *nmi_cmdline_reader_parse(const char * sysfs_dir, - const char *const *argv, - char ** hostname, - gint64 * carrier_timeout_sec); - -#endif /* __NM_INITRD_GENERATOR_H__ */ diff --git a/src/core/initrd/nmi-cmdline-reader.c b/src/core/initrd/nmi-cmdline-reader.c deleted file mode 100644 index 508ef2b2..00000000 --- a/src/core/initrd/nmi-cmdline-reader.c +++ /dev/null @@ -1,1269 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2018 Red Hat, Inc. - */ - -#include "src/core/nm-default-daemon.h" - -#include -#include - -#include "nm-core-internal.h" -#include "nm-initrd-generator.h" -#include "systemd/nm-sd-utils-shared.h" - -/*****************************************************************************/ - -#define _NMLOG(level, domain, ...) \ - nm_log((level), \ - (domain), \ - NULL, \ - NULL, \ - "cmdline-reader: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__) \ - _NM_UTILS_MACRO_REST(__VA_ARGS__)) - -/*****************************************************************************/ - -typedef struct { - GHashTable * hash; - GPtrArray * array; - GPtrArray * vlan_parents; - GHashTable * explicit_ip_connections; - NMConnection *bootdev_connection; /* connection for bootdev=$ifname */ - NMConnection *default_connection; /* connection not bound to any ifname */ - char * hostname; - - /* Parameters to be set for all connections */ - gboolean ignore_auto_dns; - int dhcp_timeout; - char * dhcp4_vci; - - gint64 carrier_timeout_sec; -} Reader; - -static Reader * -reader_new(void) -{ - Reader *reader; - - reader = g_slice_new(Reader); - *reader = (Reader){ - .hash = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_object_unref), - .explicit_ip_connections = - g_hash_table_new_full(nm_direct_hash, NULL, g_object_unref, NULL), - .vlan_parents = g_ptr_array_new_with_free_func(g_free), - .array = g_ptr_array_new(), - }; - - return reader; -} - -static GHashTable * -reader_destroy(Reader *reader, gboolean free_hash) -{ - gs_unref_hashtable GHashTable *hash = NULL; - - g_ptr_array_unref(reader->array); - g_ptr_array_unref(reader->vlan_parents); - g_hash_table_unref(reader->explicit_ip_connections); - hash = g_steal_pointer(&reader->hash); - nm_clear_g_free(&reader->hostname); - nm_clear_g_free(&reader->dhcp4_vci); - nm_g_slice_free(reader); - if (!free_hash) - return g_steal_pointer(&hash); - return NULL; -} - -static NMConnection * -reader_add_connection(Reader *reader, const char *name, NMConnection *connection_take) -{ - char *name_dup; - - name_dup = g_strdup(name); - if (g_hash_table_insert(reader->hash, name_dup, connection_take)) - g_ptr_array_add(reader->array, name_dup); - - return connection_take; -} - -/* Returns a new connection owned by the reader */ -static NMConnection * -reader_create_connection(Reader * reader, - const char * basename, - const char * id, - const char * ifname, - const char * mac, - const char * type_name, - NMConnectionMultiConnect multi_connect) -{ - NMConnection *connection; - NMSetting * setting; - - connection = reader_add_connection(reader, basename, nm_simple_connection_new()); - - /* Start off assuming dynamic IP configurations. */ - - setting = nm_setting_ip4_config_new(); - nm_connection_add_setting(connection, setting); - g_object_set(setting, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP4_CONFIG_METHOD_AUTO, - NM_SETTING_IP_CONFIG_MAY_FAIL, - TRUE, - NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, - reader->ignore_auto_dns, - NM_SETTING_IP_CONFIG_DHCP_TIMEOUT, - reader->dhcp_timeout, - NM_SETTING_IP4_CONFIG_DHCP_VENDOR_CLASS_IDENTIFIER, - reader->dhcp4_vci, - NULL); - - setting = nm_setting_ip6_config_new(); - nm_connection_add_setting(connection, setting); - g_object_set(setting, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP4_CONFIG_METHOD_AUTO, - NM_SETTING_IP_CONFIG_MAY_FAIL, - TRUE, - NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, - (int) NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64, - NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, - reader->ignore_auto_dns, - NM_SETTING_IP_CONFIG_DHCP_TIMEOUT, - reader->dhcp_timeout, - NULL); - - setting = nm_setting_connection_new(); - nm_connection_add_setting(connection, setting); - g_object_set(setting, - NM_SETTING_CONNECTION_ID, - id, - NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), - NM_SETTING_CONNECTION_INTERFACE_NAME, - ifname, - NM_SETTING_CONNECTION_TYPE, - type_name, - NM_SETTING_CONNECTION_MULTI_CONNECT, - multi_connect, - NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES, - 1, - NULL); - - if (nm_streq0(type_name, NM_SETTING_INFINIBAND_SETTING_NAME)) { - setting = nm_setting_infiniband_new(); - nm_connection_add_setting(connection, setting); - g_object_set(setting, NM_SETTING_INFINIBAND_TRANSPORT_MODE, "datagram", NULL); - } - - if (mac) { - if (nm_streq0(type_name, NM_SETTING_INFINIBAND_SETTING_NAME)) { - setting = (NMSetting *) nm_connection_get_setting_infiniband(connection); - g_object_set(setting, NM_SETTING_INFINIBAND_MAC_ADDRESS, mac, NULL); - } else { - setting = nm_setting_wired_new(); - nm_connection_add_setting(connection, setting); - g_object_set(setting, NM_SETTING_WIRED_MAC_ADDRESS, mac, NULL); - } - } - - return connection; -} - -static NMConnection * -reader_get_default_connection(Reader *reader) -{ - NMConnection *con; - - if (!reader->default_connection) { - con = reader_create_connection(reader, - "default_connection", - "Wired Connection", - NULL, - NULL, - NM_SETTING_WIRED_SETTING_NAME, - NM_CONNECTION_MULTI_CONNECT_MULTIPLE); - nm_connection_add_setting(con, nm_setting_wired_new()); - reader->default_connection = con; - } - return reader->default_connection; -} - -static NMConnection * -reader_get_connection(Reader * reader, - const char *iface_spec, - const char *type_name, - gboolean create_if_missing) -{ - NMConnection *connection = NULL; - NMSetting * setting; - const char * ifname = NULL; - gs_free char *mac = NULL; - - if (iface_spec) { - if (nm_utils_is_valid_iface_name(iface_spec, NULL)) - ifname = iface_spec; - else { - mac = nm_utils_hwaddr_canonical(iface_spec, -1); - if (!mac) - _LOGW(LOGD_CORE, "invalid interface '%s'", iface_spec); - } - } - - if (!ifname && !mac) { - NMConnection * candidate; - NMSettingConnection *s_con; - guint i; - - /* - * If ifname was not given, we'll match the connection by type. - * If the type was not given either, then we're happy with any connection but slaves. - * This is so that things like "bond=bond0:eth1,eth2 nameserver=1.3.3.7 end up - * slapping the nameserver to the most reasonable connection (bond0). - */ - for (i = 0; i < reader->array->len; i++) { - candidate = g_hash_table_lookup(reader->hash, reader->array->pdata[i]); - s_con = nm_connection_get_setting_connection(candidate); - - if (type_name == NULL && nm_setting_connection_get_master(s_con) == NULL) { - connection = candidate; - break; - } - - if (type_name != NULL - && nm_streq(nm_setting_connection_get_connection_type(s_con), type_name)) { - connection = candidate; - break; - } - } - } else - connection = g_hash_table_lookup(reader->hash, (gpointer) ifname ?: mac); - - if (!connection) { - if (!create_if_missing) - return NULL; - - if (!type_name) { - if (NM_STR_HAS_PREFIX(ifname, "ib") - || (mac && nm_utils_hwaddr_valid(mac, INFINIBAND_ALEN))) - type_name = NM_SETTING_INFINIBAND_SETTING_NAME; - else - type_name = NM_SETTING_WIRED_SETTING_NAME; - } - - connection = reader_create_connection(reader, - ifname ?: mac, - ifname ?: (mac ?: "Wired Connection"), - ifname, - mac, - type_name, - NM_CONNECTION_MULTI_CONNECT_SINGLE); - } - setting = (NMSetting *) nm_connection_get_setting_connection(connection); - - if (type_name) { - g_object_set(setting, NM_SETTING_CONNECTION_TYPE, type_name, NULL); - if (!nm_connection_get_setting_by_name(connection, type_name)) { - setting = g_object_new(nm_setting_lookup_type(type_name), NULL); - nm_connection_add_setting(connection, setting); - } - } - - return connection; -} - -static char * -get_word(char **argument, const char separator) -{ - char *word; - int nest = 0; - - if (*argument == NULL) - return NULL; - - if (**argument == '[') { - nest++; - (*argument)++; - } - - word = *argument; - - while (**argument != '\0') { - if (nest && **argument == ']') { - **argument = '\0'; - (*argument)++; - nest--; - continue; - } - - if (nest == 0 && **argument == separator) { - **argument = '\0'; - (*argument)++; - break; - } - (*argument)++; - } - - return *word ? word : NULL; -} - -static void -connection_set(NMConnection *connection, - const char * setting_name, - const char * property, - const char * value) -{ - NMSetting * setting; - GType setting_type; - nm_auto_unref_gtypeclass GObjectClass *object_class = NULL; - GParamSpec * spec; - - setting_type = nm_setting_lookup_type(setting_name); - object_class = g_type_class_ref(setting_type); - spec = g_object_class_find_property(object_class, property); - nm_assert(spec); - - setting = nm_connection_get_setting_by_name(connection, setting_name); - if (!setting) { - setting = g_object_new(setting_type, NULL); - nm_connection_add_setting(connection, setting); - } - - if (G_IS_PARAM_SPEC_UINT(spec)) { - guint v; - - v = _nm_utils_ascii_str_to_int64(value, 10, 0, G_MAXUINT, 0); - if (errno || !nm_g_object_set_property_uint(G_OBJECT(setting), property, v, NULL)) { - _LOGW(LOGD_CORE, - "Could not set property '%s.%s' to '%s'", - setting_name, - property, - value); - } - } else if (G_IS_PARAM_SPEC_STRING(spec)) - g_object_set(setting, property, value, NULL); - else - _LOGW(LOGD_CORE, "Don't know how to set '%s' of %s", property, setting_name); -} - -static void -reader_read_all_connections_from_fw(Reader *reader, const char *sysfs_dir) -{ - gs_unref_hashtable GHashTable *ibft = NULL; - NMConnection * dt_connection; - const char * mac; - GHashTable * nic; - const char * index; - GError * error = NULL; - guint i, length; - gs_free const char ** keys = NULL; - - ibft = nmi_ibft_read(sysfs_dir); - keys = nm_utils_strdict_get_keys(ibft, TRUE, &length); - - for (i = 0; i < length; i++) { - gs_unref_object NMConnection *connection = NULL; - gs_free char * name = NULL; - - mac = keys[i]; - nic = g_hash_table_lookup(ibft, mac); - connection = nm_simple_connection_new(); - index = g_hash_table_lookup(nic, "index"); - if (!index) { - _LOGW(LOGD_CORE, "Ignoring an iBFT entry without an index"); - continue; - } - - if (!nmi_ibft_update_connection_from_nic(connection, nic, &error)) { - _LOGW(LOGD_CORE, "Unable to merge iBFT configuration: %s", error->message); - g_error_free(error); - continue; - } - - name = g_strdup_printf("ibft%s", index); - reader_add_connection(reader, name, g_steal_pointer(&connection)); - } - - dt_connection = nmi_dt_reader_parse(sysfs_dir); - if (dt_connection) - reader_add_connection(reader, "ofw", dt_connection); -} - -static void -reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument) -{ - NMConnection * connection; - NMSettingIPConfig *s_ip4 = NULL, *s_ip6 = NULL; - gs_unref_hashtable GHashTable *ibft = NULL; - const char * tmp; - const char * tmp2; - const char * kind = NULL; - const char * client_ip = NULL; - const char * peer = NULL; - const char * gateway_ip = NULL; - const char * netmask = NULL; - const char * client_hostname = NULL; - const char * iface_spec = NULL; - const char * mtu = NULL; - const char * macaddr = NULL; - int client_ip_family = AF_UNSPEC; - int client_ip_prefix = -1; - const char * dns[2] = { - 0, - }; - int dns_addr_family[2] = { - 0, - }; - int i; - GError *error = NULL; - - if (!*argument) - return; - - tmp = get_word(&argument, ':'); - if (!*argument) { - /* ip={dhcp|on|any|dhcp6|auto6|link6|ibft} */ - kind = tmp; - } else { - tmp2 = get_word(&argument, ':'); - if (NM_IN_STRSET(tmp2, - "none", - "off", - "dhcp", - "on" - "any", - "dhcp6", - "auto", - "auto6", - "link6", - "ibft")) { - /* :{none|off|dhcp|on|any|dhcp6|auto|auto6|link6|ibft} */ - iface_spec = tmp; - kind = tmp2; - } else { - /* :[]:::: */ - client_ip = tmp; - if (client_ip) { - client_ip_family = get_ip_address_family(client_ip, TRUE); - if (client_ip_family == AF_UNSPEC) { - _LOGW(LOGD_CORE, "Invalid IP address '%s'.", client_ip); - return; - } - } - - peer = tmp2; - gateway_ip = get_word(&argument, ':'); - netmask = get_word(&argument, ':'); - client_hostname = get_word(&argument, ':'); - iface_spec = get_word(&argument, ':'); - kind = get_word(&argument, ':'); - } - - if (client_hostname && !nm_sd_hostname_is_valid(client_hostname, FALSE)) - client_hostname = NULL; - - if (client_hostname) { - g_free(reader->hostname); - reader->hostname = g_strdup(client_hostname); - } - - tmp = get_word(&argument, ':'); - dns_addr_family[0] = get_ip_address_family(tmp, FALSE); - if (dns_addr_family[0] != AF_UNSPEC) { - dns[0] = tmp; - dns[1] = get_word(&argument, ':'); - dns_addr_family[1] = get_ip_address_family(dns[1], FALSE); - if (*argument) - _LOGW(LOGD_CORE, "Ignoring extra: '%s'.", argument); - } else { - mtu = tmp; - macaddr = argument; - } - } - - if (iface_spec == NULL && NM_IN_STRSET(kind, "fw", "ibft")) { - reader_read_all_connections_from_fw(reader, sysfs_dir); - return; - } - - /* Parsing done, construct the NMConnection. */ - if (iface_spec) - connection = reader_get_connection(reader, iface_spec, NULL, TRUE); - else - connection = reader_get_default_connection(reader); - - g_hash_table_add(reader->explicit_ip_connections, g_object_ref(connection)); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - s_ip6 = nm_connection_get_setting_ip6_config(connection); - - if (netmask && *netmask) { - gboolean is_ipv4 = client_ip_family == AF_INET; - NMIPAddr addr; - - if (is_ipv4 && nm_utils_parse_inaddr_bin(AF_INET, netmask, NULL, &addr)) - client_ip_prefix = nm_utils_ip4_netmask_to_prefix(addr.addr4); - else - client_ip_prefix = _nm_utils_ascii_str_to_int64(netmask, 10, 0, is_ipv4 ? 32 : 128, -1); - - if (client_ip_prefix == -1) - _LOGW(LOGD_CORE, "Invalid IP mask: %s", netmask); - } - - /* Static IP configuration might be present. */ - if (client_ip && *client_ip) { - NMIPAddress *address = NULL; - NMIPAddr addr; - - if (nm_utils_parse_inaddr_prefix_bin(client_ip_family, - client_ip, - NULL, - &addr, - client_ip_prefix == -1 ? &client_ip_prefix : NULL)) { - if (client_ip_prefix == -1) { - switch (client_ip_family) { - case AF_INET: - client_ip_prefix = _nm_utils_ip4_get_default_prefix(addr.addr4); - break; - case AF_INET6: - client_ip_prefix = 64; - break; - } - } - - address = nm_ip_address_new_binary(client_ip_family, - &addr.addr_ptr, - client_ip_prefix, - &error); - if (!address) { - _LOGW(LOGD_CORE, "Invalid address '%s': %s", client_ip, error->message); - g_clear_error(&error); - } - } else - nm_assert_not_reached(); - - if (address) { - switch (client_ip_family) { - case AF_INET: - g_object_set(s_ip4, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP4_CONFIG_METHOD_MANUAL, - NM_SETTING_IP_CONFIG_MAY_FAIL, - FALSE, - NULL); - nm_setting_ip_config_add_address(s_ip4, address); - break; - case AF_INET6: - g_object_set(s_ip6, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP4_CONFIG_METHOD_MANUAL, - NM_SETTING_IP_CONFIG_MAY_FAIL, - FALSE, - NULL); - nm_setting_ip_config_add_address(s_ip6, address); - break; - default: - nm_assert_not_reached(); - break; - } - nm_ip_address_unref(address); - } - } - - /* Dynamic IP configuration configured explicitly. */ - if (NM_IN_STRSET(kind, "none", "off")) { - if (nm_setting_ip_config_get_num_addresses(s_ip6) == 0) { - g_object_set(s_ip6, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED, - NULL); - } - if (nm_setting_ip_config_get_num_addresses(s_ip4) == 0) { - g_object_set(s_ip4, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP4_CONFIG_METHOD_DISABLED, - NULL); - } - } else if (nm_streq0(kind, "dhcp")) { - g_object_set(s_ip4, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP4_CONFIG_METHOD_AUTO, - NM_SETTING_IP_CONFIG_MAY_FAIL, - FALSE, - NULL); - if (nm_setting_ip_config_get_num_addresses(s_ip6) == 0) { - g_object_set(s_ip6, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP6_CONFIG_METHOD_AUTO, - NULL); - } - } else if (NM_IN_STRSET(kind, "auto6", "dhcp6")) { - g_object_set(s_ip4, NM_SETTING_IP_CONFIG_MAY_FAIL, FALSE, NULL); - if (nm_setting_ip_config_get_num_addresses(s_ip4) == 0) { - g_object_set(s_ip4, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP4_CONFIG_METHOD_DISABLED, - NULL); - } - } else if (nm_streq0(kind, "link6")) { - g_object_set(s_ip6, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL, - NM_SETTING_IP_CONFIG_MAY_FAIL, - FALSE, - NULL); - if (nm_setting_ip_config_get_num_addresses(s_ip4) == 0) { - g_object_set(s_ip4, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP4_CONFIG_METHOD_DISABLED, - NULL); - } - } else if (nm_streq0(kind, "ibft")) { - NMSettingWired *s_wired; - const char * mac = NULL; - const char * ifname; - gs_free char * mac_free = NULL; - gs_free char * address_path = NULL; - GHashTable * nic = NULL; - - if ((s_wired = nm_connection_get_setting_wired(connection)) - && (mac = nm_setting_wired_get_mac_address(s_wired))) { - /* got mac from the connection */ - } else if ((ifname = nm_connection_get_interface_name(connection))) { - /* read it from sysfs */ - address_path = g_build_filename(sysfs_dir, "class", "net", ifname, "address", NULL); - if (g_file_get_contents(address_path, &mac_free, NULL, &error)) { - g_strchomp(mac_free); - mac = mac_free; - } else { - _LOGW(LOGD_CORE, "Can't get a MAC address for %s: %s", ifname, error->message); - g_clear_error(&error); - } - } - - if (mac) { - gs_free char *mac_up = NULL; - - mac_up = g_ascii_strup(mac, -1); - ibft = nmi_ibft_read(sysfs_dir); - nic = g_hash_table_lookup(ibft, mac_up); - if (!nic) - _LOGW(LOGD_CORE, "No iBFT NIC for %s (%s)", iface_spec, mac_up); - } - - if (nic) { - if (!nmi_ibft_update_connection_from_nic(connection, nic, &error)) { - _LOGW(LOGD_CORE, "Unable to merge iBFT configuration: %s", error->message); - g_clear_error(&error); - } - } - } - - if (peer && *peer) - _LOGW(LOGD_CORE, "Ignoring peer: %s (not implemented)\n", peer); - - if (gateway_ip && *gateway_ip) { - switch (get_ip_address_family(gateway_ip, FALSE)) { - case AF_INET: - g_object_set(s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, gateway_ip, NULL); - break; - case AF_INET6: - g_object_set(s_ip6, NM_SETTING_IP_CONFIG_GATEWAY, gateway_ip, NULL); - break; - default: - _LOGW(LOGD_CORE, "Invalid gateway: %s", gateway_ip); - break; - } - } - - if (client_hostname && *client_hostname) { - g_object_set(s_ip4, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, client_hostname, NULL); - g_object_set(s_ip6, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, client_hostname, NULL); - } - - for (i = 0; i < 2; i++) { - if (dns_addr_family[i] == AF_UNSPEC) - break; - if (nm_utils_ipaddr_is_valid(dns_addr_family[i], dns[i])) { - switch (dns_addr_family[i]) { - case AF_INET: - nm_setting_ip_config_add_dns(s_ip4, dns[i]); - break; - case AF_INET6: - nm_setting_ip_config_add_dns(s_ip6, dns[i]); - break; - default: - _LOGW(LOGD_CORE, "Unknown address family: %s", dns[i]); - break; - } - } else { - _LOGW(LOGD_CORE, "Invalid name server: %s", dns[i]); - } - } - - if (mtu && *mtu) - connection_set(connection, NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MTU, mtu); - - if (macaddr && *macaddr) - connection_set(connection, - NM_SETTING_WIRED_SETTING_NAME, - NM_SETTING_WIRED_CLONED_MAC_ADDRESS, - macaddr); -} - -static void -reader_parse_master(Reader *reader, char *argument, const char *type_name, const char *default_name) -{ - NMConnection * connection; - NMSettingConnection *s_con; - gs_free char * master_to_free = NULL; - const char * master; - char * slaves; - const char * slave; - char * opts; - const char * mtu = NULL; - - master = get_word(&argument, ':'); - if (!master) - master = master_to_free = g_strdup_printf("%s0", default_name ?: type_name); - slaves = get_word(&argument, ':'); - - connection = reader_get_connection(reader, master, type_name, TRUE); - s_con = nm_connection_get_setting_connection(connection); - master = nm_setting_connection_get_uuid(s_con); - - if (nm_streq(type_name, NM_SETTING_BRIDGE_SETTING_NAME)) { - NMSettingBridge *s_bridge = nm_connection_get_setting_bridge(connection); - - /* Avoid the forwarding delay */ - g_object_set(s_bridge, NM_SETTING_BRIDGE_STP, FALSE, NULL); - } else if (nm_streq(type_name, NM_SETTING_BOND_SETTING_NAME)) { - NMSettingBond *s_bond = nm_connection_get_setting_bond(connection); - - opts = get_word(&argument, ':'); - while (opts && *opts) { - gs_free_error GError *error = NULL; - char * opt; - const char * opt_name; - - opt = get_word(&opts, ','); - opt_name = get_word(&opt, '='); - - if (!_nm_setting_bond_validate_option(opt_name, opt, &error)) { - _LOGW(LOGD_CORE, - "Ignoring invalid bond option: %s%s%s = %s%s%s: %s", - NM_PRINT_FMT_QUOTE_STRING(opt_name), - NM_PRINT_FMT_QUOTE_STRING(opt), - error->message); - continue; - } - nm_setting_bond_add_option(s_bond, opt_name, opt); - } - - mtu = get_word(&argument, ':'); - } - - do { - slave = get_word(&slaves, ','); - if (slave == NULL) - slave = "eth0"; - - connection = reader_get_connection(reader, slave, NULL, TRUE); - s_con = nm_connection_get_setting_connection(connection); - g_object_set(s_con, - NM_SETTING_CONNECTION_SLAVE_TYPE, - type_name, - NM_SETTING_CONNECTION_MASTER, - master, - NULL); - if (mtu) - connection_set(connection, NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MTU, mtu); - } while (slaves && *slaves != '\0'); - - if (argument && *argument) - _LOGW(LOGD_CORE, "Ignoring extra: '%s'.", argument); -} - -static void -reader_add_routes(Reader *reader, GPtrArray *array) -{ - guint i; - - for (i = 0; i < array->len; i++) { - NMConnection * connection = NULL; - const char * net; - const char * gateway; - const char * interface; - int family = AF_UNSPEC; - NMIPAddr net_addr = {}; - NMIPAddr gateway_addr = {}; - int net_prefix = -1; - NMIPRoute * route; - NMSettingIPConfig *s_ip; - char * argument; - gs_free_error GError *error = NULL; - - argument = array->pdata[i]; - net = get_word(&argument, ':'); - gateway = get_word(&argument, ':'); - interface = get_word(&argument, ':'); - - if (interface) - connection = reader_get_connection(reader, interface, NULL, TRUE); - if (!connection) - connection = reader->bootdev_connection; - if (!connection) - connection = reader_get_connection(reader, interface, NULL, FALSE); - if (!connection) - connection = reader_get_default_connection(reader); - - if (net && *net) { - if (!nm_utils_parse_inaddr_prefix_bin(family, net, &family, &net_addr, &net_prefix)) { - _LOGW(LOGD_CORE, "Unrecognized address: %s", net); - continue; - } - } - - if (gateway && *gateway) { - if (!nm_utils_parse_inaddr_bin(family, gateway, &family, &gateway_addr)) { - _LOGW(LOGD_CORE, "Unrecognized address: %s", gateway); - continue; - } - } - - switch (family) { - case AF_INET: - s_ip = nm_connection_get_setting_ip4_config(connection); - if (net_prefix == -1) - net_prefix = 32; - break; - case AF_INET6: - s_ip = nm_connection_get_setting_ip6_config(connection); - if (net_prefix == -1) - net_prefix = 128; - break; - default: - _LOGW(LOGD_CORE, "Unknown address family: %s", net); - continue; - } - - route = nm_ip_route_new_binary(family, - &net_addr.addr_ptr, - net_prefix, - &gateway_addr.addr_ptr, - -1, - &error); - if (!route) { - g_warning("Invalid route '%s via %s': %s\n", net, gateway, error->message); - continue; - } - - nm_setting_ip_config_add_route(s_ip, route); - nm_ip_route_unref(route); - } -} - -static void -reader_parse_vlan(Reader *reader, char *argument) -{ - NMConnection * connection; - NMSettingVlan *s_vlan; - const char * vlan; - const char * phy; - const char * vlanid; - - vlan = get_word(&argument, ':'); - phy = get_word(&argument, ':'); - - for (vlanid = vlan + strlen(vlan); vlanid > vlan; vlanid--) { - if (!g_ascii_isdigit(*(vlanid - 1))) - break; - } - - connection = reader_get_connection(reader, vlan, NM_SETTING_VLAN_SETTING_NAME, TRUE); - - s_vlan = nm_connection_get_setting_vlan(connection); - g_object_set(s_vlan, - NM_SETTING_VLAN_PARENT, - phy, - NM_SETTING_VLAN_ID, - (guint) _nm_utils_ascii_str_to_int64(vlanid, 10, 0, G_MAXUINT, G_MAXUINT), - NULL); - - if (argument && *argument) - _LOGW(LOGD_CORE, "Ignoring extra: '%s'.", argument); - - if (!nm_strv_ptrarray_contains(reader->vlan_parents, phy)) - g_ptr_array_add(reader->vlan_parents, g_strdup(phy)); -} - -static void -reader_parse_rd_znet(Reader *reader, char *argument, gboolean net_ifnames) -{ - const char * nettype; - const char * subchannels[4] = {0, 0, 0, 0}; - const char * tmp; - gs_free char * ifname = NULL; - const char * prefix; - NMConnection * connection; - NMSettingWired *s_wired; - static int count_ctc = 0; - static int count_eth = 0; - int index; - - nettype = get_word(&argument, ','); - subchannels[0] = get_word(&argument, ','); - subchannels[1] = get_word(&argument, ','); - - if (nm_streq0(nettype, "ctc")) { - if (net_ifnames == TRUE) { - prefix = "sl"; - } else { - prefix = "ctc"; - index = count_ctc++; - } - } else { - subchannels[2] = get_word(&argument, ','); - if (net_ifnames == TRUE) { - prefix = "en"; - } else { - prefix = "eth"; - index = count_eth++; - } - } - - if (net_ifnames == TRUE) { - const char *bus_id; - size_t bus_id_len; - size_t bus_id_start; - - /* The following logic is taken from names_ccw() in systemd/src/udev/udev-builtin-net_id.c */ - bus_id = subchannels[0]; - bus_id_len = strlen(bus_id); - bus_id_start = strspn(bus_id, ".0"); - bus_id += bus_id_start < bus_id_len ? bus_id_start : bus_id_len - 1; - - ifname = g_strdup_printf("%sc%s", prefix, bus_id); - } else { - ifname = g_strdup_printf("%s%d", prefix, index); - } - - connection = reader_get_connection(reader, ifname, NM_SETTING_WIRED_SETTING_NAME, FALSE); - if (!connection) - return; - s_wired = nm_connection_get_setting_wired(connection); - g_object_set(s_wired, - NM_SETTING_WIRED_S390_NETTYPE, - nettype, - NM_SETTING_WIRED_S390_SUBCHANNELS, - &subchannels, - NULL); - - while ((tmp = get_word(&argument, ',')) != NULL) { - char *val; - - val = strchr(tmp, '='); - if (val) { - gs_free char *key = NULL; - - key = g_strndup(tmp, val - tmp); - val[0] = '\0'; - val++; - nm_setting_wired_add_s390_option(s_wired, key, val); - } - } -} - -static void -_normalize_conn(gpointer key, gpointer value, gpointer user_data) -{ - NMConnection *connection = value; - - nm_connection_normalize(connection, NULL, NULL, NULL); -} - -static void -reader_add_nameservers(Reader *reader, GPtrArray *nameservers) -{ - NMConnection * connection; - NMSettingIPConfig *s_ip; - GHashTableIter iter; - int addr_family; - const char * ns; - guint i; - - for (i = 0; i < nameservers->len; i++) { - ns = nameservers->pdata[i]; - addr_family = get_ip_address_family(ns, FALSE); - if (addr_family == AF_UNSPEC) { - _LOGW(LOGD_CORE, "Unknown address family: %s", ns); - continue; - } - - g_hash_table_iter_init(&iter, reader->hash); - while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &connection)) { - switch (addr_family) { - case AF_INET: - s_ip = nm_connection_get_setting_ip4_config(connection); - if (!NM_IN_STRSET(nm_setting_ip_config_get_method(s_ip), - NM_SETTING_IP4_CONFIG_METHOD_AUTO, - NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) - continue; - break; - case AF_INET6: - s_ip = nm_connection_get_setting_ip6_config(connection); - if (!NM_IN_STRSET(nm_setting_ip_config_get_method(s_ip), - NM_SETTING_IP6_CONFIG_METHOD_AUTO, - NM_SETTING_IP6_CONFIG_METHOD_DHCP, - NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) - continue; - break; - default: - nm_assert_not_reached(); - continue; - } - - nm_setting_ip_config_add_dns(s_ip, ns); - } - } -} - -static void -connection_set_needed(NMConnection *connection) -{ - NMSettingConnection *s_con; - - s_con = nm_connection_get_setting_connection(connection); - if (!nm_streq0(nm_setting_connection_get_connection_type(s_con), NM_SETTING_WIRED_SETTING_NAME)) - return; - - g_object_set(s_con, - NM_SETTING_CONNECTION_WAIT_DEVICE_TIMEOUT, - (int) NMI_WAIT_DEVICE_TIMEOUT_MS, - NULL); -} - -static void -connection_set_needed_cb(gpointer key, gpointer value, gpointer user_data) -{ - connection_set_needed(value); -} - -GHashTable * -nmi_cmdline_reader_parse(const char * sysfs_dir, - const char *const *argv, - char ** hostname, - gint64 * carrier_timeout_sec) -{ - Reader * reader; - const char * tag; - gboolean ignore_bootif = FALSE; - gboolean neednet = FALSE; - gs_free char * bootif_val = NULL; - gs_free char * bootdev = NULL; - gboolean net_ifnames = TRUE; - gs_unref_ptrarray GPtrArray *nameservers = NULL; - gs_unref_ptrarray GPtrArray *routes = NULL; - gs_unref_ptrarray GPtrArray *znets = NULL; - int i; - guint64 dhcp_timeout = 90; - guint64 dhcp_num_tries = 1; - - reader = reader_new(); - - for (i = 0; argv[i]; i++) { - gs_free char *argument_clone = NULL; - char * argument; - - argument_clone = g_strdup(argv[i]); - argument = argument_clone; - - tag = get_word(&argument, '='); - - if (nm_streq(tag, "net.ifnames")) - net_ifnames = !nm_streq(argument, "0"); - else if (nm_streq(tag, "rd.peerdns")) - reader->ignore_auto_dns = !_nm_utils_ascii_str_to_bool(argument, TRUE); - else if (nm_streq(tag, "rd.net.timeout.dhcp")) { - if (nm_streq0(argument, "infinity")) { - dhcp_timeout = G_MAXINT32; - } else { - dhcp_timeout = - _nm_utils_ascii_str_to_int64(argument, 10, 1, G_MAXINT32, dhcp_timeout); - } - } else if (nm_streq(tag, "rd.net.dhcp.retry")) { - dhcp_num_tries = - _nm_utils_ascii_str_to_int64(argument, 10, 1, G_MAXINT32, dhcp_num_tries); - } else if (nm_streq(tag, "rd.net.dhcp.vendor-class")) { - if (nm_utils_validate_dhcp4_vendor_class_id(argument, NULL)) - nm_utils_strdup_reset(&reader->dhcp4_vci, argument); - } else if (nm_streq(tag, "rd.net.timeout.carrier")) { - reader->carrier_timeout_sec = - _nm_utils_ascii_str_to_int64(argument, 10, 0, G_MAXINT32, 0); - } - } - - reader->dhcp_timeout = NM_CLAMP(dhcp_timeout * dhcp_num_tries, 1, G_MAXINT32); - - for (i = 0; argv[i]; i++) { - gs_free char *argument_clone = NULL; - char * argument; - char * word; - - argument_clone = g_strdup(argv[i]); - argument = argument_clone; - - tag = get_word(&argument, '='); - if (nm_streq(tag, "ip")) - reader_parse_ip(reader, sysfs_dir, argument); - else if (nm_streq(tag, "rd.route")) { - if (!routes) - routes = g_ptr_array_new_with_free_func(g_free); - g_ptr_array_add(routes, g_strdup(argument)); - } else if (nm_streq(tag, "bridge")) - reader_parse_master(reader, argument, NM_SETTING_BRIDGE_SETTING_NAME, "br"); - else if (nm_streq(tag, "bond")) - reader_parse_master(reader, argument, NM_SETTING_BOND_SETTING_NAME, NULL); - else if (nm_streq(tag, "team")) - reader_parse_master(reader, argument, NM_SETTING_TEAM_SETTING_NAME, NULL); - else if (nm_streq(tag, "vlan")) - reader_parse_vlan(reader, argument); - else if (nm_streq(tag, "bootdev")) { - g_free(bootdev); - bootdev = g_strdup(argument); - } else if (nm_streq(tag, "nameserver")) { - word = get_word(&argument, '\0'); - if (word) { - if (!nameservers) - nameservers = g_ptr_array_new_with_free_func(g_free); - g_ptr_array_add(nameservers, g_strdup(word)); - } - if (argument && *argument) - _LOGW(LOGD_CORE, "Ignoring extra: '%s'.", argument); - } else if (nm_streq(tag, "rd.iscsi.ibft") && _nm_utils_ascii_str_to_bool(argument, TRUE)) - reader_read_all_connections_from_fw(reader, sysfs_dir); - else if (nm_streq(tag, "rd.bootif")) - ignore_bootif = !_nm_utils_ascii_str_to_bool(argument, TRUE); - else if (nm_streq(tag, "rd.neednet")) - neednet = _nm_utils_ascii_str_to_bool(argument, TRUE); - else if (nm_streq(tag, "rd.znet")) { - if (!znets) - znets = g_ptr_array_new_with_free_func(g_free); - g_ptr_array_add(znets, g_strdup(argument)); - } else if (g_ascii_strcasecmp(tag, "BOOTIF") == 0) { - nm_clear_g_free(&bootif_val); - bootif_val = g_strdup(argument); - } - } - - for (i = 0; i < reader->vlan_parents->len; i++) { - NMConnection * connection; - NMSettingIPConfig *s_ip; - - /* Disable IP configuration for parent connections of VLANs, - * unless those interfaces were explicitly configured otherwise. */ - - connection = reader_get_connection(reader, reader->vlan_parents->pdata[i], NULL, TRUE); - if (!g_hash_table_contains(reader->explicit_ip_connections, connection)) { - s_ip = nm_connection_get_setting_ip4_config(connection); - if (s_ip) { - g_object_set(s_ip, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP4_CONFIG_METHOD_DISABLED, - NULL); - } - - s_ip = nm_connection_get_setting_ip6_config(connection); - if (s_ip) { - g_object_set(s_ip, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED, - NULL); - } - } - } - - if (ignore_bootif) - nm_clear_g_free(&bootif_val); - if (bootif_val) { - NMConnection * connection; - NMSettingWired *s_wired; - const char * bootif = bootif_val; - char prefix[4]; - - if (!nm_utils_hwaddr_valid(bootif, ETH_ALEN)) { - strncpy(prefix, bootif, 3); - prefix[3] = '\0'; - - if (NM_IN_STRSET(prefix, "01-", "01:", "00-", "00:") - && nm_utils_hwaddr_valid(&bootif[3], ETH_ALEN)) { - /* - * BOOTIF MAC address can be prefixed with a hardware type identifier. - * "01" stays for "wired", "00" is also accepted as it means "undefined". - * No others are known. - */ - bootif += 3; - } - } - - connection = reader_get_connection(reader, NULL, NM_SETTING_WIRED_SETTING_NAME, FALSE); - if (!connection) - connection = reader_get_default_connection(reader); - - s_wired = nm_connection_get_setting_wired(connection); - - if (nm_connection_get_interface_name(connection) - || (nm_setting_wired_get_mac_address(s_wired) - && !nm_utils_hwaddr_matches(nm_setting_wired_get_mac_address(s_wired), - -1, - bootif, - -1))) { - connection = reader_create_connection(reader, - "bootif_connection", - "BOOTIF Connection", - NULL, - bootif, - NM_SETTING_WIRED_SETTING_NAME, - NM_CONNECTION_MULTI_CONNECT_SINGLE); - } else { - g_object_set(s_wired, NM_SETTING_WIRED_MAC_ADDRESS, bootif, NULL); - } - } - - if (bootdev) { - NMConnection *connection; - - connection = reader_get_connection(reader, bootdev, NULL, TRUE); - reader->bootdev_connection = connection; - connection_set_needed(connection); - } - - if (neednet) { - if (g_hash_table_size(reader->hash) == 0) { - /* Make sure there's some connection. */ - reader_get_default_connection(reader); - } - - g_hash_table_foreach(reader->hash, connection_set_needed_cb, NULL); - } - - if (routes) - reader_add_routes(reader, routes); - - if (nameservers) - reader_add_nameservers(reader, nameservers); - - if (znets) { - for (i = 0; i < znets->len; i++) - reader_parse_rd_znet(reader, znets->pdata[i], net_ifnames); - } - - g_hash_table_foreach(reader->hash, _normalize_conn, NULL); - - NM_SET_OUT(hostname, g_steal_pointer(&reader->hostname)); - - NM_SET_OUT(carrier_timeout_sec, reader->carrier_timeout_sec); - - return reader_destroy(reader, FALSE); -} diff --git a/src/core/initrd/nmi-dt-reader.c b/src/core/initrd/nmi-dt-reader.c deleted file mode 100644 index 63e4524b..00000000 --- a/src/core/initrd/nmi-dt-reader.c +++ /dev/null @@ -1,371 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2019 Red Hat, Inc. - */ - -#include "src/core/nm-default-daemon.h" - -#include "nm-initrd-generator.h" - -#include -#include - -#include "nm-core-internal.h" - -/*****************************************************************************/ - -#define _NMLOG(level, domain, ...) \ - nm_log((level), \ - (domain), \ - NULL, \ - NULL, \ - "dt-reader: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__) _NM_UTILS_MACRO_REST(__VA_ARGS__)) - -/*****************************************************************************/ - -static gboolean -dt_get_property(const char *base, - const char *dev, - const char *prop, - char ** contents, - size_t * length) -{ - gs_free char *filename = g_build_filename(base, dev, prop, NULL); - gs_free_error GError *error = NULL; - - if (!g_file_test(filename, G_FILE_TEST_EXISTS)) - return FALSE; - - if (!contents) - return TRUE; - - if (!g_file_get_contents(filename, contents, length, &error)) { - _LOGW(LOGD_CORE, "%s: Can not read the %s property: %s", dev, prop, error->message); - return FALSE; - } - - return TRUE; -} - -static NMIPAddress * -dt_get_ipaddr_property(const char *base, const char *dev, const char *prop, int *family) -{ - gs_free char *buf = NULL; - size_t len; - int f; - - if (!dt_get_property(base, dev, prop, &buf, &len)) - return NULL; - - f = nm_utils_addr_family_from_size(len); - if (f == AF_UNSPEC || (*family != AF_UNSPEC && *family != f)) { - _LOGW(LOGD_CORE, "%s: Address %s has unrecognized length (%zd)", dev, prop, len); - return NULL; - } - - *family = f; - return nm_ip_address_new_binary(f, buf, 0, NULL); -} - -static char * -dt_get_hwaddr_property(const char *base, const char *dev, const char *prop) -{ - gs_free guint8 *buf = NULL; - size_t len; - - if (!dt_get_property(base, dev, prop, (char **) &buf, &len)) - return NULL; - - if (len != ETH_ALEN) { - _LOGW(LOGD_CORE, "%s: MAC address %s has unrecognized length (%zd)", dev, prop, len); - return NULL; - } - - return g_strdup_printf("%02x:%02x:%02x:%02x:%02x:%02x", - buf[0], - buf[1], - buf[2], - buf[3], - buf[4], - buf[4]); -} - -static NMIPAddress * -str_addr(const char *str, int *family) -{ - NMIPAddr addr_bin; - - if (!nm_utils_parse_inaddr_bin_full(*family, TRUE, str, family, &addr_bin)) { - _LOGW(LOGD_CORE, "Malformed IP address: '%s'", str); - return NULL; - } - return nm_ip_address_new_binary(*family, &addr_bin, 0, NULL); -} - -NMConnection * -nmi_dt_reader_parse(const char *sysfs_dir) -{ - gs_unref_object NMConnection *connection = NULL; - gs_free char * base = NULL; - gs_free char * bootpath = NULL; - gs_strfreev char ** tokens = NULL; - char * path = NULL; - gboolean bootp = FALSE; - const char * s_ipaddr = NULL; - const char * s_netmask = NULL; - const char * s_gateway = NULL; - nm_auto_unref_ip_address NMIPAddress *ipaddr = NULL; - nm_auto_unref_ip_address NMIPAddress *gateway = NULL; - const char * duplex = NULL; - gs_free char * hwaddr = NULL; - gs_free char * local_hwaddr = NULL; - gs_free char * hostname = NULL; - guint32 speed = 0; - int prefix = -1; - NMSettingIPConfig * s_ip = NULL; - NMSetting * s_ip4 = NULL; - NMSetting * s_ip6 = NULL; - NMSetting * s_wired = NULL; - int family = AF_UNSPEC; - int i = 0; - char * c; - gs_free_error GError *error = NULL; - - base = g_build_filename(sysfs_dir, "firmware", "devicetree", "base", NULL); - - if (!dt_get_property(base, "chosen", "bootpath", &bootpath, NULL)) - return NULL; - - c = strchr(bootpath, ':'); - if (c) { - *c = '\0'; - path = c + 1; - } else { - path = ""; - } - - dt_get_property(base, "chosen", "client-name", &hostname, NULL); - - local_hwaddr = dt_get_hwaddr_property(base, bootpath, "local-mac-address"); - hwaddr = dt_get_hwaddr_property(base, bootpath, "mac-address"); - if (nm_streq0(local_hwaddr, hwaddr)) - nm_clear_g_free(&local_hwaddr); - - tokens = g_strsplit(path, ",", 0); - - /* - * Ethernet device settings. Defined by "Open Firmware, - * Recommended Practice: Device Support Extensions, Version 1.0 [1] - * [1] https://www.devicetree.org/open-firmware/practice/devicex/dse1_0a.ps - */ - - for (i = 0; tokens[i]; i++) { - /* Skip these. They have magical meaning for OpenFirmware. */ - if (NM_IN_STRSET(tokens[i], "nfs", "last")) - continue; - if (nm_streq(tokens[i], "promiscuous")) { - /* Ignore. */ - continue; - } - - if (g_str_has_prefix(tokens[i], "speed=")) { - speed = _nm_utils_ascii_str_to_int64(tokens[i] + 6, 10, 0, G_MAXUINT32, 0); - continue; - } - - if (g_str_has_prefix(tokens[i], "duplex=auto")) { - continue; - } else if (g_str_has_prefix(tokens[i], "duplex=half") - || g_str_has_prefix(tokens[i], "duplex=full")) { - duplex = tokens[i] + 7; - continue; - } - - break; - } - - /* - * Network boot configuration. Defined by "Open Firmware, - * Recommended Practice: TFTP Booting Extension, Version 1.0 [1] - * [1] https://www.devicetree.org/open-firmware/practice/obp-tftp/tftp1_0.pdf - */ - - for (; tokens[i]; i++) { - if (NM_IN_STRSET(tokens[i], "bootp", "dhcp", "rarp")) { - bootp = TRUE; - continue; - } - break; - } - - /* s-iaddr, or perhaps a raw absolute filename */ - if (tokens[i] && tokens[i][0] != '/') - i++; - - /* filename */ - if (tokens[i]) - i++; - - /* c-iaddr */ - if (tokens[i]) { - s_ipaddr = tokens[i]; - i++; - } - - /* g-iaddr */ - if (tokens[i]) { - s_gateway = tokens[i]; - i++; - } - - if (tokens[i] && (strchr(tokens[i], '.') || strchr(tokens[i], ':'))) { - /* yaboot claims the mask can be specified here, - * though it doesn't support it. */ - s_netmask = tokens[i]; - i++; - } - - /* bootp-retries */ - if (tokens[i]) - i++; - - /* tftp-retries */ - if (tokens[i]) - i++; - - if (tokens[i]) { - /* yaboot accepts a mask here */ - s_netmask = tokens[i]; - i++; - } - - connection = nm_simple_connection_new(); - - nm_connection_add_setting(connection, - g_object_new(NM_TYPE_SETTING_CONNECTION, - NM_SETTING_CONNECTION_TYPE, - NM_SETTING_WIRED_SETTING_NAME, - NM_SETTING_CONNECTION_ID, - "OpenFirmware Connection", - NULL)); - - s_ip4 = nm_setting_ip4_config_new(); - nm_connection_add_setting(connection, s_ip4); - - s_ip6 = nm_setting_ip6_config_new(); - nm_connection_add_setting(connection, s_ip6); - - g_object_set(s_ip6, - NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, - (int) NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64, - NULL); - - if (!bootp && dt_get_property(base, "chosen", "bootp-response", NULL, NULL)) - bootp = TRUE; - - if (!bootp) { - nm_auto_unref_ip_address NMIPAddress *netmask = NULL; - - netmask = dt_get_ipaddr_property(base, "chosen", "netmask-ip", &family); - gateway = dt_get_ipaddr_property(base, "chosen", "gateway-ip", &family); - if (gateway) - s_gateway = nm_ip_address_get_address(gateway); - ipaddr = dt_get_ipaddr_property(base, "chosen", "client-ip", &family); - - if (family == AF_UNSPEC) { - nm_assert(netmask == NULL); - nm_assert(gateway == NULL); - nm_assert(ipaddr == NULL); - - netmask = str_addr(s_netmask, &family); - ipaddr = str_addr(s_ipaddr, &family); - - prefix = _nm_utils_ascii_str_to_int64(s_netmask, 10, 0, 128, -1); - } - - if (prefix == -1 && family == AF_INET && netmask) { - guint32 netmask_v4; - - nm_ip_address_get_address_binary(netmask, &netmask_v4); - prefix = nm_utils_ip4_netmask_to_prefix(netmask_v4); - } - - if (prefix == -1) - _LOGW(LOGD_CORE, "Unable to determine the network prefix"); - else - nm_ip_address_set_prefix(ipaddr, prefix); - } - - if (!ipaddr) { - family = AF_UNSPEC; - bootp = TRUE; - } - - if (bootp) { - g_object_set(s_ip4, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP4_CONFIG_METHOD_AUTO, - NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, - hostname, - NULL); - g_object_set(s_ip6, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP6_CONFIG_METHOD_AUTO, - NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, - hostname, - NULL); - } else { - switch (family) { - case AF_INET: - s_ip = (NMSettingIPConfig *) s_ip4; - g_object_set(s_ip4, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP4_CONFIG_METHOD_MANUAL, - NULL); - g_object_set(s_ip6, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED, - NULL); - break; - case AF_INET6: - s_ip = (NMSettingIPConfig *) s_ip6; - g_object_set(s_ip4, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP4_CONFIG_METHOD_DISABLED, - NULL); - g_object_set(s_ip6, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP6_CONFIG_METHOD_MANUAL, - NULL); - break; - default: - g_return_val_if_reached(NULL); - } - - nm_setting_ip_config_add_address(s_ip, ipaddr); - g_object_set(s_ip, NM_SETTING_IP_CONFIG_GATEWAY, s_gateway, NULL); - } - - if (duplex || speed || hwaddr || local_hwaddr) { - s_wired = nm_setting_wired_new(); - nm_connection_add_setting(connection, s_wired); - - g_object_set(s_wired, - NM_SETTING_WIRED_SPEED, - speed, - NM_SETTING_WIRED_DUPLEX, - duplex, - NM_SETTING_WIRED_MAC_ADDRESS, - hwaddr, - NM_SETTING_WIRED_CLONED_MAC_ADDRESS, - local_hwaddr, - NULL); - } - - if (!nm_connection_normalize(connection, NULL, NULL, &error)) { - _LOGW(LOGD_CORE, "Generated an invalid connection: %s", error->message); - nm_clear_pointer(&connection, g_object_unref); - } - - return g_steal_pointer(&connection); -} diff --git a/src/core/initrd/nmi-ibft-reader.c b/src/core/initrd/nmi-ibft-reader.c deleted file mode 100644 index 9895cda4..00000000 --- a/src/core/initrd/nmi-ibft-reader.c +++ /dev/null @@ -1,463 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2014 - 2018 Red Hat, Inc. - */ - -#include "src/core/nm-default-daemon.h" - -#include "nm-initrd-generator.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "nm-core-internal.h" -#include "NetworkManagerUtils.h" - -/*****************************************************************************/ - -#define _NMLOG(level, domain, ...) \ - nm_log((level), \ - (domain), \ - NULL, \ - NULL, \ - "ibft-reader: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__) _NM_UTILS_MACRO_REST(__VA_ARGS__)) - -/*****************************************************************************/ - -static GHashTable * -load_one_nic(const char *sysfs_dir, const char *dir_name) -{ - gs_free char *nic_path = g_build_filename(sysfs_dir, dir_name, NULL); - GDir * nic_dir; - const char * entry_name; - char * content; - gs_free_error GError *error = NULL; - GHashTable * nic; - - g_return_val_if_fail(sysfs_dir != NULL, FALSE); - - nic_dir = g_dir_open(nic_path, 0, &error); - if (!nic_dir) { - _LOGW(LOGD_CORE, "Can't open %s: %s", nic_path, error->message); - return NULL; - } - - nic = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_free); - while ((entry_name = g_dir_read_name(nic_dir))) { - gs_free char *entry_path = g_build_filename(nic_path, entry_name, NULL); - - if (!g_file_test(entry_path, G_FILE_TEST_IS_REGULAR)) - continue; - - if (!g_file_get_contents(entry_path, &content, NULL, &error)) { - _LOGW(LOGD_CORE, "Can't read %s: %s", entry_path, error->message); - g_clear_error(&error); - continue; - } - - g_strchomp(content); - if (!g_hash_table_insert(nic, g_strdup(entry_name), content)) - _LOGW(LOGD_CORE, "Duplicate iBFT entry: %s", entry_name); - } - - g_dir_close(nic_dir); - - return nic; -} - -GHashTable * -nmi_ibft_read(const char *sysfs_dir) -{ - gs_free char *ibft_path = NULL; - GDir * ibft_dir; - const char * dir_name; - GHashTable * ibft, *nic; - char * mac; - gs_free_error GError *error = NULL; - - g_return_val_if_fail(sysfs_dir != NULL, FALSE); - - ibft_path = g_build_filename(sysfs_dir, "firmware", "ibft", NULL); - - ibft = g_hash_table_new_full(nm_str_hash, - g_str_equal, - g_free, - (GDestroyNotify) g_hash_table_unref); - - if (!g_file_test(ibft_path, G_FILE_TEST_IS_DIR)) - nm_utils_modprobe(NULL, FALSE, "iscsi_ibft", NULL); - if (!g_file_test(ibft_path, G_FILE_TEST_IS_DIR)) - return ibft; - - ibft_dir = g_dir_open(ibft_path, 0, &error); - if (!ibft_dir) { - _LOGW(LOGD_CORE, "Unable to open iBFT firmware directory: %s", error->message); - return ibft; - } - - while ((dir_name = g_dir_read_name(ibft_dir))) { - if (!g_str_has_prefix(dir_name, "ethernet")) - continue; - - nic = load_one_nic(ibft_path, dir_name); - mac = g_hash_table_lookup(nic, "mac"); - - if (!mac) { - _LOGW(LOGD_CORE, "Ignoring an iBFT record without a MAC address"); - g_hash_table_unref(nic); - continue; - } - - mac = g_ascii_strup(mac, -1); - if (!g_hash_table_insert(ibft, mac, nic)) - _LOGW(LOGD_CORE, "Duplicate iBFT record for %s", mac); - } - - g_dir_close(ibft_dir); - - return ibft; -} - -static gboolean -ip_setting_add_from_block(GHashTable *nic, NMConnection *connection, GError **error) -{ - NMSettingIPConfig *s_ip = NULL; - NMSettingIPConfig *s_ip4 = NULL; - NMSettingIPConfig *s_ip6 = NULL; - NMIPAddress * addr; - const char * s_ipaddr = NULL; - const char * s_prefix = NULL; - const char * s_gateway = NULL; - const char * s_dns1 = NULL; - const char * s_dns2 = NULL; - const char * s_origin = NULL; - const char * method = NULL; - int family; - gint64 prefix; - - s_ipaddr = (const char *) g_hash_table_lookup(nic, "ip-addr"); - s_prefix = (const char *) g_hash_table_lookup(nic, "prefix-len"); - s_gateway = (const char *) g_hash_table_lookup(nic, "gateway"); - s_dns1 = (const char *) g_hash_table_lookup(nic, "primary-dns"); - s_dns2 = (const char *) g_hash_table_lookup(nic, "secondary-dns"); - s_origin = (const char *) g_hash_table_lookup(nic, "origin"); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - if (!s_ip4) { - s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new(); - nm_connection_add_setting(connection, (NMSetting *) s_ip4); - } - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - if (!s_ip6) { - s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new(); - nm_connection_add_setting(connection, (NMSetting *) s_ip6); - - g_object_set(s_ip6, - NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, - (int) NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64, - NULL); - } - - family = get_ip_address_family(s_ipaddr, FALSE); - if (family == AF_UNSPEC) - family = get_ip_address_family(s_gateway, FALSE); - - switch (family) { - case AF_INET: - s_ip = s_ip4; - g_object_set(s_ip6, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED, - NULL); - break; - case AF_INET6: - s_ip = s_ip6; - g_object_set(s_ip4, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP4_CONFIG_METHOD_DISABLED, - NULL); - break; - default: - g_set_error(error, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_INVALID_CONNECTION, - "iBFT: invalid IP address '%s'.", - s_ipaddr); - return FALSE; - } - - if ((nm_streq0(s_origin, "3") && family == AF_INET) - || (nm_streq0(s_origin, "4") && family == AF_INET)) { - method = NM_SETTING_IP4_CONFIG_METHOD_AUTO; - } else if (nm_streq0(s_origin, "3") && family == AF_INET6) { - method = NM_SETTING_IP6_CONFIG_METHOD_DHCP; - } else if (nm_streq0(s_origin, "4") && family == AF_INET6) { - method = NM_SETTING_IP6_CONFIG_METHOD_AUTO; - } else if (family == AF_INET) { - method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL; - } else if (family == AF_INET6) { - method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL; - } else { - g_return_val_if_reached(FALSE); - } - g_object_set(s_ip, - NM_SETTING_IP_CONFIG_METHOD, - method, - NM_SETTING_IP_CONFIG_MAY_FAIL, - FALSE, - NULL); - - if (s_gateway && !nm_utils_ipaddr_is_valid(family, s_gateway)) { - g_set_error(error, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_INVALID_CONNECTION, - "iBFT: invalid IP gateway '%s'.", - s_gateway); - return FALSE; - } - - if (s_dns1 && !nm_utils_ipaddr_is_valid(family, s_dns1)) { - g_set_error(error, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_INVALID_CONNECTION, - "iBFT: invalid DNS1 address '%s'.", - s_dns1); - return FALSE; - } - - if (s_dns2 && !nm_utils_ipaddr_is_valid(family, s_dns2)) { - g_set_error(error, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_INVALID_CONNECTION, - "iBFT: invalid DNS2 address '%s'.", - s_dns2); - return FALSE; - } - - if (s_ipaddr) { - prefix = _nm_utils_ascii_str_to_int64(s_prefix, 10, 0, 128, -1); - if (prefix == -1) { - g_set_error(error, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_INVALID_CONNECTION, - "iBFT: invalid IP prefix '%s'.", - s_prefix); - return FALSE; - } - - addr = nm_ip_address_new(family, s_ipaddr, prefix, error); - if (!addr) { - g_prefix_error(error, "iBFT: "); - return FALSE; - } - - nm_setting_ip_config_add_address(s_ip, addr); - nm_ip_address_unref(addr); - - g_object_set(s_ip, NM_SETTING_IP_CONFIG_GATEWAY, s_gateway, NULL); - } - - if (s_dns1) - nm_setting_ip_config_add_dns(s_ip, s_dns1); - if (s_dns2) - nm_setting_ip_config_add_dns(s_ip, s_dns2); - - return TRUE; -} - -static gboolean -connection_setting_add(GHashTable * nic, - NMConnection *connection, - const char * type, - const char * prefix, - GError ** error) -{ - NMSetting * s_con; - char * id, *uuid; - const char *s_index, *s_hwaddr, *s_ipaddr, *s_vlanid; - - s_index = (const char *) g_hash_table_lookup(nic, "index"); - s_hwaddr = (const char *) g_hash_table_lookup(nic, "mac"); - s_ipaddr = (const char *) g_hash_table_lookup(nic, "ip-addr"); - s_vlanid = (const char *) g_hash_table_lookup(nic, "vlan"); - - if (!s_hwaddr) { - g_set_error_literal(error, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_INVALID_CONNECTION, - "iBFT: missing MAC address"); - return FALSE; - } - - id = g_strdup_printf("iBFT%s%s Connection%s%s", - prefix ? " " : "", - prefix ? prefix : "", - s_index ? " " : "", - s_index ? s_index : ""); - - uuid = _nm_utils_uuid_generate_from_strings("ibft", - s_hwaddr, - s_vlanid ? "V" : "v", - s_vlanid ? s_vlanid : "", - s_ipaddr ? "A" : "DHCP", - s_ipaddr ? s_ipaddr : "", - NULL); - - s_con = (NMSetting *) nm_connection_get_setting_connection(connection); - if (!s_con) { - s_con = nm_setting_connection_new(); - nm_connection_add_setting(connection, s_con); - } - - g_object_set(s_con, - NM_SETTING_CONNECTION_TYPE, - type, - NM_SETTING_CONNECTION_UUID, - uuid, - NM_SETTING_CONNECTION_ID, - id, - NM_SETTING_CONNECTION_INTERFACE_NAME, - NULL, - NULL); - - g_free(uuid); - g_free(id); - - return TRUE; -} - -static gboolean -is_ibft_vlan_device(GHashTable *nic) -{ - const char *s_vlan_id; - - g_assert(nic); - - s_vlan_id = (const char *) g_hash_table_lookup(nic, "vlan"); - - if (s_vlan_id) { - /* VLAN 0 is normally a valid VLAN ID, but in the iBFT case it - * means "no VLAN". - */ - if (_nm_utils_ascii_str_to_int64(s_vlan_id, 10, 1, 4095, -1) != -1) - return TRUE; - } - - return FALSE; -} - -static gboolean -vlan_setting_add_from_block(GHashTable *nic, NMConnection *connection, GError **error) -{ - NMSetting * s_vlan = NULL; - const char *vlan_id_str = NULL; - gint64 vlan_id = -1; - - g_assert(nic); - g_assert(connection); - - /* This won't fail since this function shouldn't be called unless the - * iBFT VLAN ID exists and is > 0. - */ - vlan_id_str = (const char *) g_hash_table_lookup(nic, "vlan"); - g_assert(vlan_id_str); - - /* VLAN 0 is normally a valid VLAN ID, but in the iBFT case it means "no VLAN" */ - vlan_id = _nm_utils_ascii_str_to_int64(vlan_id_str, 10, 1, 4095, -1); - if (vlan_id == -1) { - g_set_error(error, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid VLAN_ID '%s'", - vlan_id_str); - return FALSE; - } - - s_vlan = (NMSetting *) nm_connection_get_setting_vlan(connection); - if (!s_vlan) { - s_vlan = nm_setting_vlan_new(); - nm_connection_add_setting(connection, s_vlan); - } - - g_object_set(s_vlan, NM_SETTING_VLAN_ID, (guint32) vlan_id, NULL); - - return TRUE; -} - -static gboolean -wired_setting_add_from_block(GHashTable *nic, NMConnection *connection, GError **error) -{ - NMSetting * s_wired = NULL; - const char *hwaddr = NULL; - - g_assert(nic); - g_assert(connection); - - hwaddr = (const char *) g_hash_table_lookup(nic, "mac"); - if (!hwaddr) { - g_set_error_literal(error, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_INVALID_CONNECTION, - "iBFT: missing MAC address"); - return FALSE; - } - - if (!nm_utils_hwaddr_valid(hwaddr, ETH_ALEN)) { - g_set_error(error, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_INVALID_CONNECTION, - "iBFT: invalid MAC address '%s'.", - hwaddr); - return FALSE; - } - - s_wired = (NMSetting *) nm_connection_get_setting_wired(connection); - if (!s_wired) { - s_wired = nm_setting_wired_new(); - nm_connection_add_setting(connection, s_wired); - } - - g_object_set(s_wired, NM_SETTING_WIRED_MAC_ADDRESS, hwaddr, NULL); - - return TRUE; -} - -gboolean -nmi_ibft_update_connection_from_nic(NMConnection *connection, GHashTable *nic, GError **error) -{ - gboolean is_vlan = FALSE; - - g_assert(nic); - - is_vlan = is_ibft_vlan_device(nic); - if (is_vlan && !vlan_setting_add_from_block(nic, connection, error)) - return FALSE; - - /* Always have a wired setting; for VLAN it defines the parent */ - if (!wired_setting_add_from_block(nic, connection, error)) - return FALSE; - - if (!ip_setting_add_from_block(nic, connection, error)) - return FALSE; - - if (!connection_setting_add(nic, - connection, - is_vlan ? NM_SETTING_VLAN_SETTING_NAME - : NM_SETTING_WIRED_SETTING_NAME, - is_vlan ? "VLAN" : NULL, - error)) - return FALSE; - - if (!nm_connection_normalize(connection, NULL, NULL, error)) - return FALSE; - - return TRUE; -} diff --git a/src/core/initrd/tests/meson.build b/src/core/initrd/tests/meson.build deleted file mode 100644 index e47ff790..00000000 --- a/src/core/initrd/tests/meson.build +++ /dev/null @@ -1,24 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later - -test_units = [ - 'test-dt-reader', - 'test-ibft-reader', - 'test-cmdline-reader', -] - -foreach test_unit : test_units - exe = executable( - test_unit, - test_unit + '.c', - dependencies: libNetworkManagerTest_dep, - c_args: test_c_flags, - link_with: libnmi_core, - ) - - test( - 'initrd/' + test_unit, - test_script, - timeout: default_test_timeout, - args: test_args + [exe.full_path()], - ) -endforeach diff --git a/src/core/initrd/tests/sysfs-bad-dns1/class/net/eth0/address b/src/core/initrd/tests/sysfs-bad-dns1/class/net/eth0/address deleted file mode 100644 index 20659db7..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns1/class/net/eth0/address +++ /dev/null @@ -1 +0,0 @@ -00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/gateway b/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/gateway deleted file mode 100644 index bf6cf454..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/gateway +++ /dev/null @@ -1 +0,0 @@ -192.168.35.254 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/index b/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/index deleted file mode 100644 index c2270834..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/index +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/ip-addr b/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/ip-addr deleted file mode 100644 index 944c8d45..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/ip-addr +++ /dev/null @@ -1 +0,0 @@ -192.168.32.72 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/mac b/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/mac deleted file mode 100644 index 20659db7..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/mac +++ /dev/null @@ -1 +0,0 @@ -00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/origin b/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/origin deleted file mode 100644 index 56a6051c..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/origin +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/prefix-len b/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/prefix-len deleted file mode 100644 index 8fdd954d..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/prefix-len +++ /dev/null @@ -1 +0,0 @@ -22 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/primary-dns b/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/primary-dns deleted file mode 100644 index 2303dbdc..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/primary-dns +++ /dev/null @@ -1 +0,0 @@ -10000.500.250.1 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/secondary-dns b/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/secondary-dns deleted file mode 100644 index 2eb9e1d0..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/secondary-dns +++ /dev/null @@ -1 +0,0 @@ -10.16.255.3 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/subnet-mask b/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/subnet-mask deleted file mode 100644 index 7cb9d0a9..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/subnet-mask +++ /dev/null @@ -1 +0,0 @@ -255.255.252.0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/vlan b/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/vlan deleted file mode 100644 index c2270834..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/ethernet0/vlan +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/initiator/initiator-name b/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/initiator/initiator-name deleted file mode 100644 index 509a7ab8..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/initiator/initiator-name +++ /dev/null @@ -1 +0,0 @@ -iqn.pjones6 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/index b/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/index deleted file mode 100644 index c2270834..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/index +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/ip-addr b/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/ip-addr deleted file mode 100644 index 7450fdf9..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/ip-addr +++ /dev/null @@ -1 +0,0 @@ -10.16.52.16 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/lun b/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/lun deleted file mode 100644 index c43d0930..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/lun +++ /dev/null @@ -1 +0,0 @@ -00000000 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/port b/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/port deleted file mode 100644 index 58f0d919..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/port +++ /dev/null @@ -1 +0,0 @@ -3260 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/target-name b/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/target-name deleted file mode 100644 index 32c9450a..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns1/firmware/ibft/target0/target-name +++ /dev/null @@ -1 +0,0 @@ -iqn.0.2008-11.com.blahblah:iscsi0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns2/class/net/eth0/address b/src/core/initrd/tests/sysfs-bad-dns2/class/net/eth0/address deleted file mode 100644 index 20659db7..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns2/class/net/eth0/address +++ /dev/null @@ -1 +0,0 @@ -00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/gateway b/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/gateway deleted file mode 100644 index bf6cf454..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/gateway +++ /dev/null @@ -1 +0,0 @@ -192.168.35.254 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/index b/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/index deleted file mode 100644 index c2270834..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/index +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/ip-addr b/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/ip-addr deleted file mode 100644 index 944c8d45..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/ip-addr +++ /dev/null @@ -1 +0,0 @@ -192.168.32.72 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/mac b/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/mac deleted file mode 100644 index 20659db7..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/mac +++ /dev/null @@ -1 +0,0 @@ -00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/origin b/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/origin deleted file mode 100644 index 56a6051c..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/origin +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/prefix-len b/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/prefix-len deleted file mode 100644 index 8fdd954d..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/prefix-len +++ /dev/null @@ -1 +0,0 @@ -22 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/primary-dns b/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/primary-dns deleted file mode 100644 index 2e152cb0..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/primary-dns +++ /dev/null @@ -1 +0,0 @@ -10.16.255.2 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/secondary-dns b/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/secondary-dns deleted file mode 100644 index 5ed7b719..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/secondary-dns +++ /dev/null @@ -1 +0,0 @@ -blah.foo.bar.baz \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/subnet-mask b/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/subnet-mask deleted file mode 100644 index 7cb9d0a9..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/subnet-mask +++ /dev/null @@ -1 +0,0 @@ -255.255.252.0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/vlan b/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/vlan deleted file mode 100644 index c2270834..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/ethernet0/vlan +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/initiator/initiator-name b/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/initiator/initiator-name deleted file mode 100644 index 509a7ab8..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/initiator/initiator-name +++ /dev/null @@ -1 +0,0 @@ -iqn.pjones6 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/index b/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/index deleted file mode 100644 index c2270834..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/index +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/ip-addr b/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/ip-addr deleted file mode 100644 index 7450fdf9..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/ip-addr +++ /dev/null @@ -1 +0,0 @@ -10.16.52.16 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/lun b/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/lun deleted file mode 100644 index c43d0930..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/lun +++ /dev/null @@ -1 +0,0 @@ -00000000 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/port b/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/port deleted file mode 100644 index 58f0d919..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/port +++ /dev/null @@ -1 +0,0 @@ -3260 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/target-name b/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/target-name deleted file mode 100644 index 32c9450a..00000000 --- a/src/core/initrd/tests/sysfs-bad-dns2/firmware/ibft/target0/target-name +++ /dev/null @@ -1 +0,0 @@ -iqn.0.2008-11.com.blahblah:iscsi0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-gateway/class/net/eth0/address b/src/core/initrd/tests/sysfs-bad-gateway/class/net/eth0/address deleted file mode 100644 index 20659db7..00000000 --- a/src/core/initrd/tests/sysfs-bad-gateway/class/net/eth0/address +++ /dev/null @@ -1 +0,0 @@ -00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/gateway b/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/gateway deleted file mode 100644 index 1970856e..00000000 --- a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/gateway +++ /dev/null @@ -1 +0,0 @@ -bb.cc.dd.ee \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/index b/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/index deleted file mode 100644 index c2270834..00000000 --- a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/index +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/ip-addr b/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/ip-addr deleted file mode 100644 index 944c8d45..00000000 --- a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/ip-addr +++ /dev/null @@ -1 +0,0 @@ -192.168.32.72 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/mac b/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/mac deleted file mode 100644 index 20659db7..00000000 --- a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/mac +++ /dev/null @@ -1 +0,0 @@ -00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/origin b/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/origin deleted file mode 100644 index 56a6051c..00000000 --- a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/origin +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/prefix-len b/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/prefix-len deleted file mode 100644 index 8fdd954d..00000000 --- a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/prefix-len +++ /dev/null @@ -1 +0,0 @@ -22 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/primary-dns b/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/primary-dns deleted file mode 100644 index 2e152cb0..00000000 --- a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/primary-dns +++ /dev/null @@ -1 +0,0 @@ -10.16.255.2 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/secondary-dns b/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/secondary-dns deleted file mode 100644 index 2eb9e1d0..00000000 --- a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/secondary-dns +++ /dev/null @@ -1 +0,0 @@ -10.16.255.3 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/subnet-mask b/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/subnet-mask deleted file mode 100644 index 7cb9d0a9..00000000 --- a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/subnet-mask +++ /dev/null @@ -1 +0,0 @@ -255.255.252.0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/vlan b/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/vlan deleted file mode 100644 index c2270834..00000000 --- a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/ethernet0/vlan +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/initiator/initiator-name b/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/initiator/initiator-name deleted file mode 100644 index 509a7ab8..00000000 --- a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/initiator/initiator-name +++ /dev/null @@ -1 +0,0 @@ -iqn.pjones6 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/index b/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/index deleted file mode 100644 index c2270834..00000000 --- a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/index +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/ip-addr b/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/ip-addr deleted file mode 100644 index 7450fdf9..00000000 --- a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/ip-addr +++ /dev/null @@ -1 +0,0 @@ -10.16.52.16 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/lun b/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/lun deleted file mode 100644 index c43d0930..00000000 --- a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/lun +++ /dev/null @@ -1 +0,0 @@ -00000000 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/port b/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/port deleted file mode 100644 index 58f0d919..00000000 --- a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/port +++ /dev/null @@ -1 +0,0 @@ -3260 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/target-name b/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/target-name deleted file mode 100644 index 32c9450a..00000000 --- a/src/core/initrd/tests/sysfs-bad-gateway/firmware/ibft/target0/target-name +++ /dev/null @@ -1 +0,0 @@ -iqn.0.2008-11.com.blahblah:iscsi0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-ipaddr/class/net/eth0/address b/src/core/initrd/tests/sysfs-bad-ipaddr/class/net/eth0/address deleted file mode 100644 index 20659db7..00000000 --- a/src/core/initrd/tests/sysfs-bad-ipaddr/class/net/eth0/address +++ /dev/null @@ -1 +0,0 @@ -00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/gateway b/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/gateway deleted file mode 100644 index bf6cf454..00000000 --- a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/gateway +++ /dev/null @@ -1 +0,0 @@ -192.168.35.254 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/index b/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/index deleted file mode 100644 index c2270834..00000000 --- a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/index +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/ip-addr b/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/ip-addr deleted file mode 100644 index d526f324..00000000 --- a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/ip-addr +++ /dev/null @@ -1 +0,0 @@ -aa.bb.cc.dd \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/mac b/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/mac deleted file mode 100644 index 20659db7..00000000 --- a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/mac +++ /dev/null @@ -1 +0,0 @@ -00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/origin b/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/origin deleted file mode 100644 index 56a6051c..00000000 --- a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/origin +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/prefix-len b/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/prefix-len deleted file mode 100644 index 8fdd954d..00000000 --- a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/prefix-len +++ /dev/null @@ -1 +0,0 @@ -22 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/primary-dns b/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/primary-dns deleted file mode 100644 index 2e152cb0..00000000 --- a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/primary-dns +++ /dev/null @@ -1 +0,0 @@ -10.16.255.2 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/secondary-dns b/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/secondary-dns deleted file mode 100644 index 2eb9e1d0..00000000 --- a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/secondary-dns +++ /dev/null @@ -1 +0,0 @@ -10.16.255.3 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/subnet-mask b/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/subnet-mask deleted file mode 100644 index 7cb9d0a9..00000000 --- a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/subnet-mask +++ /dev/null @@ -1 +0,0 @@ -255.255.252.0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/vlan b/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/vlan deleted file mode 100644 index c2270834..00000000 --- a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/ethernet0/vlan +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/initiator/initiator-name b/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/initiator/initiator-name deleted file mode 100644 index 509a7ab8..00000000 --- a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/initiator/initiator-name +++ /dev/null @@ -1 +0,0 @@ -iqn.pjones6 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/index b/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/index deleted file mode 100644 index c2270834..00000000 --- a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/index +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/ip-addr b/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/ip-addr deleted file mode 100644 index 7450fdf9..00000000 --- a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/ip-addr +++ /dev/null @@ -1 +0,0 @@ -10.16.52.16 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/lun b/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/lun deleted file mode 100644 index c43d0930..00000000 --- a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/lun +++ /dev/null @@ -1 +0,0 @@ -00000000 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/port b/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/port deleted file mode 100644 index 58f0d919..00000000 --- a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/port +++ /dev/null @@ -1 +0,0 @@ -3260 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/target-name b/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/target-name deleted file mode 100644 index 32c9450a..00000000 --- a/src/core/initrd/tests/sysfs-bad-ipaddr/firmware/ibft/target0/target-name +++ /dev/null @@ -1 +0,0 @@ -iqn.0.2008-11.com.blahblah:iscsi0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/class/net/eth0/address b/src/core/initrd/tests/sysfs-dhcp/class/net/eth0/address deleted file mode 100644 index 20659db7..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/class/net/eth0/address +++ /dev/null @@ -1 +0,0 @@ -00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/class/net/eth1/address b/src/core/initrd/tests/sysfs-dhcp/class/net/eth1/address deleted file mode 100644 index befa7850..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/class/net/eth1/address +++ /dev/null @@ -1 +0,0 @@ -00:33:21:98:b9:f1 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/gateway b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/gateway deleted file mode 100644 index 59ea5b82..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/gateway +++ /dev/null @@ -1 +0,0 @@ -10.16.52.254 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/index b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/index deleted file mode 100644 index c2270834..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/index +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/mac b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/mac deleted file mode 100644 index 20659db7..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/mac +++ /dev/null @@ -1 +0,0 @@ -00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/origin b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/origin deleted file mode 100644 index e440e5c8..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/origin +++ /dev/null @@ -1 +0,0 @@ -3 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/primary-dns b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/primary-dns deleted file mode 100644 index 2e152cb0..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/primary-dns +++ /dev/null @@ -1 +0,0 @@ -10.16.255.2 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/secondary-dns b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/secondary-dns deleted file mode 100644 index 2eb9e1d0..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/secondary-dns +++ /dev/null @@ -1 +0,0 @@ -10.16.255.3 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/vlan b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/vlan deleted file mode 100644 index c2270834..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet0/vlan +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/gateway b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/gateway deleted file mode 100644 index 59ea5b82..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/gateway +++ /dev/null @@ -1 +0,0 @@ -10.16.52.254 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/index b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/index deleted file mode 100644 index 56a6051c..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/index +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/mac b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/mac deleted file mode 100644 index befa7850..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/mac +++ /dev/null @@ -1 +0,0 @@ -00:33:21:98:b9:f1 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/origin b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/origin deleted file mode 100644 index e440e5c8..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/origin +++ /dev/null @@ -1 +0,0 @@ -3 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/primary-dns b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/primary-dns deleted file mode 100644 index 2e152cb0..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/primary-dns +++ /dev/null @@ -1 +0,0 @@ -10.16.255.2 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/secondary-dns b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/secondary-dns deleted file mode 100644 index 2eb9e1d0..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/secondary-dns +++ /dev/null @@ -1 +0,0 @@ -10.16.255.3 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/vlan b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/vlan deleted file mode 100644 index c2270834..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/ethernet1/vlan +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/initiator/initiator-name b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/initiator/initiator-name deleted file mode 100644 index 509a7ab8..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/initiator/initiator-name +++ /dev/null @@ -1 +0,0 @@ -iqn.pjones6 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target0/index b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target0/index deleted file mode 100644 index c2270834..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target0/index +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target0/ip-addr b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target0/ip-addr deleted file mode 100644 index 7450fdf9..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target0/ip-addr +++ /dev/null @@ -1 +0,0 @@ -10.16.52.16 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target0/lun b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target0/lun deleted file mode 100644 index c43d0930..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target0/lun +++ /dev/null @@ -1 +0,0 @@ -00000000 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target0/port b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target0/port deleted file mode 100644 index 58f0d919..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target0/port +++ /dev/null @@ -1 +0,0 @@ -3260 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target0/target-name b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target0/target-name deleted file mode 100644 index 32c9450a..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target0/target-name +++ /dev/null @@ -1 +0,0 @@ -iqn.0.2008-11.com.blahblah:iscsi0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target1/index b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target1/index deleted file mode 100644 index 56a6051c..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target1/index +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target1/ip-addr b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target1/ip-addr deleted file mode 100644 index 7450fdf9..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target1/ip-addr +++ /dev/null @@ -1 +0,0 @@ -10.16.52.16 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target1/lun b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target1/lun deleted file mode 100644 index c43d0930..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target1/lun +++ /dev/null @@ -1 +0,0 @@ -00000000 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target1/port b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target1/port deleted file mode 100644 index 58f0d919..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target1/port +++ /dev/null @@ -1 +0,0 @@ -3260 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target1/target-name b/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target1/target-name deleted file mode 100644 index ac3a6a2a..00000000 --- a/src/core/initrd/tests/sysfs-dhcp/firmware/ibft/target1/target-name +++ /dev/null @@ -1 +0,0 @@ -iqn.1.2008-11.com.blahblah:iscsi1 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dt-tftp/firmware/devicetree/base/chosen/bootpath b/src/core/initrd/tests/sysfs-dt-tftp/firmware/devicetree/base/chosen/bootpath deleted file mode 100644 index 6f069ae0..00000000 Binary files a/src/core/initrd/tests/sysfs-dt-tftp/firmware/devicetree/base/chosen/bootpath and /dev/null differ diff --git a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/bootp-request b/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/bootp-request deleted file mode 100644 index 034d423e..00000000 Binary files a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/bootp-request and /dev/null differ diff --git a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/bootp-response b/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/bootp-response deleted file mode 100644 index 25982d6f..00000000 Binary files a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/bootp-response and /dev/null differ diff --git a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/bootpath b/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/bootpath deleted file mode 100644 index db880702..00000000 Binary files a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/bootpath and /dev/null differ diff --git a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/broadcast-ip b/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/broadcast-ip deleted file mode 100644 index 7bde8641..00000000 --- a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/broadcast-ip +++ /dev/null @@ -1 +0,0 @@ -ÿÿÿÿ \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/client-ip b/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/client-ip deleted file mode 100644 index f108ba9b..00000000 --- a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/client-ip +++ /dev/null @@ -1,2 +0,0 @@ - -+ \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/client-name b/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/client-name deleted file mode 100644 index fe0f76b8..00000000 Binary files a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/client-name and /dev/null differ diff --git a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/domain-name b/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/domain-name deleted file mode 100644 index b34f9f96..00000000 Binary files a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/domain-name and /dev/null differ diff --git a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/gateway-ip b/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/gateway-ip deleted file mode 100644 index f0361835..00000000 --- a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/gateway-ip +++ /dev/null @@ -1,2 +0,0 @@ - -+þ \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/name b/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/name deleted file mode 100644 index f3e58052..00000000 Binary files a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/name and /dev/null differ diff --git a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/netmask-ip b/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/netmask-ip deleted file mode 100644 index d441cd83..00000000 Binary files a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/netmask-ip and /dev/null differ diff --git a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/root-path b/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/root-path deleted file mode 100644 index f76dd238..00000000 Binary files a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/root-path and /dev/null differ diff --git a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/server-ip b/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/server-ip deleted file mode 100644 index a2a4b2e8..00000000 --- a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/server-ip +++ /dev/null @@ -1,2 +0,0 @@ - -& \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/tftp-file b/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/tftp-file deleted file mode 100644 index c0e0e330..00000000 Binary files a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/tftp-file and /dev/null differ diff --git a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/vendor-options b/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/vendor-options deleted file mode 100644 index f76dd238..00000000 Binary files a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/chosen/vendor-options and /dev/null differ diff --git a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/ethernet/device_type b/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/ethernet/device_type deleted file mode 100644 index df3c9d9f..00000000 Binary files a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/ethernet/device_type and /dev/null differ diff --git a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/ethernet/local-mac-address b/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/ethernet/local-mac-address deleted file mode 100644 index c983e752..00000000 --- a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/ethernet/local-mac-address +++ /dev/null @@ -1 +0,0 @@ -¬>åØ \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/ethernet/mac-address b/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/ethernet/mac-address deleted file mode 100644 index c983e752..00000000 --- a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/ethernet/mac-address +++ /dev/null @@ -1 +0,0 @@ -¬>åØ \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/ethernet/name b/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/ethernet/name deleted file mode 100644 index 88eaddfe..00000000 Binary files a/src/core/initrd/tests/sysfs-dt/firmware/devicetree/base/ethernet/name and /dev/null differ diff --git a/src/core/initrd/tests/sysfs-static/class/net/eth0/address b/src/core/initrd/tests/sysfs-static/class/net/eth0/address deleted file mode 100644 index 20659db7..00000000 --- a/src/core/initrd/tests/sysfs-static/class/net/eth0/address +++ /dev/null @@ -1 +0,0 @@ -00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/class/net/eth1/address b/src/core/initrd/tests/sysfs-static/class/net/eth1/address deleted file mode 100644 index befa7850..00000000 --- a/src/core/initrd/tests/sysfs-static/class/net/eth1/address +++ /dev/null @@ -1 +0,0 @@ -00:33:21:98:b9:f1 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/gateway b/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/gateway deleted file mode 100644 index bf6cf454..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/gateway +++ /dev/null @@ -1 +0,0 @@ -192.168.35.254 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/index b/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/index deleted file mode 100644 index c2270834..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/index +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/ip-addr b/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/ip-addr deleted file mode 100644 index 944c8d45..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/ip-addr +++ /dev/null @@ -1 +0,0 @@ -192.168.32.72 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/mac b/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/mac deleted file mode 100644 index 20659db7..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/mac +++ /dev/null @@ -1 +0,0 @@ -00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/origin b/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/origin deleted file mode 100644 index 56a6051c..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/origin +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/prefix-len b/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/prefix-len deleted file mode 100644 index 8fdd954d..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/prefix-len +++ /dev/null @@ -1 +0,0 @@ -22 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/primary-dns b/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/primary-dns deleted file mode 100644 index 2e152cb0..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/primary-dns +++ /dev/null @@ -1 +0,0 @@ -10.16.255.2 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/secondary-dns b/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/secondary-dns deleted file mode 100644 index 2eb9e1d0..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/secondary-dns +++ /dev/null @@ -1 +0,0 @@ -10.16.255.3 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/subnet-mask b/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/subnet-mask deleted file mode 100644 index 7cb9d0a9..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/subnet-mask +++ /dev/null @@ -1 +0,0 @@ -255.255.252.0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/vlan b/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/vlan deleted file mode 100644 index c2270834..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet0/vlan +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/gateway b/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/gateway deleted file mode 100644 index 59ea5b82..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/gateway +++ /dev/null @@ -1 +0,0 @@ -10.16.52.254 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/index b/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/index deleted file mode 100644 index 56a6051c..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/index +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/mac b/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/mac deleted file mode 100644 index befa7850..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/mac +++ /dev/null @@ -1 +0,0 @@ -00:33:21:98:b9:f1 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/origin b/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/origin deleted file mode 100644 index e440e5c8..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/origin +++ /dev/null @@ -1 +0,0 @@ -3 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/primary-dns b/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/primary-dns deleted file mode 100644 index 2e152cb0..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/primary-dns +++ /dev/null @@ -1 +0,0 @@ -10.16.255.2 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/secondary-dns b/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/secondary-dns deleted file mode 100644 index 2eb9e1d0..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/secondary-dns +++ /dev/null @@ -1 +0,0 @@ -10.16.255.3 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/vlan b/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/vlan deleted file mode 100644 index c2270834..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/ethernet1/vlan +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/initiator/initiator-name b/src/core/initrd/tests/sysfs-static/firmware/ibft/initiator/initiator-name deleted file mode 100644 index 509a7ab8..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/initiator/initiator-name +++ /dev/null @@ -1 +0,0 @@ -iqn.pjones6 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/target0/index b/src/core/initrd/tests/sysfs-static/firmware/ibft/target0/index deleted file mode 100644 index c2270834..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/target0/index +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/target0/ip-addr b/src/core/initrd/tests/sysfs-static/firmware/ibft/target0/ip-addr deleted file mode 100644 index 7450fdf9..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/target0/ip-addr +++ /dev/null @@ -1 +0,0 @@ -10.16.52.16 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/target0/lun b/src/core/initrd/tests/sysfs-static/firmware/ibft/target0/lun deleted file mode 100644 index c43d0930..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/target0/lun +++ /dev/null @@ -1 +0,0 @@ -00000000 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/target0/port b/src/core/initrd/tests/sysfs-static/firmware/ibft/target0/port deleted file mode 100644 index 58f0d919..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/target0/port +++ /dev/null @@ -1 +0,0 @@ -3260 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/target0/target-name b/src/core/initrd/tests/sysfs-static/firmware/ibft/target0/target-name deleted file mode 100644 index 32c9450a..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/target0/target-name +++ /dev/null @@ -1 +0,0 @@ -iqn.0.2008-11.com.blahblah:iscsi0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/target1/index b/src/core/initrd/tests/sysfs-static/firmware/ibft/target1/index deleted file mode 100644 index 56a6051c..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/target1/index +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/target1/ip-addr b/src/core/initrd/tests/sysfs-static/firmware/ibft/target1/ip-addr deleted file mode 100644 index 7450fdf9..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/target1/ip-addr +++ /dev/null @@ -1 +0,0 @@ -10.16.52.16 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/target1/lun b/src/core/initrd/tests/sysfs-static/firmware/ibft/target1/lun deleted file mode 100644 index c43d0930..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/target1/lun +++ /dev/null @@ -1 +0,0 @@ -00000000 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/target1/port b/src/core/initrd/tests/sysfs-static/firmware/ibft/target1/port deleted file mode 100644 index 58f0d919..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/target1/port +++ /dev/null @@ -1 +0,0 @@ -3260 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-static/firmware/ibft/target1/target-name b/src/core/initrd/tests/sysfs-static/firmware/ibft/target1/target-name deleted file mode 100644 index ac3a6a2a..00000000 --- a/src/core/initrd/tests/sysfs-static/firmware/ibft/target1/target-name +++ /dev/null @@ -1 +0,0 @@ -iqn.1.2008-11.com.blahblah:iscsi1 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-vlan/class/net/eth0/address b/src/core/initrd/tests/sysfs-vlan/class/net/eth0/address deleted file mode 100644 index 20659db7..00000000 --- a/src/core/initrd/tests/sysfs-vlan/class/net/eth0/address +++ /dev/null @@ -1 +0,0 @@ -00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/index b/src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/index deleted file mode 100644 index c2270834..00000000 --- a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/index +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/ip-addr b/src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/ip-addr deleted file mode 100644 index 4923230c..00000000 --- a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/ip-addr +++ /dev/null @@ -1 +0,0 @@ -192.168.6.200 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/mac b/src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/mac deleted file mode 100644 index 20659db7..00000000 --- a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/mac +++ /dev/null @@ -1 +0,0 @@ -00:33:21:98:b9:f0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/origin b/src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/origin deleted file mode 100644 index 56a6051c..00000000 --- a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/origin +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/prefix-len b/src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/prefix-len deleted file mode 100644 index cabf43b5..00000000 --- a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/prefix-len +++ /dev/null @@ -1 +0,0 @@ -24 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/subnet-mask b/src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/subnet-mask deleted file mode 100644 index 5a279b41..00000000 --- a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/subnet-mask +++ /dev/null @@ -1 +0,0 @@ -255.255.255.0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/vlan b/src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/vlan deleted file mode 100644 index d800886d..00000000 --- a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/ethernet0/vlan +++ /dev/null @@ -1 +0,0 @@ -123 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/initiator/initiator-name b/src/core/initrd/tests/sysfs-vlan/firmware/ibft/initiator/initiator-name deleted file mode 100644 index 8e9cd2c4..00000000 --- a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/initiator/initiator-name +++ /dev/null @@ -1 +0,0 @@ -iqn.2010-04.org.ipxe:d05faa97-c4be-44f6-a723-efde9aa399a0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/target0/index b/src/core/initrd/tests/sysfs-vlan/firmware/ibft/target0/index deleted file mode 100644 index c2270834..00000000 --- a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/target0/index +++ /dev/null @@ -1 +0,0 @@ -0 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/target0/ip-addr b/src/core/initrd/tests/sysfs-vlan/firmware/ibft/target0/ip-addr deleted file mode 100644 index a32ce01b..00000000 --- a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/target0/ip-addr +++ /dev/null @@ -1 +0,0 @@ -192.168.6.32 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/target0/lun b/src/core/initrd/tests/sysfs-vlan/firmware/ibft/target0/lun deleted file mode 100644 index f309ca6a..00000000 --- a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/target0/lun +++ /dev/null @@ -1 +0,0 @@ -01000000 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/target0/port b/src/core/initrd/tests/sysfs-vlan/firmware/ibft/target0/port deleted file mode 100644 index 58f0d919..00000000 --- a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/target0/port +++ /dev/null @@ -1 +0,0 @@ -3260 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/target0/target-name b/src/core/initrd/tests/sysfs-vlan/firmware/ibft/target0/target-name deleted file mode 100644 index f0e61157..00000000 --- a/src/core/initrd/tests/sysfs-vlan/firmware/ibft/target0/target-name +++ /dev/null @@ -1 +0,0 @@ -iqn.2003-01.org.x:disk1 \ No newline at end of file diff --git a/src/core/initrd/tests/sysfs/class/net/eth0/address b/src/core/initrd/tests/sysfs/class/net/eth0/address deleted file mode 100644 index 1f2f610e..00000000 --- a/src/core/initrd/tests/sysfs/class/net/eth0/address +++ /dev/null @@ -1 +0,0 @@ -00:53:00:AB:00:01 diff --git a/src/core/initrd/tests/sysfs/class/net/eth2/address b/src/core/initrd/tests/sysfs/class/net/eth2/address deleted file mode 100644 index 6ec1078a..00000000 --- a/src/core/initrd/tests/sysfs/class/net/eth2/address +++ /dev/null @@ -1 +0,0 @@ -00:53:06:66:ab:01 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/acpi_header/oem_id b/src/core/initrd/tests/sysfs/firmware/ibft/acpi_header/oem_id deleted file mode 100644 index 590d9cd2..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/acpi_header/oem_id +++ /dev/null @@ -1 +0,0 @@ -NMTst diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/acpi_header/oem_table_id b/src/core/initrd/tests/sysfs/firmware/ibft/acpi_header/oem_table_id deleted file mode 100644 index 35d4d09c..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/acpi_header/oem_table_id +++ /dev/null @@ -1 +0,0 @@ -Whatevs diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/acpi_header/signature b/src/core/initrd/tests/sysfs/firmware/ibft/acpi_header/signature deleted file mode 100644 index e3a5d7ef..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/acpi_header/signature +++ /dev/null @@ -1 +0,0 @@ -IBFT diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/dhcp b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/dhcp deleted file mode 100644 index 98a0d797..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/dhcp +++ /dev/null @@ -1 +0,0 @@ -2001:0db8:0000:0000:0000:0000:0000:0002 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/flags b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/flags deleted file mode 100644 index 00750edc..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/flags +++ /dev/null @@ -1 +0,0 @@ -3 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/gateway b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/gateway deleted file mode 100644 index 7f378f8f..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/gateway +++ /dev/null @@ -1 +0,0 @@ -2001:0db8:0000:0000:0000:0000:0000:0001 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/hostname b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/hostname deleted file mode 100644 index 3ed5163c..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/hostname +++ /dev/null @@ -1 +0,0 @@ -host0.example.com diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/index b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/index deleted file mode 100644 index 573541ac..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/index +++ /dev/null @@ -1 +0,0 @@ -0 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/ip-addr b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/ip-addr deleted file mode 100644 index 98a0d797..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/ip-addr +++ /dev/null @@ -1 +0,0 @@ -2001:0db8:0000:0000:0000:0000:0000:0002 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/mac b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/mac deleted file mode 100644 index f2441319..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/mac +++ /dev/null @@ -1 +0,0 @@ -00:53:00:ab:00:01 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/origin b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/origin deleted file mode 100644 index b8626c4c..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/origin +++ /dev/null @@ -1 +0,0 @@ -4 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/prefix-len b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/prefix-len deleted file mode 100644 index 900731ff..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/prefix-len +++ /dev/null @@ -1 +0,0 @@ -64 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/primary-dns b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/primary-dns deleted file mode 100644 index e7511d5a..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/primary-dns +++ /dev/null @@ -1 +0,0 @@ -2001:0db8:0000:0000:0000:0000:0000:0053 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/secondary-dns b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/secondary-dns deleted file mode 100644 index 1f6c5c95..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/secondary-dns +++ /dev/null @@ -1 +0,0 @@ -2001:0db8:0000:0000:0000:0000:0000:5353 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/subnet-mask b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/subnet-mask deleted file mode 100644 index 5df93454..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/subnet-mask +++ /dev/null @@ -1 +0,0 @@ -255.255.255.255 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/vlan b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/vlan deleted file mode 100644 index 7cc86ad1..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet0/vlan +++ /dev/null @@ -1 +0,0 @@ -666 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/dhcp b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/dhcp deleted file mode 100644 index 61ef5585..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/dhcp +++ /dev/null @@ -1 +0,0 @@ -192.0.2.2 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/flags b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/flags deleted file mode 100644 index 00750edc..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/flags +++ /dev/null @@ -1 +0,0 @@ -3 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/gateway b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/gateway deleted file mode 100644 index 2096f194..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/gateway +++ /dev/null @@ -1 +0,0 @@ -192.0.2.1 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/hostname b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/hostname deleted file mode 100644 index 5dc539d5..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/hostname +++ /dev/null @@ -1 +0,0 @@ -host2.example.com diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/index b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/index deleted file mode 100644 index 0cfbf088..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/index +++ /dev/null @@ -1 +0,0 @@ -2 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/ip-addr b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/ip-addr deleted file mode 100644 index 61ef5585..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/ip-addr +++ /dev/null @@ -1 +0,0 @@ -192.0.2.2 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/mac b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/mac deleted file mode 100644 index 2fc3d525..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/mac +++ /dev/null @@ -1 +0,0 @@ -00:53:06:66:AB:01 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/origin b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/origin deleted file mode 100644 index 00750edc..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/origin +++ /dev/null @@ -1 +0,0 @@ -3 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/prefix-len b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/prefix-len deleted file mode 100644 index a45fd52c..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/prefix-len +++ /dev/null @@ -1 +0,0 @@ -24 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/primary-dns b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/primary-dns deleted file mode 100644 index 6fa8c742..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/primary-dns +++ /dev/null @@ -1 +0,0 @@ -192.0.2.53 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/secondary-dns b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/secondary-dns deleted file mode 100644 index a7269ff5..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/secondary-dns +++ /dev/null @@ -1 +0,0 @@ -192.0.2.54 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/subnet-mask b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/subnet-mask deleted file mode 100644 index d30f9e9f..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/subnet-mask +++ /dev/null @@ -1 +0,0 @@ -255.255.255.0 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/vlan b/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/vlan deleted file mode 100644 index 573541ac..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/ethernet2/vlan +++ /dev/null @@ -1 +0,0 @@ -0 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/initiator/flags b/src/core/initrd/tests/sysfs/firmware/ibft/initiator/flags deleted file mode 100644 index 00750edc..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/initiator/flags +++ /dev/null @@ -1 +0,0 @@ -3 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/initiator/index b/src/core/initrd/tests/sysfs/firmware/ibft/initiator/index deleted file mode 100644 index 573541ac..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/initiator/index +++ /dev/null @@ -1 +0,0 @@ -0 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/initiator/initiator-name b/src/core/initrd/tests/sysfs/firmware/ibft/initiator/initiator-name deleted file mode 100644 index 337b5a0f..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/initiator/initiator-name +++ /dev/null @@ -1 +0,0 @@ -iqn.1994-05.com.example.initiator:48b055856417 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/initiator/isns-server b/src/core/initrd/tests/sysfs/firmware/ibft/initiator/isns-server deleted file mode 100644 index 4aff9398..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/initiator/isns-server +++ /dev/null @@ -1 +0,0 @@ -2001:0db8:0000:0000:0000:0000:0000:3205 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/initiator/pri-radius-server b/src/core/initrd/tests/sysfs/firmware/ibft/initiator/pri-radius-server deleted file mode 100644 index a26fb649..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/initiator/pri-radius-server +++ /dev/null @@ -1 +0,0 @@ -2001:0db8:0000:0000:0000:0000:0000:1812 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/initiator/sec-radius-server b/src/core/initrd/tests/sysfs/firmware/ibft/initiator/sec-radius-server deleted file mode 100644 index 908be27f..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/initiator/sec-radius-server +++ /dev/null @@ -1 +0,0 @@ -192.0.2.181 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/initiator/slp-server b/src/core/initrd/tests/sysfs/firmware/ibft/initiator/slp-server deleted file mode 100644 index fca9e24b..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/initiator/slp-server +++ /dev/null @@ -1 +0,0 @@ -2001:0db8:0000:0000:0000:0000:0000:0427 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/target0/chap-type b/src/core/initrd/tests/sysfs/firmware/ibft/target0/chap-type deleted file mode 100644 index 573541ac..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/target0/chap-type +++ /dev/null @@ -1 +0,0 @@ -0 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/target0/flags b/src/core/initrd/tests/sysfs/firmware/ibft/target0/flags deleted file mode 100644 index 00750edc..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/target0/flags +++ /dev/null @@ -1 +0,0 @@ -3 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/target0/index b/src/core/initrd/tests/sysfs/firmware/ibft/target0/index deleted file mode 100644 index 573541ac..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/target0/index +++ /dev/null @@ -1 +0,0 @@ -0 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/target0/ip-addr b/src/core/initrd/tests/sysfs/firmware/ibft/target0/ip-addr deleted file mode 100644 index 994b6e9c..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/target0/ip-addr +++ /dev/null @@ -1 +0,0 @@ -2001:0db8:0000:0000:0000:0000:0000:3260 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/target0/lun b/src/core/initrd/tests/sysfs/firmware/ibft/target0/lun deleted file mode 100644 index 7c295bd4..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/target0/lun +++ /dev/null @@ -1 +0,0 @@ -01000000 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/target0/nic-assoc b/src/core/initrd/tests/sysfs/firmware/ibft/target0/nic-assoc deleted file mode 100644 index 573541ac..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/target0/nic-assoc +++ /dev/null @@ -1 +0,0 @@ -0 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/target0/port b/src/core/initrd/tests/sysfs/firmware/ibft/target0/port deleted file mode 100644 index 53f0295f..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/target0/port +++ /dev/null @@ -1 +0,0 @@ -3260 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/target2/chap-type b/src/core/initrd/tests/sysfs/firmware/ibft/target2/chap-type deleted file mode 100644 index 573541ac..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/target2/chap-type +++ /dev/null @@ -1 +0,0 @@ -0 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/target2/flags b/src/core/initrd/tests/sysfs/firmware/ibft/target2/flags deleted file mode 100644 index 00750edc..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/target2/flags +++ /dev/null @@ -1 +0,0 @@ -3 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/target2/index b/src/core/initrd/tests/sysfs/firmware/ibft/target2/index deleted file mode 100644 index 0cfbf088..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/target2/index +++ /dev/null @@ -1 +0,0 @@ -2 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/target2/ip-addr b/src/core/initrd/tests/sysfs/firmware/ibft/target2/ip-addr deleted file mode 100644 index a210477e..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/target2/ip-addr +++ /dev/null @@ -1 +0,0 @@ -2001:0db8:0000:0000:0000:0000:0002:3260 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/target2/lun b/src/core/initrd/tests/sysfs/firmware/ibft/target2/lun deleted file mode 100644 index 7c295bd4..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/target2/lun +++ /dev/null @@ -1 +0,0 @@ -01000000 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/target2/nic-assoc b/src/core/initrd/tests/sysfs/firmware/ibft/target2/nic-assoc deleted file mode 100644 index 0cfbf088..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/target2/nic-assoc +++ /dev/null @@ -1 +0,0 @@ -2 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/target2/port b/src/core/initrd/tests/sysfs/firmware/ibft/target2/port deleted file mode 100644 index 53f0295f..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/target2/port +++ /dev/null @@ -1 +0,0 @@ -3260 diff --git a/src/core/initrd/tests/sysfs/firmware/ibft/target2/target-name b/src/core/initrd/tests/sysfs/firmware/ibft/target2/target-name deleted file mode 100644 index f4094320..00000000 --- a/src/core/initrd/tests/sysfs/firmware/ibft/target2/target-name +++ /dev/null @@ -1 +0,0 @@ -iqn.1994-05.com.example.target:48b055851337 diff --git a/src/core/initrd/tests/test-cmdline-reader.c b/src/core/initrd/tests/test-cmdline-reader.c deleted file mode 100644 index 33fb22d3..00000000 --- a/src/core/initrd/tests/test-cmdline-reader.c +++ /dev/null @@ -1,2182 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2018 Red Hat, Inc. - */ - -#include "src/core/nm-default-daemon.h" - -#include -#include -#include -#include -#include -#include - -#include "nm-core-internal.h" -#include "NetworkManagerUtils.h" - -#include "../nm-initrd-generator.h" - -#include "nm-test-utils-core.h" - -#define TEST_INITRD_DIR NM_BUILD_SRCDIR "/src/core/initrd/tests" - -/*****************************************************************************/ - -#define _parse(ARGV, out_hostname, out_carrier_timeout_sec) \ - ({ \ - const char *const *const _ARGV = (ARGV); \ - char **const _out_hostname = (out_hostname); \ - gint64 *const _out_carrier_timeout_sec = (out_carrier_timeout_sec); \ - GHashTable * _connections; \ - \ - _connections = nmi_cmdline_reader_parse(TEST_INITRD_DIR "/sysfs", \ - _ARGV, \ - _out_hostname, \ - _out_carrier_timeout_sec); \ - \ - g_assert(_connections); \ - \ - _connections; \ - }) - -#define _parse_cons(ARGV) \ - ({ \ - GHashTable * _con_connections; \ - gs_free char *_con_hostname = NULL; \ - gint64 _con_carrier_timeout_sec = 0; \ - \ - _con_connections = _parse((ARGV), \ - nmtst_get_rand_bool() ? &_con_hostname : NULL, \ - nmtst_get_rand_bool() ? &_con_carrier_timeout_sec : NULL); \ - g_assert_cmpstr(_con_hostname, ==, NULL); \ - g_assert_cmpint(_con_carrier_timeout_sec, ==, 0); \ - \ - _con_connections; \ - }) - -#define _parse_con(ARGV, connection_name) \ - ({ \ - gs_unref_hashtable GHashTable *_1_connections = NULL; \ - NMConnection * _1_connection; \ - const char *const _1_connection_name = (connection_name); \ - \ - g_assert(_1_connection_name); \ - \ - _1_connections = _parse_cons((ARGV)); \ - \ - g_assert_cmpint(g_hash_table_size(_1_connections), ==, 1); \ - \ - _1_connection = g_hash_table_lookup(_1_connections, _1_connection_name); \ - g_assert(NM_IS_CONNECTION(_1_connection)); \ - \ - nmtst_assert_connection_verifies_without_normalization(_1_connection); \ - \ - NM_CONNECTION(g_object_ref(_1_connection)); \ - }) - -/*****************************************************************************/ - -static void -test_auto(void) -{ - const char *const *ARGV = NM_MAKE_STRV("ip=auto"); - gs_unref_object NMConnection *connection = NULL; - NMSettingConnection * s_con; - NMSettingWired * s_wired; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - - connection = _parse_con(ARGV, "default_connection"); - - g_assert(!nm_connection_get_setting_vlan(connection)); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "Wired Connection"); - g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0); - g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con), - ==, - NM_CONNECTION_MULTI_CONNECT_MULTIPLE); - g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1); - - g_assert(nm_setting_connection_get_autoconnect(s_con)); - - s_wired = nm_connection_get_setting_wired(connection); - g_assert(s_wired); - g_assert(!nm_setting_wired_get_mac_address(s_wired)); - g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 0); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4)); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 0); - g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 0); - g_assert(!nm_setting_ip_config_get_gateway(s_ip4)); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6)); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 0); - g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip6), ==, 0); - g_assert(!nm_setting_ip_config_get_gateway(s_ip6)); -} - -static void -test_dhcp_with_hostname(void) -{ - gs_unref_hashtable GHashTable *connections = NULL; - const char *const * ARGV = NM_MAKE_STRV("ip=::::host1::dhcp"); - NMConnection * connection; - NMSettingConnection * s_con; - NMSettingWired * s_wired; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - gs_free char * hostname = NULL; - gint64 carrier_timeout_sec = 0; - - connections = _parse(ARGV, &hostname, &carrier_timeout_sec); - g_assert_cmpint(g_hash_table_size(connections), ==, 1); - g_assert_cmpstr(hostname, ==, "host1"); - g_assert_cmpint(carrier_timeout_sec, ==, 0); - - connection = g_hash_table_lookup(connections, "default_connection"); - - nmtst_assert_connection_verifies_without_normalization(connection); - - g_assert(!nm_connection_get_setting_vlan(connection)); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "Wired Connection"); - g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0); - g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con), - ==, - NM_CONNECTION_MULTI_CONNECT_MULTIPLE); - g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1); - - g_assert(nm_setting_connection_get_autoconnect(s_con)); - - s_wired = nm_connection_get_setting_wired(connection); - g_assert(s_wired); - g_assert(!nm_setting_wired_get_mac_address(s_wired)); - g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 0); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); -} - -static void -test_dhcp_with_mtu(void) -{ - const char *const *ARGV0 = NM_MAKE_STRV("ip=:dhcp:1499"); - const char *const *ARGV1 = NM_MAKE_STRV("ip=::::::dhcp:1499"); - const char *const *ARGV[] = {ARGV0, ARGV1}; - guint i; - - for (i = 0; i < G_N_ELEMENTS(ARGV); i++) { - gs_unref_object NMConnection *connection = NULL; - NMSettingConnection * s_con; - NMSettingWired * s_wired; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - - connection = _parse_con(ARGV[i], "default_connection"); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "Wired Connection"); - g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0); - g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con), - ==, - NM_CONNECTION_MULTI_CONNECT_MULTIPLE); - g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1); - - g_assert(nm_setting_connection_get_autoconnect(s_con)); - - s_wired = nm_connection_get_setting_wired(connection); - g_assert(s_wired); - g_assert(!nm_setting_wired_get_mac_address(s_wired)); - g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 1499); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), - ==, - NM_SETTING_IP4_CONFIG_METHOD_AUTO); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), - ==, - NM_SETTING_IP6_CONFIG_METHOD_AUTO); - } -} - -static void -test_dhcp_timeout(void) -{ - struct { - const char *const *cmdline; - int timeout; - } data[] = { - {NM_MAKE_STRV("ip=dhcp"), 90}, - {NM_MAKE_STRV("ip=dhcp", "rd.net.timeout.dhcp=0"), 90}, - {NM_MAKE_STRV("ip=dhcp", "rd.net.timeout.dhcp=foobar"), 90}, - {NM_MAKE_STRV("ip=dhcp", "rd.net.timeout.dhcp=42"), 42}, - {NM_MAKE_STRV("ip=dhcp", "rd.net.dhcp.retry=2"), 180}, - {NM_MAKE_STRV("ip=dhcp", "rd.net.dhcp.retry=3", "rd.net.timeout.dhcp=40"), 120}, - {NM_MAKE_STRV("ip=dhcp", "rd.net.timeout.dhcp=infinity"), G_MAXINT32}, - {NM_MAKE_STRV("ip=dhcp", "rd.net.timeout.dhcp=infinity", "rd.net.dhcp.retry=100"), - G_MAXINT32}, - }; - guint i; - - for (i = 0; i < G_N_ELEMENTS(data); i++) { - gs_unref_object NMConnection *connection = NULL; - NMSettingConnection * s_con; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - - connection = _parse_con(data[i].cmdline, "default_connection"); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "Wired Connection"); - g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0); - g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con), - ==, - NM_CONNECTION_MULTI_CONNECT_MULTIPLE); - g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1); - g_assert_cmpint(nm_setting_connection_get_autoconnect_retries(s_con), ==, 1); - g_assert(nm_setting_connection_get_autoconnect(s_con)); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), - ==, - NM_SETTING_IP4_CONFIG_METHOD_AUTO); - g_assert_cmpint(nm_setting_ip_config_get_dhcp_timeout(s_ip4), ==, data[i].timeout); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), - ==, - NM_SETTING_IP6_CONFIG_METHOD_AUTO); - g_assert_cmpint(nm_setting_ip_config_get_dhcp_timeout(s_ip6), ==, data[i].timeout); - } -} - -static void -test_if_auto_with_mtu(void) -{ - const char *const *ARGV = NM_MAKE_STRV("ip=eth0:auto:1666"); - gs_unref_object NMConnection *connection = NULL; - NMSettingConnection * s_con; - NMSettingWired * s_wired; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - - connection = _parse_con(ARGV, "eth0"); - - g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0"); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpint(nm_setting_connection_get_autoconnect_retries(s_con), ==, 1); - - s_wired = nm_connection_get_setting_wired(connection); - g_assert(s_wired); - g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 1666); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4)); - g_assert_cmpint(nm_setting_ip_config_get_dhcp_timeout(s_ip4), ==, 90); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6)); -} - -static void -test_if_dhcp6(void) -{ - const char *const *ARGV = NM_MAKE_STRV("ip=eth1:dhcp6"); - gs_unref_object NMConnection *connection = NULL; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - - connection = _parse_con(ARGV, "eth1"); - - g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth1"); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), - ==, - NM_SETTING_IP4_CONFIG_METHOD_DISABLED); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4)); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6)); -} - -static void -test_if_auto_with_mtu_and_mac(void) -{ - const char *const *ARGV = NM_MAKE_STRV("ip=eth2:auto6:2048:00:53:ef:12:34:56"); - gs_unref_object NMConnection *connection = NULL; - NMSettingWired * s_wired; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - - connection = _parse_con(ARGV, "eth2"); - - g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth2"); - - s_wired = nm_connection_get_setting_wired(connection); - g_assert(s_wired); - g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 2048); - g_assert_cmpstr(nm_setting_wired_get_cloned_mac_address(s_wired), ==, "00:53:EF:12:34:56"); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), - ==, - NM_SETTING_IP4_CONFIG_METHOD_DISABLED); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4)); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6)); -} - -static void -test_if_ip4_manual(void) -{ - gs_unref_hashtable GHashTable *connections = NULL; - const char *const * ARGV = NM_MAKE_STRV("ip=192.0.2.2::192.0.2.1:255.255.255.0:" - "hostname0.example.com:eth3:none:192.0.2.53", - "ip=203.0.113.2::203.0.113.1:26:" - "hostname1.example.com:eth4"); - NMConnection * connection; - NMSettingConnection * s_con; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - NMIPAddress * ip_addr; - gs_free char * hostname = NULL; - gint64 carrier_timeout_sec = 0; - - connections = _parse(ARGV, &hostname, &carrier_timeout_sec); - g_assert_cmpint(g_hash_table_size(connections), ==, 2); - g_assert_cmpstr(hostname, ==, "hostname1.example.com"); - g_assert_cmpint(carrier_timeout_sec, ==, 0); - - connection = g_hash_table_lookup(connections, "eth3"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth3"); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - 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_get_ignore_auto_dns(s_ip4)); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 1); - g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 0), ==, "192.0.2.53"); - g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip4), ==, 0); - g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 1); - ip_addr = nm_setting_ip_config_get_address(s_ip4, 0); - g_assert(ip_addr); - g_assert_cmpstr(nm_ip_address_get_address(ip_addr), ==, "192.0.2.2"); - g_assert_cmpint(nm_ip_address_get_prefix(ip_addr), ==, 24); - g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, "192.0.2.1"); - g_assert_cmpstr(nm_setting_ip_config_get_dhcp_hostname(s_ip4), ==, "hostname0.example.com"); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), - ==, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED); - g_assert(nm_setting_ip_config_get_may_fail(s_ip6)); - - connection = g_hash_table_lookup(connections, "eth4"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth4"); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - 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_get_ignore_auto_dns(s_ip4)); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 0); - g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip4), ==, 0); - g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 1); - ip_addr = nm_setting_ip_config_get_address(s_ip4, 0); - g_assert(ip_addr); - g_assert_cmpstr(nm_ip_address_get_address(ip_addr), ==, "203.0.113.2"); - g_assert_cmpint(nm_ip_address_get_prefix(ip_addr), ==, 26); - g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, "203.0.113.1"); - g_assert_cmpstr(nm_setting_ip_config_get_dhcp_hostname(s_ip4), ==, "hostname1.example.com"); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); - g_assert(nm_setting_ip_config_get_may_fail(s_ip6)); -} - -static void -test_if_ip6_manual(void) -{ - gs_unref_hashtable GHashTable *connections = NULL; - const char *const * ARGV = NM_MAKE_STRV("ip=[2001:0db8::02]/64::[2001:0db8::01]::" - "hostname0.example.com:eth4::[2001:0db8::53]"); - NMConnection * connection; - NMSettingIPConfig * s_ip6; - NMIPAddress * ip_addr; - gs_free char * hostname = NULL; - gint64 carrier_timeout_sec = 0; - - connections = _parse(ARGV, &hostname, &carrier_timeout_sec); - g_assert_cmpint(g_hash_table_size(connections), ==, 1); - g_assert_cmpstr(hostname, ==, "hostname0.example.com"); - g_assert_cmpint(carrier_timeout_sec, ==, 0); - - connection = g_hash_table_lookup(connections, "eth4"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth4"); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), - ==, - NM_SETTING_IP6_CONFIG_METHOD_MANUAL); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6)); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 1); - g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip6, 0), ==, "2001:db8::53"); - g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip6), ==, 0); - g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip6), ==, 1); - ip_addr = nm_setting_ip_config_get_address(s_ip6, 0); - g_assert(ip_addr); - g_assert_cmpstr(nm_ip_address_get_address(ip_addr), ==, "2001:db8::2"); - g_assert_cmpint(nm_ip_address_get_prefix(ip_addr), ==, 64); - g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip6), ==, "2001:db8::1"); - g_assert_cmpstr(nm_setting_ip_config_get_dhcp_hostname(s_ip6), ==, "hostname0.example.com"); -} - -static void -test_if_off(void) -{ - gs_unref_hashtable GHashTable *connections = NULL; - const char *const * ARGV = NM_MAKE_STRV("ip=off", - "ip=ens3:off", - "ip=10.0.0.8:::::ens4:off", - "ip=[2001:DB8::8]:::::ens5:off"); - NMConnection * connection; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - struct { - const char name[32]; - const char ipv4_method[32]; - const char ipv6_method[32]; - - } conn_expected[] = { - {"default_connection", - NM_SETTING_IP4_CONFIG_METHOD_DISABLED, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED}, - {"ens3", NM_SETTING_IP4_CONFIG_METHOD_DISABLED, NM_SETTING_IP6_CONFIG_METHOD_DISABLED}, - {"ens4", NM_SETTING_IP4_CONFIG_METHOD_MANUAL, NM_SETTING_IP6_CONFIG_METHOD_DISABLED}, - {"ens5", NM_SETTING_IP4_CONFIG_METHOD_DISABLED, NM_SETTING_IP6_CONFIG_METHOD_MANUAL}, - }; - - connections = _parse_cons(ARGV); - g_assert_cmpint(g_hash_table_size(connections), ==, G_N_ELEMENTS(conn_expected)); - - for (int i = 0; i < G_N_ELEMENTS(conn_expected); ++i) { - connection = g_hash_table_lookup(connections, conn_expected[i].name); - nmtst_assert_connection_verifies_without_normalization(connection); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, conn_expected[i].ipv4_method); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, conn_expected[i].ipv6_method); - } -} - -static void -test_if_mac_ifname(void) -{ - gs_unref_hashtable GHashTable *connections = NULL; - const char *const * ARGV = NM_MAKE_STRV("ip=[2001:0db8::42]/64::[2001:0db8::01]::" - "hostname0:00-11-22-33-44-55::[2001:0db8::53]"); - NMConnection * connection; - NMSettingIPConfig * s_ip6; - NMSettingWired * s_wired; - NMIPAddress * ip_addr; - gs_free char * hostname = NULL; - gint64 carrier_timeout_sec = 0; - - connections = _parse(ARGV, &hostname, &carrier_timeout_sec); - g_assert_cmpint(g_hash_table_size(connections), ==, 1); - g_assert_cmpstr(hostname, ==, "hostname0"); - g_assert_cmpint(carrier_timeout_sec, ==, 0); - - connection = g_hash_table_lookup(connections, "00:11:22:33:44:55"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "00:11:22:33:44:55"); - g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, NULL); - - s_wired = nm_connection_get_setting_wired(connection); - g_assert(s_wired); - g_assert_cmpstr(nm_setting_wired_get_mac_address(s_wired), ==, "00:11:22:33:44:55"); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), - ==, - NM_SETTING_IP6_CONFIG_METHOD_MANUAL); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6)); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 1); - g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip6, 0), ==, "2001:db8::53"); - g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip6), ==, 0); - g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip6), ==, 1); - ip_addr = nm_setting_ip_config_get_address(s_ip6, 0); - g_assert(ip_addr); - g_assert_cmpstr(nm_ip_address_get_address(ip_addr), ==, "2001:db8::42"); - g_assert_cmpint(nm_ip_address_get_prefix(ip_addr), ==, 64); - g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip6), ==, "2001:db8::1"); - g_assert_cmpstr(nm_setting_ip_config_get_dhcp_hostname(s_ip6), ==, "hostname0"); -} - -static void -test_multiple_merge(void) -{ - const char *const *ARGV = - NM_MAKE_STRV("ip=192.0.2.2/16:::::eth0", "ip=[2001:db8::2]:::56::eth0"); - gs_unref_object NMConnection *connection = NULL; - NMSettingConnection * s_con; - NMSettingWired * s_wired; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - NMIPAddress * ip_addr; - - connection = _parse_con(ARGV, "eth0"); - - g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0"); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1); - - s_wired = nm_connection_get_setting_wired(connection); - g_assert(s_wired); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - 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_get_ignore_auto_dns(s_ip4)); - g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 1); - ip_addr = nm_setting_ip_config_get_address(s_ip4, 0); - g_assert(ip_addr); - g_assert_cmpstr(nm_ip_address_get_address(ip_addr), ==, "192.0.2.2"); - g_assert_cmpint(nm_ip_address_get_prefix(ip_addr), ==, 16); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), - ==, - NM_SETTING_IP6_CONFIG_METHOD_MANUAL); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6)); - g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip6), ==, 1); - ip_addr = nm_setting_ip_config_get_address(s_ip6, 0); - g_assert(ip_addr); - g_assert_cmpstr(nm_ip_address_get_address(ip_addr), ==, "2001:db8::2"); - g_assert_cmpint(nm_ip_address_get_prefix(ip_addr), ==, 56); -} - -static void -test_multiple_bootdev(void) -{ - gs_unref_hashtable GHashTable *connections = NULL; - - const char *const *ARGV = NM_MAKE_STRV("nameserver=1.2.3.4", - "ip=eth3:auto6", - "ip=eth4:dhcp", - "ip=eth5:link6", - "bootdev=eth4"); - - NMConnection * connection; - NMSettingConnection *s_con; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - - connections = _parse_cons(ARGV); - g_assert_cmpint(g_hash_table_size(connections), ==, 3); - - connection = g_hash_table_lookup(connections, "eth3"); - g_assert(connection); - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1); - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); - - connection = g_hash_table_lookup(connections, "eth4"); - g_assert(connection); - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), - ==, - NMI_WAIT_DEVICE_TIMEOUT_MS); - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 1); - g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 0), ==, "1.2.3.4"); - - connection = g_hash_table_lookup(connections, "eth5"); - g_assert(connection); - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1); - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), - ==, - NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL); -} - -static void -test_bootdev(void) -{ - gs_unref_hashtable GHashTable *connections = NULL; - const char *const * ARGV = NM_MAKE_STRV("vlan=vlan2:ens5", "bootdev=ens3"); - NMConnection * connection; - NMSettingConnection * s_con; - - connections = _parse_cons(ARGV); - g_assert_cmpint(g_hash_table_size(connections), ==, 3); - - connection = g_hash_table_lookup(connections, "ens3"); - nmtst_assert_connection_verifies_without_normalization(connection); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "ens3"); - g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "ens3"); - g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), - ==, - NMI_WAIT_DEVICE_TIMEOUT_MS); - - connection = g_hash_table_lookup(connections, "vlan2"); - nmtst_assert_connection_verifies_without_normalization(connection); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_VLAN_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "vlan2"); - g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "vlan2"); - - connection = g_hash_table_lookup(connections, "ens5"); - nmtst_assert_connection_verifies_without_normalization(connection); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "ens5"); - g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "ens5"); -} - -static void -test_some_more(void) -{ - gs_unref_hashtable GHashTable *connections = NULL; - const char *const * ARGV = NM_MAKE_STRV("bootdev=eth1", - "hail", - "nameserver=[2001:DB8:3::53]", - "satan", - "nameserver=192.0.2.53", - "worship", - "doom", - "rd.peerdns=0", - "rd.route=[2001:DB8:3::/48]:[2001:DB8:2::1]:ens10"); - NMConnection * connection; - NMSettingConnection * s_con; - NMSettingWired * s_wired; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - NMIPRoute * ip_route; - - connections = _parse_cons(ARGV); - g_assert_cmpint(g_hash_table_size(connections), ==, 2); - - connection = g_hash_table_lookup(connections, "eth1"); - nmtst_assert_connection_verifies_without_normalization(connection); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "eth1"); - g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "eth1"); - g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con), - ==, - NM_CONNECTION_MULTI_CONNECT_SINGLE); - - s_wired = nm_connection_get_setting_wired(connection); - g_assert(s_wired); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - g_assert(nm_setting_ip_config_get_ignore_auto_dns(s_ip4)); - g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 0); - g_assert(!nm_setting_ip_config_get_gateway(s_ip4)); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 1); - g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 0), ==, "192.0.2.53"); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); - g_assert(nm_setting_ip_config_get_ignore_auto_dns(s_ip6)); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 1); - g_assert(!nm_setting_ip_config_get_gateway(s_ip6)); - g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip6, 0), ==, "2001:db8:3::53"); - - connection = g_hash_table_lookup(connections, "ens10"); - nmtst_assert_connection_verifies_without_normalization(connection); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "ens10"); - g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "ens10"); - g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con), - ==, - NM_CONNECTION_MULTI_CONNECT_SINGLE); - - s_wired = nm_connection_get_setting_wired(connection); - g_assert(s_wired); - g_assert(!nm_setting_wired_get_mac_address(s_wired)); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 1); - g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip6, 0), ==, "2001:db8:3::53"); - g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip6), ==, 1); - g_assert(!nm_setting_ip_config_get_gateway(s_ip6)); - ip_route = nm_setting_ip_config_get_route(s_ip6, 0); - g_assert_cmpstr(nm_ip_route_get_dest(ip_route), ==, "2001:db8:3::"); - g_assert_cmpint(nm_ip_route_get_family(ip_route), ==, AF_INET6); - g_assert_cmpint(nm_ip_route_get_metric(ip_route), ==, -1); - g_assert_cmpstr(nm_ip_route_get_next_hop(ip_route), ==, "2001:db8:2::1"); - g_assert_cmpint(nm_ip_route_get_prefix(ip_route), ==, 48); -} - -static void -test_bond(void) -{ - gs_unref_hashtable GHashTable *connections = NULL; - const char *const * ARGV = NM_MAKE_STRV("rd.route=192.0.2.53::bong0", - "bond=bong0:eth0,eth1:mode=balance-rr", - "nameserver=203.0.113.53"); - NMConnection * connection; - NMSettingConnection * s_con; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - NMSettingBond * s_bond; - NMIPRoute * ip_route; - const char * master_uuid; - - connections = _parse_cons(ARGV); - g_assert_cmpint(g_hash_table_size(connections), ==, 3); - - connection = g_hash_table_lookup(connections, "bong0"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_connection_type(connection), - ==, - NM_SETTING_BOND_SETTING_NAME); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "bong0"); - master_uuid = nm_connection_get_uuid(connection); - g_assert(master_uuid); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4)); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 1); - g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 0), ==, "203.0.113.53"); - g_assert(!nm_setting_ip_config_get_gateway(s_ip4)); - g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip4), ==, 1); - ip_route = nm_setting_ip_config_get_route(s_ip4, 0); - g_assert_cmpstr(nm_ip_route_get_dest(ip_route), ==, "192.0.2.53"); - g_assert_cmpint(nm_ip_route_get_family(ip_route), ==, AF_INET); - g_assert_cmpint(nm_ip_route_get_metric(ip_route), ==, -1); - g_assert(!nm_ip_route_get_next_hop(ip_route)); - g_assert_cmpint(nm_ip_route_get_prefix(ip_route), ==, 32); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6)); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 0); - g_assert(!nm_setting_ip_config_get_gateway(s_ip6)); - g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip6), ==, 0); - - s_bond = nm_connection_get_setting_bond(connection); - g_assert(s_bond); - g_assert_cmpint(nm_setting_bond_get_num_options(s_bond), ==, 1); - g_assert_cmpstr(nm_setting_bond_get_option_by_name(s_bond, "mode"), ==, "balance-rr"); - - connection = g_hash_table_lookup(connections, "eth0"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0"); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "eth0"); - g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con), ==, NM_SETTING_BOND_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, master_uuid); - g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con), - ==, - NM_CONNECTION_MULTI_CONNECT_SINGLE); - - connection = g_hash_table_lookup(connections, "eth1"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth1"); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "eth1"); - g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con), ==, NM_SETTING_BOND_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, master_uuid); - g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con), - ==, - NM_CONNECTION_MULTI_CONNECT_SINGLE); -} - -static void -test_bond_ip(void) -{ - gs_unref_hashtable GHashTable *connections = NULL; - const char *const * ARGV = - NM_MAKE_STRV("bond=bond0:eth0,eth1", - "ip=192.168.1.1::192.168.1.254:24::bond0:none:1480:01:02:03:04:05:06", - "nameserver=4.8.15.16"); - NMConnection * connection; - NMSettingConnection *s_con; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - NMSettingWired * s_wired; - NMSettingBond * s_bond; - NMIPAddress * ip_addr; - const char * master_uuid; - - connections = _parse_cons(ARGV); - g_assert_cmpint(g_hash_table_size(connections), ==, 3); - - connection = g_hash_table_lookup(connections, "bond0"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_connection_type(connection), - ==, - NM_SETTING_BOND_SETTING_NAME); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "bond0"); - master_uuid = nm_connection_get_uuid(connection); - g_assert(master_uuid); - - s_wired = nm_connection_get_setting_wired(connection); - g_assert(s_wired); - g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 1480); - g_assert_cmpstr(nm_setting_wired_get_cloned_mac_address(s_wired), ==, "01:02:03:04:05:06"); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), - ==, - NM_SETTING_IP4_CONFIG_METHOD_MANUAL); - g_assert_cmpint(nm_setting_ip_config_get_num_addresses(s_ip4), ==, 1); - ip_addr = nm_setting_ip_config_get_address(s_ip4, 0); - g_assert(ip_addr); - g_assert_cmpstr(nm_ip_address_get_address(ip_addr), ==, "192.168.1.1"); - g_assert_cmpint(nm_ip_address_get_prefix(ip_addr), ==, 24); - g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, "192.168.1.254"); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 1); - g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 0), ==, "4.8.15.16"); - g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip4), ==, 0); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), - ==, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6)); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 0); - g_assert(!nm_setting_ip_config_get_gateway(s_ip6)); - g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip6), ==, 0); - - s_bond = nm_connection_get_setting_bond(connection); - g_assert(s_bond); - g_assert_cmpint(nm_setting_bond_get_num_options(s_bond), ==, 1); - g_assert_cmpstr(nm_setting_bond_get_option_by_name(s_bond, "mode"), ==, "balance-rr"); - - connection = g_hash_table_lookup(connections, "eth0"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0"); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "eth0"); - g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con), ==, NM_SETTING_BOND_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, master_uuid); - g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con), - ==, - NM_CONNECTION_MULTI_CONNECT_SINGLE); - - connection = g_hash_table_lookup(connections, "eth1"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth1"); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "eth1"); - g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con), ==, NM_SETTING_BOND_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, master_uuid); - g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con), - ==, - NM_CONNECTION_MULTI_CONNECT_SINGLE); -} - -static void -test_bond_default(void) -{ - gs_unref_hashtable GHashTable *connections = NULL; - const char *const * ARGV = NM_MAKE_STRV("bond"); - NMConnection * connection; - NMSettingConnection * s_con; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - NMSettingBond * s_bond; - const char * master_uuid; - - connections = _parse_cons(ARGV); - g_assert_cmpint(g_hash_table_size(connections), ==, 2); - - connection = g_hash_table_lookup(connections, "bond0"); - - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_connection_type(connection), - ==, - NM_SETTING_BOND_SETTING_NAME); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "bond0"); - master_uuid = nm_connection_get_uuid(connection); - g_assert(master_uuid); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4)); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 0); - g_assert(!nm_setting_ip_config_get_gateway(s_ip4)); - g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip4), ==, 0); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6)); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 0); - g_assert(!nm_setting_ip_config_get_gateway(s_ip6)); - g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip6), ==, 0); - - s_bond = nm_connection_get_setting_bond(connection); - g_assert(s_bond); - g_assert_cmpint(nm_setting_bond_get_num_options(s_bond), ==, 1); - g_assert_cmpstr(nm_setting_bond_get_option_by_name(s_bond, "mode"), ==, "balance-rr"); - - connection = g_hash_table_lookup(connections, "eth0"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0"); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "eth0"); - g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con), ==, NM_SETTING_BOND_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, master_uuid); - g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con), - ==, - NM_CONNECTION_MULTI_CONNECT_SINGLE); -} - -static void -test_bridge(void) -{ - gs_unref_hashtable GHashTable *connections = NULL; - const char *const * ARGV = NM_MAKE_STRV("bridge=bridge0:eth0,eth1", - "rd.route=192.0.2.53::bridge0", - "rd.net.timeout.dhcp=10"); - NMConnection * connection; - NMSettingConnection * s_con; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - NMSettingBridge * s_bridge; - NMIPRoute * ip_route; - const char * master_uuid; - - connections = _parse_cons(ARGV); - g_assert_cmpint(g_hash_table_size(connections), ==, 3); - - connection = g_hash_table_lookup(connections, "bridge0"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_connection_type(connection), - ==, - NM_SETTING_BRIDGE_SETTING_NAME); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "bridge0"); - master_uuid = nm_connection_get_uuid(connection); - g_assert(master_uuid); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4)); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 0); - g_assert(!nm_setting_ip_config_get_gateway(s_ip4)); - g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip4), ==, 1); - g_assert_cmpint(nm_setting_ip_config_get_dhcp_timeout(s_ip4), ==, 10); - ip_route = nm_setting_ip_config_get_route(s_ip4, 0); - g_assert_cmpstr(nm_ip_route_get_dest(ip_route), ==, "192.0.2.53"); - g_assert_cmpint(nm_ip_route_get_family(ip_route), ==, AF_INET); - g_assert_cmpint(nm_ip_route_get_metric(ip_route), ==, -1); - g_assert(!nm_ip_route_get_next_hop(ip_route)); - g_assert_cmpint(nm_ip_route_get_prefix(ip_route), ==, 32); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6)); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 0); - g_assert(!nm_setting_ip_config_get_gateway(s_ip6)); - g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip6), ==, 0); - g_assert_cmpint(nm_setting_ip_config_get_dhcp_timeout(s_ip6), ==, 10); - - s_bridge = nm_connection_get_setting_bridge(connection); - g_assert(s_bridge); - g_assert_cmpint(nm_setting_bridge_get_stp(s_bridge), ==, FALSE); - - connection = g_hash_table_lookup(connections, "eth0"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0"); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "eth0"); - g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con), - ==, - NM_SETTING_BRIDGE_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, master_uuid); - g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con), - ==, - NM_CONNECTION_MULTI_CONNECT_SINGLE); - - connection = g_hash_table_lookup(connections, "eth1"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth1"); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "eth1"); - g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con), - ==, - NM_SETTING_BRIDGE_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, master_uuid); - g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con), - ==, - NM_CONNECTION_MULTI_CONNECT_SINGLE); -} - -static void -test_bridge_default(void) -{ - gs_unref_hashtable GHashTable *connections = NULL; - const char *const * ARGV = NM_MAKE_STRV("bridge"); - NMConnection * connection; - NMSettingConnection * s_con; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - NMSettingBridge * s_bridge; - const char * master_uuid; - - connections = _parse_cons(ARGV); - g_assert_cmpint(g_hash_table_size(connections), ==, 2); - - connection = g_hash_table_lookup(connections, "br0"); - - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_connection_type(connection), - ==, - NM_SETTING_BRIDGE_SETTING_NAME); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "br0"); - master_uuid = nm_connection_get_uuid(connection); - g_assert(master_uuid); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4)); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 0); - g_assert(!nm_setting_ip_config_get_gateway(s_ip4)); - g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip4), ==, 0); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6)); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 0); - g_assert(!nm_setting_ip_config_get_gateway(s_ip6)); - g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip6), ==, 0); - - s_bridge = nm_connection_get_setting_bridge(connection); - g_assert(s_bridge); - - connection = g_hash_table_lookup(connections, "eth0"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0"); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "eth0"); - g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con), - ==, - NM_SETTING_BRIDGE_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, master_uuid); - g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con), - ==, - NM_CONNECTION_MULTI_CONNECT_SINGLE); -} - -static void -test_bridge_ip(void) -{ - gs_unref_hashtable GHashTable *connections = NULL; - const char *const * ARGV = - NM_MAKE_STRV("ip=bridge123:auto:1280:00:11:22:33:CA:fe", - "bridge=bridge123:eth0,eth1,eth2,eth3,eth4,eth5,eth6,eth7,eth8,eth9"); - NMConnection * connection; - NMSettingConnection *s_con; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - NMSettingWired * s_wired; - NMSettingBridge * s_bridge; - const char * master_uuid; - guint i; - - connections = _parse_cons(ARGV); - g_assert_cmpint(g_hash_table_size(connections), ==, 11); - - connection = g_hash_table_lookup(connections, "bridge123"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_connection_type(connection), - ==, - NM_SETTING_BRIDGE_SETTING_NAME); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "bridge123"); - master_uuid = nm_connection_get_uuid(connection); - g_assert(master_uuid); - - s_wired = nm_connection_get_setting_wired(connection); - g_assert(s_wired); - g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 1280); - g_assert_cmpstr(nm_setting_wired_get_cloned_mac_address(s_wired), ==, "00:11:22:33:CA:FE"); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); - - s_bridge = nm_connection_get_setting_bridge(connection); - g_assert(s_bridge); - - for (i = 0; i < 10; i++) { - char ifname[16]; - - nm_sprintf_buf(ifname, "eth%u", i); - - connection = g_hash_table_lookup(connections, ifname); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_id(connection), ==, ifname); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, ifname); - g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con), - ==, - NM_SETTING_BRIDGE_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, master_uuid); - g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con), - ==, - NM_CONNECTION_MULTI_CONNECT_SINGLE); - } -} - -static void -test_team(void) -{ - gs_unref_hashtable GHashTable *connections = NULL; - const char *const * ARGV = NM_MAKE_STRV("team=team0:eth0,eth1", "ip=team0:dhcp6"); - NMConnection * connection; - NMSettingConnection * s_con; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - NMSettingTeam * s_team; - const char * master_uuid; - - connections = _parse_cons(ARGV); - g_assert_cmpint(g_hash_table_size(connections), ==, 3); - - connection = g_hash_table_lookup(connections, "team0"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_connection_type(connection), - ==, - NM_SETTING_TEAM_SETTING_NAME); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "team0"); - master_uuid = nm_connection_get_uuid(connection); - g_assert(master_uuid); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), - ==, - NM_SETTING_IP4_CONFIG_METHOD_DISABLED); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4)); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip4), ==, 0); - g_assert(!nm_setting_ip_config_get_gateway(s_ip4)); - g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip4), ==, 0); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6)); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip6), ==, 0); - g_assert(!nm_setting_ip_config_get_gateway(s_ip6)); - g_assert_cmpint(nm_setting_ip_config_get_num_routes(s_ip6), ==, 0); - - s_team = nm_connection_get_setting_team(connection); - g_assert(s_team); - - connection = g_hash_table_lookup(connections, "eth0"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0"); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "eth0"); - g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con), ==, NM_SETTING_TEAM_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, master_uuid); - g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con), - ==, - NM_CONNECTION_MULTI_CONNECT_SINGLE); - - connection = g_hash_table_lookup(connections, "eth1"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth1"); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "eth1"); - g_assert_cmpstr(nm_setting_connection_get_slave_type(s_con), ==, NM_SETTING_TEAM_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_master(s_con), ==, master_uuid); - g_assert_cmpint(nm_setting_connection_get_multi_connect(s_con), - ==, - NM_CONNECTION_MULTI_CONNECT_SINGLE); -} - -static void -test_vlan(void) -{ - const char *const *ARGV0 = NM_MAKE_STRV("ip=eth0.100:dhcp", "vlan=eth0.100:eth0"); - const char *const *ARGV1 = NM_MAKE_STRV("vlan=eth0.100:eth0", "ip=eth0.100:dhcp"); - const char *const *ARGV[] = {ARGV0, ARGV1}; - guint i; - - for (i = 0; i < G_N_ELEMENTS(ARGV); i++) { - gs_unref_hashtable GHashTable *connections = NULL; - NMConnection * connection; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - NMSettingVlan * s_vlan; - - connections = _parse_cons(ARGV[i]); - g_assert_cmpint(g_hash_table_size(connections), ==, 2); - - /* VLAN eth0.100 */ - connection = g_hash_table_lookup(connections, "eth0.100"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_connection_type(connection), - ==, - NM_SETTING_VLAN_SETTING_NAME); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0.100"); - - s_vlan = nm_connection_get_setting_vlan(connection); - g_assert(s_vlan); - g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, "eth0"); - g_assert_cmpint(nm_setting_vlan_get_id(s_vlan), ==, 100); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), - ==, - NM_SETTING_IP4_CONFIG_METHOD_AUTO); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), - ==, - NM_SETTING_IP6_CONFIG_METHOD_AUTO); - - /* Ethernet eth0 */ - connection = g_hash_table_lookup(connections, "eth0"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_connection_type(connection), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0"); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), - ==, - NM_SETTING_IP4_CONFIG_METHOD_DISABLED); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), - ==, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED); - } -} - -static void -test_vlan_with_dhcp_on_parent(void) -{ - const char *const *ARGV0 = NM_MAKE_STRV("vlan=eth0.100:eth0", "ip=eth0:dhcp"); - const char *const *ARGV1 = NM_MAKE_STRV("ip=eth0:dhcp", "vlan=eth0.100:eth0"); - const char *const *ARGV[] = {ARGV0, ARGV1}; - guint i; - - for (i = 0; i < G_N_ELEMENTS(ARGV); i++) { - gs_unref_hashtable GHashTable *connections = NULL; - NMConnection * connection; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - NMSettingVlan * s_vlan; - - connections = _parse_cons(ARGV[i]); - g_assert_cmpint(g_hash_table_size(connections), ==, 2); - - /* VLAN eth0.100 */ - connection = g_hash_table_lookup(connections, "eth0.100"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_connection_type(connection), - ==, - NM_SETTING_VLAN_SETTING_NAME); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0.100"); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), - ==, - NM_SETTING_IP4_CONFIG_METHOD_AUTO); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), - ==, - NM_SETTING_IP6_CONFIG_METHOD_AUTO); - - s_vlan = nm_connection_get_setting_vlan(connection); - g_assert(s_vlan); - g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, "eth0"); - g_assert_cmpint(nm_setting_vlan_get_id(s_vlan), ==, 100); - - /* Ethernet eth0 */ - connection = g_hash_table_lookup(connections, "eth0"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_connection_type(connection), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0"); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), - ==, - NM_SETTING_IP4_CONFIG_METHOD_AUTO); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), - ==, - NM_SETTING_IP6_CONFIG_METHOD_AUTO); - } -} - -static void -test_vlan_over_bond(void) -{ - const char *const *ARGV0 = NM_MAKE_STRV("ip=1.2.3.4:::24::vlan1:none", - "bond=bond2:ens3,ens4:mode=active-backup", - "vlan=vlan1:bond2"); - const char *const *ARGV1 = NM_MAKE_STRV("vlan=vlan1:bond2", - "ip=1.2.3.4:::24::vlan1:none", - "bond=bond2:ens3,ens4:mode=active-backup"); - const char *const *ARGV2 = NM_MAKE_STRV("bond=bond2:ens3,ens4:mode=active-backup", - "ip=1.2.3.4:::24::vlan1:none", - "vlan=vlan1:bond2"); - const char *const *ARGV[] = {ARGV0, ARGV1, ARGV2}; - guint i; - - for (i = 0; i < G_N_ELEMENTS(ARGV); i++) { - gs_unref_hashtable GHashTable *connections = NULL; - NMConnection * connection; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - NMSettingVlan * s_vlan; - - connections = _parse_cons(ARGV[i]); - g_assert_cmpint(g_hash_table_size(connections), ==, 4); - - /* VLAN vlan1 */ - connection = g_hash_table_lookup(connections, "vlan1"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_connection_type(connection), - ==, - NM_SETTING_VLAN_SETTING_NAME); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "vlan1"); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), - ==, - NM_SETTING_IP4_CONFIG_METHOD_MANUAL); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), - ==, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED); - - s_vlan = nm_connection_get_setting_vlan(connection); - g_assert(s_vlan); - g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, "bond2"); - g_assert_cmpint(nm_setting_vlan_get_id(s_vlan), ==, 1); - - /* Bond bond2 */ - connection = g_hash_table_lookup(connections, "bond2"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_connection_type(connection), - ==, - NM_SETTING_BOND_SETTING_NAME); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "bond2"); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), - ==, - NM_SETTING_IP4_CONFIG_METHOD_DISABLED); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), - ==, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED); - - /* Ethernet ens3 and ens4 */ - connection = g_hash_table_lookup(connections, "ens3"); - g_assert(connection); - connection = g_hash_table_lookup(connections, "ens4"); - g_assert(connection); - } -} - -static void -test_ibft_ip_dev(void) -{ - const char *const * ARGV = NM_MAKE_STRV("ip=eth0:ibft"); - NMSettingConnection *s_con; - gs_unref_object NMConnection *connection = NULL; - - connection = _parse_con(ARGV, "eth0"); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_VLAN_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, NULL); -} - -static void -test_ibft_ip_dev_mac(void) -{ - const char *const * ARGV = NM_MAKE_STRV("ip=00-53-06-66-ab-01:ibft"); - NMSettingConnection *s_con; - gs_unref_object NMConnection *connection = NULL; - - connection = _parse_con(ARGV, "00:53:06:66:AB:01"); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, NULL); -} - -static void -_test_ibft_ip(const char *const *ARGV) -{ - gs_unref_hashtable GHashTable *connections = NULL; - NMConnection * connection; - - connections = _parse_cons(ARGV); - g_assert_cmpint(g_hash_table_size(connections), ==, 2); - - connection = g_hash_table_lookup(connections, "ibft0"); - nmtst_assert_connection_verifies_without_normalization(connection); - - g_assert_cmpstr(nm_connection_get_id(connection), ==, "iBFT VLAN Connection 0"); - g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, NULL); - - connection = g_hash_table_lookup(connections, "ibft2"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "iBFT Connection 2"); - g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, NULL); -} - -static void -test_ibft_ip(void) -{ - const char *const *ARGV = NM_MAKE_STRV("ip=ibft"); - - _test_ibft_ip(ARGV); -} - -static void -test_ibft_rd_iscsi_ibft(void) -{ - const char *const *ARGV = NM_MAKE_STRV("rd.iscsi.ibft"); - - _test_ibft_ip(ARGV); -} - -static void -test_ignore_extra(void) -{ - gs_unref_hashtable GHashTable *connections = NULL; - const char *const * ARGV = NM_MAKE_STRV("blabla", "extra", "lalala"); - - connections = _parse_cons(ARGV); - g_assert_cmpint(g_hash_table_size(connections), ==, 0); -} - -static void -test_rd_znet(void) -{ - gs_unref_hashtable GHashTable *connections = NULL; - const char *const *const ARGV = - NM_MAKE_STRV("ip=10.11.12.13::10.11.12.1:24:foo.example.com:enc800:none", - "ip=slc600:dhcp", - "rd.znet=qeth,0.0.0800,0.0.0801,0.0.0802,layer2=0,portno=1", - "rd.znet=ctc,0.0.0600,0.0.0601,layer2=0,portno=0"); - NMConnection * connection; - NMSettingConnection * s_con; - NMSettingWired * s_wired; - const char *const * v_subchannels; - const NMUtilsNamedValue s390_options[] = { - {.name = "layer2", .value_str = "0"}, - {.name = "portno", .value_str = "1"}, - }; - int i_s390_options_keys; - gs_free char *hostname = NULL; - gint64 carrier_timeout_sec = 0; - - connections = _parse(ARGV, &hostname, &carrier_timeout_sec); - g_assert_cmpint(g_hash_table_size(connections), ==, 2); - g_assert_cmpstr(hostname, ==, "foo.example.com"); - g_assert_cmpint(carrier_timeout_sec, ==, 0); - - connection = g_hash_table_lookup(connections, "enc800"); - g_assert(NM_IS_CONNECTION(connection)); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(NM_IS_SETTING_CONNECTION(s_con)); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "enc800"); - g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "enc800"); - - s_wired = nm_connection_get_setting_wired(connection); - g_assert(NM_IS_SETTING_WIRED(s_wired)); - - v_subchannels = nm_setting_wired_get_s390_subchannels(s_wired); - g_assert(v_subchannels); - g_assert_cmpstr(v_subchannels[0], ==, "0.0.0800"); - g_assert_cmpstr(v_subchannels[1], ==, "0.0.0801"); - g_assert_cmpstr(v_subchannels[2], ==, "0.0.0802"); - g_assert_cmpstr(v_subchannels[3], ==, NULL); - - g_assert_cmpint(nm_setting_wired_get_num_s390_options(s_wired), ==, G_N_ELEMENTS(s390_options)); - for (i_s390_options_keys = 0; i_s390_options_keys < G_N_ELEMENTS(s390_options); - i_s390_options_keys++) { - const NMUtilsNamedValue *s390_option = &s390_options[i_s390_options_keys]; - const char * k; - const char * v; - const char * v2; - - g_assert(s390_option->name); - g_assert(s390_option->value_str); - v = nm_setting_wired_get_s390_option_by_key(s_wired, s390_option->name); - g_assert(v); - g_assert_cmpstr(v, ==, s390_option->value_str); - - if (!nm_setting_wired_get_s390_option(s_wired, i_s390_options_keys, &k, &v2)) - g_assert_not_reached(); - g_assert_cmpstr(k, ==, s390_option->name); - g_assert(v == v2); - g_assert_cmpstr(v2, ==, s390_option->value_str); - } - - nmtst_assert_connection_verifies_without_normalization(connection); - - connection = g_hash_table_lookup(connections, "slc600"); - g_assert(NM_IS_CONNECTION(connection)); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(NM_IS_SETTING_CONNECTION(s_con)); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "slc600"); - g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "slc600"); - - s_wired = nm_connection_get_setting_wired(connection); - g_assert(NM_IS_SETTING_WIRED(s_wired)); - - v_subchannels = nm_setting_wired_get_s390_subchannels(s_wired); - g_assert(v_subchannels); - g_assert_cmpstr(v_subchannels[0], ==, "0.0.0600"); - g_assert_cmpstr(v_subchannels[1], ==, "0.0.0601"); - g_assert_cmpstr(v_subchannels[2], ==, NULL); - - nmtst_assert_connection_verifies_without_normalization(connection); -} - -static void -test_rd_znet_legacy(void) -{ - gs_unref_hashtable GHashTable *connections = NULL; - const char *const *const ARGV = - NM_MAKE_STRV("ip=10.11.12.13::10.11.12.1:24:foo.example.com:eth0:none", - "rd.znet=qeth,0.0.0800,0.0.0801,0.0.0802,layer2=0,portno=1", - "rd.znet=ctc,0.0.0600,0.0.0601,layer2=0,portno=0", - "ip=ctc0:dhcp", - "net.ifnames=0"); - NMConnection * connection; - NMSettingConnection *s_con; - gs_free char * hostname = NULL; - gint64 carrier_timeout_sec = 0; - - connections = _parse(ARGV, &hostname, &carrier_timeout_sec); - g_assert_cmpint(g_hash_table_size(connections), ==, 2); - g_assert_cmpstr(hostname, ==, "foo.example.com"); - g_assert_cmpint(carrier_timeout_sec, ==, 0); - - connection = g_hash_table_lookup(connections, "eth0"); - g_assert(NM_IS_CONNECTION(connection)); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(NM_IS_SETTING_CONNECTION(s_con)); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "eth0"); - g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "eth0"); - - nmtst_assert_connection_verifies_without_normalization(connection); - - connection = g_hash_table_lookup(connections, "ctc0"); - g_assert(NM_IS_CONNECTION(connection)); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(NM_IS_SETTING_CONNECTION(s_con)); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "ctc0"); - g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "ctc0"); - - nmtst_assert_connection_verifies_without_normalization(connection); -} - -static void -test_rd_znet_no_ip(void) -{ - gs_unref_hashtable GHashTable *connections = NULL; - const char *const *const ARGV = - NM_MAKE_STRV("rd.znet=qeth,0.0.0800,0.0.0801,0.0.0802,layer2=0,portno=1"); - - connections = _parse_cons(ARGV); - g_assert_cmpint(g_hash_table_size(connections), ==, 0); -} - -static void -test_bootif_ip(void) -{ - const char *const *ARGV = NM_MAKE_STRV("BOOTIF=00:53:AB:cd:02:03", "ip=dhcp"); - gs_unref_object NMConnection *connection = NULL; - NMSettingWired * s_wired; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - - connection = _parse_con(ARGV, "default_connection"); - - g_assert_cmpstr(nm_connection_get_id(connection), ==, "Wired Connection"); - - s_wired = nm_connection_get_setting_wired(connection); - g_assert_cmpstr(nm_setting_wired_get_mac_address(s_wired), ==, "00:53:AB:CD:02:03"); - g_assert(s_wired); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4)); - g_assert(!nm_setting_ip_config_get_may_fail(s_ip4)); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6)); -} - -static void -test_neednet(void) -{ - gs_unref_hashtable GHashTable *connections = NULL; - const char *const * ARGV = NM_MAKE_STRV("rd.neednet", - "ip=eno1:dhcp", - "ip=172.25.1.100::172.25.1.1:24::eno2", - "bridge=br0:eno3"); - NMConnection * connection; - NMSettingConnection * s_con; - - connections = _parse_cons(ARGV); - g_assert_cmpint(g_hash_table_size(connections), ==, 4); - - connection = g_hash_table_lookup(connections, "eno1"); - nmtst_assert_connection_verifies_without_normalization(connection); - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "eno1"); - g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), - ==, - NMI_WAIT_DEVICE_TIMEOUT_MS); - - connection = g_hash_table_lookup(connections, "eno2"); - nmtst_assert_connection_verifies_without_normalization(connection); - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "eno2"); - g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), - ==, - NMI_WAIT_DEVICE_TIMEOUT_MS); - - connection = g_hash_table_lookup(connections, "eno3"); - nmtst_assert_connection_verifies_without_normalization(connection); - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "eno3"); - g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), - ==, - NMI_WAIT_DEVICE_TIMEOUT_MS); - - connection = g_hash_table_lookup(connections, "br0"); - nmtst_assert_connection_verifies_without_normalization(connection); - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, "br0"); - g_assert_cmpint(nm_setting_connection_get_wait_device_timeout(s_con), ==, -1); -} - -static void -test_bootif_no_ip(void) -{ - const char *const *ARGV = NM_MAKE_STRV("BOOTIF=00:53:AB:cd:02:03"); - gs_unref_object NMConnection *connection = NULL; - NMSettingWired * s_wired; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - - connection = _parse_con(ARGV, "default_connection"); - - g_assert_cmpstr(nm_connection_get_id(connection), ==, "Wired Connection"); - - s_wired = nm_connection_get_setting_wired(connection); - g_assert_cmpstr(nm_setting_wired_get_mac_address(s_wired), ==, "00:53:AB:CD:02:03"); - g_assert(s_wired); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - g_assert(nm_setting_ip_config_get_may_fail(s_ip4)); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); - g_assert(nm_setting_ip_config_get_may_fail(s_ip6)); -} - -static void -test_bootif_hwtype(void) -{ - const char *const *ARGV0 = NM_MAKE_STRV("ip=eth0:dhcp", "BOOTIF=01-00-53-AB-cd-02-03"); - const char *const *ARGV1 = NM_MAKE_STRV("ip=eth0:dhcp", "BOOTIF=00-00-53-Ab-cD-02-03"); - const char *const *ARGV[] = {ARGV0, ARGV1}; - guint i; - - for (i = 0; i < G_N_ELEMENTS(ARGV); i++) { - gs_unref_hashtable GHashTable *connections = NULL; - NMConnection * connection; - NMSettingWired * s_wired; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - - connections = _parse_cons(ARGV[i]); - g_assert_cmpint(g_hash_table_size(connections), ==, 2); - - connection = g_hash_table_lookup(connections, "eth0"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "eth0"); - - s_wired = nm_connection_get_setting_wired(connection); - g_assert(!nm_setting_wired_get_mac_address(s_wired)); - g_assert(s_wired); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), - ==, - NM_SETTING_IP4_CONFIG_METHOD_AUTO); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4)); - g_assert(!nm_setting_ip_config_get_may_fail(s_ip4)); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), - ==, - NM_SETTING_IP6_CONFIG_METHOD_AUTO); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6)); - - connection = g_hash_table_lookup(connections, "bootif_connection"); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert_cmpstr(nm_connection_get_id(connection), ==, "BOOTIF Connection"); - - s_wired = nm_connection_get_setting_wired(connection); - g_assert_cmpstr(nm_setting_wired_get_mac_address(s_wired), ==, "00:53:AB:CD:02:03"); - g_assert(s_wired); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), - ==, - NM_SETTING_IP4_CONFIG_METHOD_AUTO); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip4)); - g_assert(nm_setting_ip_config_get_may_fail(s_ip4)); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), - ==, - NM_SETTING_IP6_CONFIG_METHOD_AUTO); - g_assert(!nm_setting_ip_config_get_ignore_auto_dns(s_ip6)); - g_assert(nm_setting_ip_config_get_may_fail(s_ip6)); - } -} - -/* Check that nameservers are assigned to all existing - * connections that support the specific IPv4/IPv6 address - * family. - */ -static void -test_nameserver(void) -{ - gs_unref_hashtable GHashTable *connections = NULL; - const char *const * ARGV = - NM_MAKE_STRV("nameserver=1.1.1.1", - "ip=eth0:dhcp", - "ip=eth1:auto6", - "ip=10.11.12.13::10.11.12.1:24:foo.example.com:eth2:none", - "nameserver=1.0.0.1", - "nameserver=[2606:4700:4700::1111]"); - NMConnection * connection; - NMSettingIPConfig *s_ip; - gs_free char * hostname = NULL; - gint64 carrier_timeout_sec = 0; - - connections = _parse(ARGV, &hostname, &carrier_timeout_sec); - g_assert_cmpint(g_hash_table_size(connections), ==, 3); - g_assert_cmpstr(hostname, ==, "foo.example.com"); - g_assert_cmpint(carrier_timeout_sec, ==, 0); - - connection = g_hash_table_lookup(connections, "eth0"); - nmtst_assert_connection_verifies_without_normalization(connection); - - s_ip = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip), ==, 2); - g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip, 0), ==, "1.1.1.1"); - g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip, 1), ==, "1.0.0.1"); - - connection = g_hash_table_lookup(connections, "eth1"); - nmtst_assert_connection_verifies_without_normalization(connection); - - s_ip = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip), ==, 1); - g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip, 0), ==, "2606:4700:4700::1111"); - - connection = g_hash_table_lookup(connections, "eth2"); - nmtst_assert_connection_verifies_without_normalization(connection); - - s_ip = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip); - g_assert_cmpint(nm_setting_ip_config_get_num_dns(s_ip), ==, 2); - g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip, 0), ==, "1.1.1.1"); - g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip, 1), ==, "1.0.0.1"); -} - -static void -test_bootif_off(void) -{ - gs_unref_hashtable GHashTable *connections = NULL; - const char *const *ARGV = NM_MAKE_STRV("BOOTIF=01-00-53-AB-cd-02-03", "rd.bootif=0"); - - connections = _parse_cons(ARGV); - g_assert_cmpint(g_hash_table_size(connections), ==, 0); -} - -static void -test_dhcp_vendor_class_id(void) -{ - const char *const *ARGV; - gs_unref_object NMConnection *connection = NULL; - NMSettingIP4Config * s_ip4; - gs_free char * vci_long = NULL; - char vci_arg_long[512] = {0}; - - ARGV = NM_MAKE_STRV("rd.net.dhcp.vendor-class=testvci", "ip=eno1:dhcp"); - connection = _parse_con(ARGV, "eno1"); - s_ip4 = NM_SETTING_IP4_CONFIG(nm_connection_get_setting_ip4_config(connection)); - g_assert_cmpstr(nm_setting_ip4_config_get_dhcp_vendor_class_identifier(s_ip4), ==, "testvci"); - - g_clear_object(&connection); - - ARGV = NM_MAKE_STRV("rd.net.dhcp.vendor-class", "ip=eno1:dhcp"); - connection = _parse_con(ARGV, "eno1"); - s_ip4 = NM_SETTING_IP4_CONFIG(nm_connection_get_setting_ip4_config(connection)); - g_assert(nm_setting_ip4_config_get_dhcp_vendor_class_identifier(s_ip4) == NULL); - - g_clear_object(&connection); - - memset(vci_arg_long, 'A', 400); - vci_long = g_strdup_printf("rd.net.dhcp.vendor-class=%s", vci_arg_long); - ARGV = NM_MAKE_STRV(vci_long, "ip=eno1:dhcp"); - connection = _parse_con(ARGV, "eno1"); - s_ip4 = NM_SETTING_IP4_CONFIG(nm_connection_get_setting_ip4_config(connection)); - g_assert(nm_setting_ip4_config_get_dhcp_vendor_class_identifier(s_ip4) == NULL); -} - -static void -test_infiniband_iface(void) -{ - const char *const *ARGV = NM_MAKE_STRV("ip=ib1:dhcp"); - gs_unref_object NMConnection *connection = NULL; - NMSettingInfiniband * s_ib; - - connection = _parse_con(ARGV, "ib1"); - - g_assert_cmpstr(nm_connection_get_connection_type(connection), - ==, - NM_SETTING_INFINIBAND_SETTING_NAME); - s_ib = nm_connection_get_setting_infiniband(connection); - g_assert(s_ib); -} - -static void -test_infiniband_mac(void) -{ - const char *const *ARGV = - NM_MAKE_STRV("ip=00-11-22-33-44-55-66-77-88-99-aa-bb-cc-dd-ee-ff-00-11-22-33:dhcp"); - gs_unref_object NMConnection *connection = NULL; - NMSettingInfiniband * s_ib; - - connection = _parse_con(ARGV, "00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33"); - - g_assert_cmpstr(nm_connection_get_connection_type(connection), - ==, - NM_SETTING_INFINIBAND_SETTING_NAME); - g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, NULL); - s_ib = nm_connection_get_setting_infiniband(connection); - g_assert(s_ib); - g_assert_cmpstr(nm_setting_infiniband_get_mac_address(s_ib), - ==, - "00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33"); -} - -static void -test_carrier_timeout(void) -{ - gs_unref_hashtable GHashTable *connections = NULL; - const char *const * ARGV = NM_MAKE_STRV("rd.net.timeout.carrier=20"); - gs_free char * hostname = NULL; - gint64 carrier_timeout_sec = 0; - - connections = _parse(ARGV, &hostname, &carrier_timeout_sec); - g_assert_cmpint(g_hash_table_size(connections), ==, 0); - g_assert_cmpstr(hostname, ==, NULL); - g_assert_cmpint(carrier_timeout_sec, ==, 20); -} - -NMTST_DEFINE(); - -int -main(int argc, char **argv) -{ - nmtst_init_assert_logging(&argc, &argv, "INFO", "DEFAULT"); - - g_test_add_func("/initrd/cmdline/auto", test_auto); - g_test_add_func("/initrd/cmdline/dhcp_with_hostname", test_dhcp_with_hostname); - g_test_add_func("/initrd/cmdline/dhcp_with_mtu", test_dhcp_with_mtu); - g_test_add_func("/initrd/cmdline/dhcp_timeout", test_dhcp_timeout); - g_test_add_func("/initrd/cmdline/if_auto_with_mtu", test_if_auto_with_mtu); - g_test_add_func("/initrd/cmdline/if_dhcp6", test_if_dhcp6); - g_test_add_func("/initrd/cmdline/if_auto_with_mtu_and_mac", test_if_auto_with_mtu_and_mac); - g_test_add_func("/initrd/cmdline/if_ip4_manual", test_if_ip4_manual); - g_test_add_func("/initrd/cmdline/if_ip6_manual", test_if_ip6_manual); - g_test_add_func("/initrd/cmdline/if_mac_ifname", test_if_mac_ifname); - g_test_add_func("/initrd/cmdline/if_off", test_if_off); - g_test_add_func("/initrd/cmdline/multiple/merge", test_multiple_merge); - g_test_add_func("/initrd/cmdline/multiple/bootdev", test_multiple_bootdev); - g_test_add_func("/initrd/cmdline/nameserver", test_nameserver); - g_test_add_func("/initrd/cmdline/some_more", test_some_more); - g_test_add_func("/initrd/cmdline/bootdev", test_bootdev); - g_test_add_func("/initrd/cmdline/bond", test_bond); - g_test_add_func("/initrd/cmdline/bond/ip", test_bond_ip); - g_test_add_func("/initrd/cmdline/bond/default", test_bond_default); - g_test_add_func("/initrd/cmdline/team", test_team); - g_test_add_func("/initrd/cmdline/vlan", test_vlan); - g_test_add_func("/initrd/cmdline/vlan/dhcp-on-parent", test_vlan_with_dhcp_on_parent); - g_test_add_func("/initrd/cmdline/vlan/over-bond", test_vlan_over_bond); - g_test_add_func("/initrd/cmdline/bridge", test_bridge); - g_test_add_func("/initrd/cmdline/bridge/default", test_bridge_default); - g_test_add_func("/initrd/cmdline/bridge/ip", test_bridge_ip); - g_test_add_func("/initrd/cmdline/ibft/ip_dev", test_ibft_ip_dev); - g_test_add_func("/initrd/cmdline/ibft/ip_dev_mac", test_ibft_ip_dev_mac); - g_test_add_func("/initrd/cmdline/ibft/ip", test_ibft_ip); - g_test_add_func("/initrd/cmdline/ibft/rd_iscsi_ibft", test_ibft_rd_iscsi_ibft); - g_test_add_func("/initrd/cmdline/ignore_extra", test_ignore_extra); - g_test_add_func("/initrd/cmdline/rd_znet", test_rd_znet); - g_test_add_func("/initrd/cmdline/rd_znet/legacy", test_rd_znet_legacy); - g_test_add_func("/initrd/cmdline/rd_znet/no_ip", test_rd_znet_no_ip); - g_test_add_func("/initrd/cmdline/bootif/ip", test_bootif_ip); - g_test_add_func("/initrd/cmdline/bootif/no_ip", test_bootif_no_ip); - g_test_add_func("/initrd/cmdline/bootif/hwtype", test_bootif_hwtype); - g_test_add_func("/initrd/cmdline/bootif/off", test_bootif_off); - g_test_add_func("/initrd/cmdline/neednet", test_neednet); - g_test_add_func("/initrd/cmdline/dhcp/vendor_class_id", test_dhcp_vendor_class_id); - g_test_add_func("/initrd/cmdline/infiniband/iface", test_infiniband_iface); - g_test_add_func("/initrd/cmdline/infiniband/mac", test_infiniband_mac); - g_test_add_func("/initrd/cmdline/carrier_timeout", test_carrier_timeout); - - return g_test_run(); -} diff --git a/src/core/initrd/tests/test-dt-reader.c b/src/core/initrd/tests/test-dt-reader.c deleted file mode 100644 index 619a4e6f..00000000 --- a/src/core/initrd/tests/test-dt-reader.c +++ /dev/null @@ -1,144 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2014 - 2018 Red Hat, Inc. - */ - -#include "src/core/nm-default-daemon.h" - -#include -#include -#include -#include -#include -#include - -#include "nm-core-internal.h" -#include "NetworkManagerUtils.h" - -#include "../nm-initrd-generator.h" - -#include "nm-test-utils-core.h" - -#define TEST_INITRD_DIR NM_BUILD_SRCDIR "/src/core/initrd/tests" - -/*****************************************************************************/ - -static void -test_read_dt_ofw(void) -{ - NMConnection * connection; - NMSettingConnection *s_con; - NMSettingWired * s_wired; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - const char * mac_address; - - connection = nmi_dt_reader_parse(TEST_INITRD_DIR "/sysfs-dt"); - g_assert(connection); - nmtst_assert_connection_verifies(connection); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "OpenFirmware Connection"); - g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0); - g_assert(nm_setting_connection_get_autoconnect(s_con)); - - s_wired = nm_connection_get_setting_wired(connection); - g_assert(s_wired); - mac_address = nm_setting_wired_get_mac_address(s_wired); - g_assert(mac_address); - g_assert(nm_utils_hwaddr_matches(mac_address, -1, "ac:7f:3e:e5:d8:d8", -1)); - g_assert(!nm_setting_wired_get_duplex(s_wired)); - g_assert_cmpint(nm_setting_wired_get_speed(s_wired), ==, 0); - g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 0); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - g_assert_cmpstr(nm_setting_ip_config_get_dhcp_hostname(s_ip4), ==, "demiurge"); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); - - g_object_unref(connection); -} - -static void -test_read_dt_slof(void) -{ - NMConnection * connection; - NMSettingConnection *s_con; - NMSettingWired * s_wired; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - NMIPAddress * ip4_addr; - - connection = nmi_dt_reader_parse(TEST_INITRD_DIR "/sysfs-dt-tftp"); - g_assert(connection); - nmtst_assert_connection_verifies(connection); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "OpenFirmware Connection"); - g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0); - g_assert(nm_setting_connection_get_autoconnect(s_con)); - - s_wired = nm_connection_get_setting_wired(connection); - g_assert(s_wired); - g_assert(!nm_setting_wired_get_mac_address(s_wired)); - g_assert_cmpstr(nm_setting_wired_get_duplex(s_wired), ==, "half"); - g_assert_cmpint(nm_setting_wired_get_speed(s_wired), ==, 10); - g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 0); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), - ==, - NM_SETTING_IP4_CONFIG_METHOD_MANUAL); - - 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); - g_assert_cmpstr(nm_ip_address_get_address(ip4_addr), ==, "192.168.32.2"); - g_assert_cmpint(nm_ip_address_get_prefix(ip4_addr), ==, 16); - - g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, "192.168.32.1"); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), - ==, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED); - - g_object_unref(connection); -} - -static void -test_read_dt_none(void) -{ - NMConnection *connection; - - connection = nmi_dt_reader_parse(TEST_INITRD_DIR "/sysfs"); - g_assert(!connection); -} - -NMTST_DEFINE(); - -int -main(int argc, char **argv) -{ - nmtst_init_assert_logging(&argc, &argv, "INFO", "DEFAULT"); - - g_test_add_func("/initrd/dt/ofw", test_read_dt_ofw); - g_test_add_func("/initrd/dt/slof", test_read_dt_slof); - g_test_add_func("/initrd/dt/none", test_read_dt_none); - - return g_test_run(); -} diff --git a/src/core/initrd/tests/test-ibft-reader.c b/src/core/initrd/tests/test-ibft-reader.c deleted file mode 100644 index 1d263b9e..00000000 --- a/src/core/initrd/tests/test-ibft-reader.c +++ /dev/null @@ -1,303 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2014 - 2018 Red Hat, Inc. - */ - -#include "src/core/nm-default-daemon.h" - -#include -#include -#include -#include -#include -#include - -#include "nm-core-internal.h" -#include "NetworkManagerUtils.h" - -#include "../nm-initrd-generator.h" - -#include "nm-test-utils-core.h" - -#define TEST_INITRD_DIR NM_BUILD_SRCDIR "/src/core/initrd/tests" - -/*****************************************************************************/ - -static NMConnection * -read_connection(const char *sysfs_dir, const char *expected_mac, GError **error) -{ - NMConnection * connection = NULL; - gs_unref_hashtable GHashTable *ibft = NULL; - gs_free char * mac = NULL; - GHashTable * nic = NULL; - - ibft = nmi_ibft_read(sysfs_dir); - - mac = g_ascii_strup(expected_mac, -1); - nic = g_hash_table_lookup(ibft, mac); - if (!nic) - return NULL; - - connection = nm_simple_connection_new(); - - if (!nmi_ibft_update_connection_from_nic(connection, nic, error)) - g_clear_object(&connection); - - return connection; -} - -static void -test_read_ibft_dhcp(void) -{ - NMConnection * connection; - NMSettingConnection *s_con; - NMSettingWired * s_wired; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - GError * error = NULL; - const char * mac_address; - const char * expected_mac_address = "00:33:21:98:b9:f1"; - - connection = read_connection(TEST_INITRD_DIR "/sysfs-dhcp", expected_mac_address, &error); - g_assert_no_error(error); - nmtst_assert_connection_verifies_without_normalization(connection); - - g_assert(!nm_connection_get_setting_vlan(connection)); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "iBFT Connection 1"); - g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, NULL); - g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0); - g_assert(nm_setting_connection_get_autoconnect(s_con)); - - s_wired = nm_connection_get_setting_wired(connection); - g_assert(s_wired); - mac_address = nm_setting_wired_get_mac_address(s_wired); - g_assert(mac_address); - g_assert(nm_utils_hwaddr_matches(mac_address, -1, expected_mac_address, -1)); - g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 0); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), - ==, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED); - - g_object_unref(connection); -} - -static void -test_read_ibft_static(void) -{ - NMConnection * connection; - NMSettingConnection *s_con; - NMSettingWired * s_wired; - NMSettingIPConfig * s_ip4; - NMSettingIPConfig * s_ip6; - GError * error = NULL; - const char * mac_address; - const char * expected_mac_address = "00:33:21:98:b9:f0"; - NMIPAddress * ip4_addr; - - connection = read_connection(TEST_INITRD_DIR "/sysfs-static", expected_mac_address, &error); - g_assert_no_error(error); - nmtst_assert_connection_verifies_without_normalization(connection); - - g_assert(!nm_connection_get_setting_vlan(connection)); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_id(s_con), ==, "iBFT Connection 0"); - g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, NULL); - g_assert_cmpint(nm_setting_connection_get_timestamp(s_con), ==, 0); - g_assert(nm_setting_connection_get_autoconnect(s_con)); - - s_wired = nm_connection_get_setting_wired(connection); - g_assert(s_wired); - mac_address = nm_setting_wired_get_mac_address(s_wired); - g_assert(mac_address); - g_assert(nm_utils_hwaddr_matches(mac_address, -1, expected_mac_address, -1)); - g_assert_cmpint(nm_setting_wired_get_mtu(s_wired), ==, 0); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), - ==, - NM_SETTING_IP4_CONFIG_METHOD_MANUAL); - - 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), ==, "10.16.255.2"); - g_assert_cmpstr(nm_setting_ip_config_get_dns(s_ip4, 1), ==, "10.16.255.3"); - - 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); - g_assert_cmpstr(nm_ip_address_get_address(ip4_addr), ==, "192.168.32.72"); - g_assert_cmpint(nm_ip_address_get_prefix(ip4_addr), ==, 22); - - g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, "192.168.35.254"); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), - ==, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED); - - g_object_unref(connection); -} - -static void -test_read_ibft_bad_address(gconstpointer user_data) -{ - const char * sysfs_dir = user_data; - NMConnection *connection; - GError * error = NULL; - - g_assert(g_file_test(sysfs_dir, G_FILE_TEST_EXISTS)); - - connection = read_connection(sysfs_dir, "00:33:21:98:b9:f0", &error); - g_assert(connection == NULL); - g_assert(error); - g_clear_error(&error); -} - -static void -test_read_ibft_vlan(void) -{ - NMConnection * connection; - NMSettingConnection *s_con; - NMSettingWired * s_wired; - NMSettingVlan * s_vlan; - NMSettingIPConfig * s_ip4; - const char * mac_address; - const char * expected_mac_address = "00:33:21:98:b9:f0"; - NMIPAddress * ip4_addr; - GError * error = NULL; - - connection = read_connection(TEST_INITRD_DIR "/sysfs-vlan", expected_mac_address, &error); - g_assert_no_error(error); - nmtst_assert_connection_verifies_without_normalization(connection); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con), - ==, - NM_SETTING_VLAN_SETTING_NAME); - g_assert_cmpstr(nm_setting_connection_get_interface_name(s_con), ==, NULL); - - /* ===== WIRED SETTING ===== */ - s_wired = nm_connection_get_setting_wired(connection); - g_assert(s_wired); - mac_address = nm_setting_wired_get_mac_address(s_wired); - g_assert(mac_address); - g_assert(nm_utils_hwaddr_matches(mac_address, -1, expected_mac_address, -1)); - - /* ===== VLAN SETTING ===== */ - s_vlan = nm_connection_get_setting_vlan(connection); - g_assert(s_vlan); - g_assert_cmpint(nm_setting_vlan_get_id(s_vlan), ==, 123); - g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, NULL); - - /* ===== IPv4 SETTING ===== */ - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(s_ip4); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), - ==, - NM_SETTING_IP4_CONFIG_METHOD_MANUAL); - - g_assert_cmpint(nm_setting_ip_config_get_num_dns(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); - g_assert_cmpstr(nm_ip_address_get_address(ip4_addr), ==, "192.168.6.200"); - g_assert_cmpint(nm_ip_address_get_prefix(ip4_addr), ==, 24); - - g_assert_cmpstr(nm_setting_ip_config_get_gateway(s_ip4), ==, NULL); - - g_object_unref(connection); -} - -static void -test_read_ibft(void) -{ - NMConnection * connection; - NMSettingIPConfig *s_ip4; - NMSettingIPConfig *s_ip6; - GError * error = NULL; - - /* This test doesn't actually test too much (apart from the presence of - * IPv6 that is not covered by other tests), but the test fixture is a good - * example of about everything that can be included in iBFT table (as of - * ACPI 3.0b). */ - - connection = read_connection(TEST_INITRD_DIR "/sysfs", "00:53:00:AB:00:01", &error); - g_assert(connection); - g_assert_no_error(error); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - nmtst_assert_connection_verifies_without_normalization(connection); - g_assert(nm_setting_ip_config_get_num_addresses(s_ip4) == 0); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), - ==, - NM_SETTING_IP4_CONFIG_METHOD_DISABLED); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(nm_setting_ip_config_get_num_addresses(s_ip6) == 1); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); - g_object_unref(connection); - - connection = read_connection(TEST_INITRD_DIR "/sysfs", "00:53:06:66:AB:01", &error); - g_assert(connection); - g_assert_no_error(error); - nmtst_assert_connection_verifies_without_normalization(connection); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_assert(nm_setting_ip_config_get_num_addresses(s_ip4) == 1); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(nm_setting_ip_config_get_num_addresses(s_ip6) == 0); - g_assert_cmpstr(nm_setting_ip_config_get_method(s_ip6), - ==, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED); - g_object_unref(connection); -} - -NMTST_DEFINE(); - -int -main(int argc, char **argv) -{ - nmtst_init_assert_logging(&argc, &argv, "INFO", "DEFAULT"); - - g_test_add_func("/initrd/ibft", test_read_ibft); - g_test_add_func("/initrd/ibft/dhcp", test_read_ibft_dhcp); - g_test_add_func("/initrd/ibft/static", test_read_ibft_static); - g_test_add_func("/initrd/ibft/vlan", test_read_ibft_vlan); - g_test_add_data_func("/initrd/ibft/bad-ipaddr-read", - TEST_INITRD_DIR "/sysfs-bad-ipaddr", - test_read_ibft_bad_address); - g_test_add_data_func("/initrd/ibft/bad-gateway-read", - TEST_INITRD_DIR "/sysfs-bad-gateway", - test_read_ibft_bad_address); - g_test_add_data_func("/initrd/ibft/bad-dns1-read", - TEST_INITRD_DIR "/sysfs-bad-dns1", - test_read_ibft_bad_address); - g_test_add_data_func("/initrd/ibft/bad-dns2-read", - TEST_INITRD_DIR "/sysfs-bad-dns2", - test_read_ibft_bad_address); - - return g_test_run(); -} diff --git a/src/core/main.c b/src/core/main.c index 9b79bcbb..cfcdb860 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -20,7 +21,7 @@ #include "nm-dbus-interface.h" #include "NetworkManagerUtils.h" #include "nm-manager.h" -#include "platform/nm-linux-platform.h" +#include "libnm-platform/nm-linux-platform.h" #include "nm-dbus-manager.h" #include "devices/nm-device.h" #include "dhcp/nm-dhcp-manager.h" @@ -29,11 +30,11 @@ #include "nm-dispatcher.h" #include "settings/nm-settings.h" #include "nm-auth-manager.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-dbus-object.h" #include "nm-connectivity.h" #include "dns/nm-dns-manager.h" -#include "systemd/nm-sd.h" +#include "libnm-systemd-core/nm-sd.h" #include "nm-netns.h" #if !defined(NM_DIST_VERSION) @@ -508,7 +509,7 @@ main(int argc, char *argv[]) * physical interfaces. */ nm_log_dbg(LOGD_CORE, "setting up local loopback"); - nm_platform_link_set_up(NM_PLATFORM_GET, 1, NULL); + nm_platform_link_change_flags(NM_PLATFORM_GET, 1, IFF_UP, TRUE); success = TRUE; diff --git a/src/core/meson.build b/src/core/meson.build index 368a3e85..f4d7af64 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -1,27 +1,27 @@ # SPDX-License-Identifier: LGPL-2.1-or-later -src_inc = include_directories('.') +src_core_inc = include_directories('.') core_plugin_dep = declare_dependency( - sources: libnm_core_enum_sources[1], include_directories: [ - src_inc, + src_core_inc, top_inc, - shared_inc, - libnm_core_inc, + libnm_core_public_inc, ], dependencies: [ + libnm_core_public_dep, glib_dep, ], ) core_default_dep = declare_dependency( - sources: libnm_core_enum_sources[1], - include_directories: src_inc, + include_directories: [ + src_core_inc, + src_inc, + top_inc, + ], dependencies: [ - libnm_core_nm_default_dep, - libnm_log_core_dep, - libnm_platform_dep, + libnm_core_public_dep, ], ) @@ -30,19 +30,8 @@ install_data( install_dir: dbus_conf_dir, ) -subdir('systemd') - core_plugins = [] -daemon_c_flags = [ - '-DG_LOG_DOMAIN="NetworkManager"', -] - -platform_wifi_wext_source = files() -if enable_wext - platform_wifi_wext_source += files('platform/wifi/nm-wifi-utils-wext.c') -endif - libNetworkManagerBase = static_library( 'NetworkManagerBase', sources: files( @@ -54,13 +43,6 @@ libNetworkManagerBase = static_library( 'dhcp/nm-dhcp-options.c', 'ndisc/nm-lndp-ndisc.c', 'ndisc/nm-ndisc.c', - 'platform/wifi/nm-wifi-utils-nl80211.c', - 'platform/wifi/nm-wifi-utils.c', - 'platform/wpan/nm-wpan-utils.c', - 'platform/nm-linux-platform.c', - 'platform/nm-platform.c', - 'platform/nmp-object.c', - 'platform/nmp-rules-manager.c', 'main-utils.c', 'NetworkManagerUtils.c', 'nm-core-utils.c', @@ -73,23 +55,19 @@ libNetworkManagerBase = static_library( 'nm-ip-config.c', 'nm-ip4-config.c', 'nm-ip6-config.c', - ) + platform_wifi_wext_source, + ), dependencies: [ core_default_dep, - libn_dhcp4_dep, - libnm_core_dep, - libnm_systemd_shared_dep, - libnm_udev_aux_dep, + libnm_core_public_dep, libsystemd_dep, libudev_dep, ], - c_args: daemon_c_flags, ) nm_deps = [ + libnm_core_public_dep, core_default_dep, dl_dep, - libn_acd_dep, libndp_dep, libudev_dep, logind_dep, @@ -119,6 +97,7 @@ libNetworkManager = static_library( 'devices/nm-device-bond.c', 'devices/nm-device-bridge.c', 'devices/nm-device.c', + 'devices/nm-device-utils.c', 'devices/nm-device-dummy.c', 'devices/nm-device-ethernet.c', 'devices/nm-device-ethernet-utils.c', @@ -182,7 +161,8 @@ libNetworkManager = static_library( 'nm-dcb.c', 'nm-dhcp-config.c', 'nm-dispatcher.c', - 'nm-firewall-manager.c', + 'nm-firewall-utils.c', + 'nm-firewalld-manager.c', 'nm-hostname-manager.c', 'nm-keep-alive.c', 'nm-manager.c', @@ -194,7 +174,6 @@ libNetworkManager = static_library( 'nm-sleep-monitor.c', ), dependencies: nm_deps, - c_args: daemon_c_flags, link_with: [ libNetworkManagerBase, libnm_systemd_core, @@ -207,16 +186,28 @@ executable( 'nm-iface-helper.c', dependencies: [ core_default_dep, - dl_dep, - libndp_dep, + glib_dep, libudev_dep, - libn_acd_dep, + libndp_dep, + dl_dep, ], - c_args: daemon_c_flags, link_with: [ libNetworkManagerBase, + libnm_core_aux_intern, + libnm_core_impl, + libnm_crypto, libnm_systemd_core, + libnm_platform, libnm_systemd_shared, + libnm_base, + libnm_udev_aux, + libnm_log_core, + libnm_glib_aux, + libnm_std_aux, + libn_acd, + libn_dhcp4, + libc_rbtree, + libc_siphash, ], link_args: ldflags_linker_script_binary, link_depends: linker_script_binary, @@ -225,7 +216,7 @@ executable( ) if enable_tests - test_c_flags = daemon_c_flags + test_c_flags = [] if require_root_tests test_c_flags += ['-DREQUIRE_ROOT_TESTS=1'] endif @@ -244,7 +235,23 @@ if enable_tests libNetworkManagerTest_dep = declare_dependency( dependencies: core_default_dep, - link_with: libNetworkManagerTest, + link_with: [ + libNetworkManagerTest, + libnm_core_aux_intern, + libnm_core_impl, + libnm_crypto, + libnm_platform, + libnm_base, + libnm_systemd_shared, + libnm_udev_aux, + libnm_log_core, + libnm_glib_aux, + libnm_std_aux, + libn_acd, + libn_dhcp4, + libc_siphash, + libc_rbtree, + ], ) subdir('dnsmasq/tests') @@ -261,7 +268,6 @@ if enable_ppp endif subdir('devices') -subdir('initrd') subdir('settings/plugins') # NetworkManager binary @@ -274,13 +280,27 @@ subdir('settings/plugins') NetworkManager_all_sym = executable( 'NetworkManager-all-sym', 'main.c', - dependencies: nm_deps, - c_args: daemon_c_flags, + dependencies: [ + nm_deps, + libudev_dep, + ], link_args: '-Wl,--no-gc-sections', link_whole: [ libNetworkManager, libNetworkManagerBase, - libnm_core, + libnm_core_aux_intern, + libnm_core_impl, + libnm_crypto, + libnm_platform, + libnm_base, + libnm_log_core, + libnm_udev_aux, + libnm_glib_aux, + libnm_std_aux, + libn_acd, + libn_dhcp4, + libc_rbtree, + libc_siphash, ], ) @@ -301,9 +321,27 @@ ver_script = custom_target( NetworkManager = executable( 'NetworkManager', 'main.c', - dependencies: nm_deps, - c_args: daemon_c_flags, - link_with: libNetworkManager, + dependencies: [ + nm_deps, + libudev_dep, + ], + link_with: [ + libNetworkManager, + libNetworkManagerBase, + libnm_core_aux_intern, + libnm_core_impl, + libnm_crypto, + libnm_platform, + libnm_base, + libnm_udev_aux, + libnm_log_core, + libnm_glib_aux, + libnm_std_aux, + libn_acd, + libn_dhcp4, + libc_rbtree, + libc_siphash, + ], link_args: [ '-rdynamic', '-Wl,--version-script,@0@'.format(ver_script.full_path()), diff --git a/src/core/ndisc/nm-lndp-ndisc.c b/src/core/ndisc/nm-lndp-ndisc.c index f773478f..f11178f8 100644 --- a/src/core/ndisc/nm-lndp-ndisc.c +++ b/src/core/ndisc/nm-lndp-ndisc.c @@ -13,12 +13,12 @@ #include #include -#include "nm-glib-aux/nm-str-buf.h" -#include "systemd/nm-sd-utils-shared.h" +#include "libnm-glib-aux/nm-str-buf.h" +#include "libnm-systemd-shared/nm-sd-utils-shared.h" #include "nm-ndisc-private.h" #include "NetworkManagerUtils.h" -#include "platform/nm-platform.h" -#include "nm-platform/nmp-netns.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-platform/nmp-netns.h" #define _NMLOG_PREFIX_NAME "ndisc-lndp" @@ -85,14 +85,14 @@ send_rs(NMNDisc *ndisc, GError **error) static NMIcmpv6RouterPref _route_preference_coerce(enum ndp_route_preference pref) { -#define _ASSERT_ENUM(v1, v2) \ - G_STMT_START \ - { \ - G_STATIC_ASSERT((NMIcmpv6RouterPref)(v1) == (v2)); \ - G_STATIC_ASSERT((enum ndp_route_preference)(v2) == (v1)); \ - G_STATIC_ASSERT((gint64)(v1) == (v2)); \ - G_STATIC_ASSERT((gint64)(v2) == (v1)); \ - } \ +#define _ASSERT_ENUM(v1, v2) \ + G_STMT_START \ + { \ + G_STATIC_ASSERT((NMIcmpv6RouterPref) (v1) == (v2)); \ + G_STATIC_ASSERT((enum ndp_route_preference) (v2) == (v1)); \ + G_STATIC_ASSERT((gint64) (v1) == (v2)); \ + G_STATIC_ASSERT((gint64) (v2) == (v1)); \ + } \ G_STMT_END switch (pref) { diff --git a/src/core/ndisc/nm-ndisc.c b/src/core/ndisc/nm-ndisc.c index a5c1b935..cf1b58ec 100644 --- a/src/core/ndisc/nm-ndisc.c +++ b/src/core/ndisc/nm-ndisc.c @@ -14,8 +14,8 @@ #include "nm-ndisc-private.h" #include "nm-utils.h" -#include "platform/nm-platform.h" -#include "nm-platform/nmp-netns.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-platform/nmp-netns.h" #include "nm-l3-config-data.h" #define _NMLOG_PREFIX_NAME "ndisc" @@ -806,7 +806,7 @@ solicit_retransmit_time_jitter(gint32 solicit_retransmit_time_msec) ten_percent = NM_MAX(1, solicit_retransmit_time_msec / 10); return solicit_retransmit_time_msec - ten_percent - + ((gint32)(g_random_int() % (2u * ((guint32) ten_percent)))); + + ((gint32) (g_random_int() % (2u * ((guint32) ten_percent)))); } static gboolean @@ -882,7 +882,7 @@ solicit_timer_start(NMNDisc *ndisc) * a suitable delay in 2021. Wait only up to 250 msec instead. */ delay_msec = - g_random_int() % ((guint32)(NM_NDISC_RFC4861_MAX_RTR_SOLICITATION_DELAY * 1000 / 4)); + g_random_int() % ((guint32) (NM_NDISC_RFC4861_MAX_RTR_SOLICITATION_DELAY * 1000 / 4)); _LOGD("solicit: schedule sending first solicitation (of %d) in %.3f seconds", priv->router_solicitations, diff --git a/src/core/ndisc/nm-ndisc.h b/src/core/ndisc/nm-ndisc.h index 93aee4db..15f95d20 100644 --- a/src/core/ndisc/nm-ndisc.h +++ b/src/core/ndisc/nm-ndisc.h @@ -13,8 +13,8 @@ #include "nm-setting-ip6-config.h" #include "NetworkManagerUtils.h" -#include "platform/nm-platform.h" -#include "platform/nmp-object.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-platform/nmp-object.h" #define NM_RA_TIMEOUT_DEFAULT ((guint32) 0) #define NM_RA_TIMEOUT_INFINITY ((guint32) G_MAXINT32) @@ -99,7 +99,7 @@ _nm_ndisc_lifetime_from_expiry(gint64 now_msec, gint64 expiry_msec, gboolean cei diff += 999; } - return NM_MIN(diff / 1000, (gint64)(G_MAXUINT32 - 1)); + return NM_MIN(diff / 1000, (gint64) (G_MAXUINT32 - 1)); } /*****************************************************************************/ @@ -159,10 +159,10 @@ typedef enum { #define NM_NDISC_RFC4861_MAX_RTR_SOLICITATION_DELAY 1 /* seconds */ #define NM_NDISC_MAX_ADDRESSES_DEFAULT 16 -#define NM_NDISC_ROUTER_SOLICITATIONS_DEFAULT 3 /* RFC4861, MAX_RTR_SOLICITATIONS */ -#define NM_NDISC_ROUTER_ADVERTISEMENTS_DEFAULT 3 /* RFC4861, MAX_INITIAL_RTR_ADVERTISEMENTS */ -#define NM_NDISC_ROUTER_ADVERT_DELAY 3 /* RFC4861, MIN_DELAY_BETWEEN_RAS */ -#define NM_NDISC_ROUTER_ADVERT_INITIAL_INTERVAL 16 /* RFC4861, MAX_INITIAL_RTR_ADVERT_INTERVAL */ +#define NM_NDISC_ROUTER_SOLICITATIONS_DEFAULT 3 /* RFC4861, MAX_RTR_SOLICITATIONS */ +#define NM_NDISC_ROUTER_ADVERTISEMENTS_DEFAULT 3 /* RFC4861, MAX_INITIAL_RTR_ADVERTISEMENTS */ +#define NM_NDISC_ROUTER_ADVERT_DELAY 3 /* RFC4861, MIN_DELAY_BETWEEN_RAS */ +#define NM_NDISC_ROUTER_ADVERT_INITIAL_INTERVAL 16 /* RFC4861, MAX_INITIAL_RTR_ADVERT_INTERVAL */ #define NM_NDISC_ROUTER_ADVERT_DELAY_MS 500 /* RFC4861, MAX_RA_DELAY_TIME */ #define NM_NDISC_ROUTER_ADVERT_MAX_INTERVAL 600 /* RFC4861, MaxRtrAdvInterval default */ #define NM_NDISC_ROUTER_LIFETIME 900 /* 1.5 * NM_NDISC_ROUTER_ADVERT_MAX_INTERVAL */ diff --git a/src/core/ndisc/tests/test-ndisc-linux.c b/src/core/ndisc/tests/test-ndisc-linux.c index 9a5df60b..c84ee142 100644 --- a/src/core/ndisc/tests/test-ndisc-linux.c +++ b/src/core/ndisc/tests/test-ndisc-linux.c @@ -10,7 +10,7 @@ #include "ndisc/nm-ndisc.h" #include "ndisc/nm-lndp-ndisc.h" -#include "platform/nm-linux-platform.h" +#include "libnm-platform/nm-linux-platform.h" #include "nm-test-utils-core.h" diff --git a/src/core/nm-act-request.c b/src/core/nm-act-request.c index defe3e8c..d0a2e0c7 100644 --- a/src/core/nm-act-request.c +++ b/src/core/nm-act-request.c @@ -13,17 +13,19 @@ #include #include "c-list/src/c-list.h" +#include "libnm-core-aux-intern/nm-auth-subject.h" -#include "nm-setting-wireless-security.h" #include "nm-setting-8021x.h" +#include "nm-setting-wireless-security.h" + #include "devices/nm-device.h" #include "nm-active-connection.h" +#include "nm-firewall-utils.h" #include "settings/nm-settings-connection.h" -#include "nm-libnm-core-intern/nm-auth-subject.h" typedef struct { - CList call_ids_lst_head; - NMUtilsShareRules *share_rules; + CList call_ids_lst_head; + NMFirewallConfig *firewall_config; } NMActRequestPrivate; struct _NMActRequest { @@ -248,31 +250,31 @@ nm_act_request_clear_secrets(NMActRequest *self) /*****************************************************************************/ -NMUtilsShareRules * +NMFirewallConfig * nm_act_request_get_shared(NMActRequest *req) { g_return_val_if_fail(NM_IS_ACT_REQUEST(req), FALSE); - return NM_ACT_REQUEST_GET_PRIVATE(req)->share_rules; + return NM_ACT_REQUEST_GET_PRIVATE(req)->firewall_config; } void -nm_act_request_set_shared(NMActRequest *req, NMUtilsShareRules *rules) +nm_act_request_set_shared(NMActRequest *req, NMFirewallConfig *rules) { NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE(req); g_return_if_fail(NM_IS_ACT_REQUEST(req)); - if (priv->share_rules == rules) + if (priv->firewall_config == rules) return; - if (priv->share_rules) { - nm_utils_share_rules_apply(priv->share_rules, FALSE); - priv->share_rules = NULL; + if (priv->firewall_config) { + nm_firewall_config_apply(priv->firewall_config, FALSE); + priv->firewall_config = NULL; } if (rules) { - priv->share_rules = rules; - nm_utils_share_rules_apply(priv->share_rules, TRUE); + priv->firewall_config = rules; + nm_firewall_config_apply(priv->firewall_config, TRUE); } } @@ -506,9 +508,9 @@ dispose(GObject *object) c_list_for_each_entry_safe (call_id, call_id_safe, &priv->call_ids_lst_head, call_ids_lst) _do_cancel_secrets(self, call_id, TRUE); - if (priv->share_rules) { - nm_utils_share_rules_apply(priv->share_rules, FALSE); - nm_clear_pointer(&priv->share_rules, nm_utils_share_rules_free); + if (priv->firewall_config) { + nm_firewall_config_apply(priv->firewall_config, FALSE); + nm_clear_pointer(&priv->firewall_config, nm_firewall_config_free); } G_OBJECT_CLASS(nm_act_request_parent_class)->dispose(object); diff --git a/src/core/nm-act-request.h b/src/core/nm-act-request.h index 2a568430..9c702d31 100644 --- a/src/core/nm-act-request.h +++ b/src/core/nm-act-request.h @@ -38,11 +38,11 @@ NMConnection *nm_act_request_get_applied_connection(NMActRequest *req); /*****************************************************************************/ -struct _NMUtilsShareRules; +struct _NMFirewallConfig; -struct _NMUtilsShareRules *nm_act_request_get_shared(NMActRequest *req); +struct _NMFirewallConfig *nm_act_request_get_shared(NMActRequest *req); -void nm_act_request_set_shared(NMActRequest *req, struct _NMUtilsShareRules *rules); +void nm_act_request_set_shared(NMActRequest *req, struct _NMFirewallConfig *rules); /*****************************************************************************/ diff --git a/src/core/nm-active-connection.c b/src/core/nm-active-connection.c index 3c8c472e..bf2c4a39 100644 --- a/src/core/nm-active-connection.c +++ b/src/core/nm-active-connection.c @@ -7,17 +7,17 @@ #include "nm-active-connection.h" -#include "nm-libnm-core-intern/nm-common-macros.h" +#include "libnm-core-aux-intern/nm-common-macros.h" #include "nm-dbus-interface.h" #include "devices/nm-device.h" #include "settings/nm-settings-connection.h" #include "nm-simple-connection.h" #include "nm-auth-utils.h" #include "nm-auth-manager.h" -#include "nm-libnm-core-intern/nm-auth-subject.h" +#include "libnm-core-aux-intern/nm-auth-subject.h" #include "nm-keep-alive.h" #include "NetworkManagerUtils.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #define AUTH_CALL_ID_SHARED_WIFI_PERMISSION_FAILED ((NMAuthManagerCallId *) GINT_TO_POINTER(1)) @@ -516,11 +516,6 @@ nm_active_connection_clear_secrets(NMActiveConnection *self) priv = NM_ACTIVE_CONNECTION_GET_PRIVATE(self); - if (nm_settings_connection_has_unmodified_applied_connection(priv->settings_connection.obj, - priv->applied_connection, - NM_SETTING_COMPARE_FLAG_NONE)) { - nm_settings_connection_clear_secrets(priv->settings_connection.obj, FALSE, FALSE); - } nm_connection_clear_secrets(priv->applied_connection); } @@ -1560,54 +1555,48 @@ static const GDBusSignalInfo signal_info_state_changed = NM_DEFINE_GDBUS_SIGNAL_ static const NMDBusInterfaceInfoExtended interface_info_active_connection = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_ACTIVE_CONNECTION, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, - &signal_info_state_changed, ), + .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&signal_info_state_changed, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Connection", - "o", - NM_ACTIVE_CONNECTION_CONNECTION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("SpecificObject", - "o", - NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Id", "s", NM_ACTIVE_CONNECTION_ID), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Uuid", - "s", - NM_ACTIVE_CONNECTION_UUID), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Type", - "s", - NM_ACTIVE_CONNECTION_TYPE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Devices", - "ao", - NM_ACTIVE_CONNECTION_DEVICES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("State", - "u", - NM_ACTIVE_CONNECTION_STATE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("StateFlags", - "u", - NM_ACTIVE_CONNECTION_STATE_FLAGS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Default", - "b", - NM_ACTIVE_CONNECTION_DEFAULT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Ip4Config", - "o", - NM_ACTIVE_CONNECTION_IP4_CONFIG), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Dhcp4Config", - "o", - NM_ACTIVE_CONNECTION_DHCP4_CONFIG), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Default6", - "b", - NM_ACTIVE_CONNECTION_DEFAULT6), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Ip6Config", - "o", - NM_ACTIVE_CONNECTION_IP6_CONFIG), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Dhcp6Config", - "o", - NM_ACTIVE_CONNECTION_DHCP6_CONFIG), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Vpn", "b", NM_ACTIVE_CONNECTION_VPN), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Master", - "o", - NM_ACTIVE_CONNECTION_MASTER), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Connection", + "o", + NM_ACTIVE_CONNECTION_CONNECTION), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("SpecificObject", + "o", + NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Id", "s", NM_ACTIVE_CONNECTION_ID), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Uuid", "s", NM_ACTIVE_CONNECTION_UUID), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Type", "s", NM_ACTIVE_CONNECTION_TYPE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Devices", + "ao", + NM_ACTIVE_CONNECTION_DEVICES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("State", + "u", + NM_ACTIVE_CONNECTION_STATE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("StateFlags", + "u", + NM_ACTIVE_CONNECTION_STATE_FLAGS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Default", + "b", + NM_ACTIVE_CONNECTION_DEFAULT), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Ip4Config", + "o", + NM_ACTIVE_CONNECTION_IP4_CONFIG), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Dhcp4Config", + "o", + NM_ACTIVE_CONNECTION_DHCP4_CONFIG), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Default6", + "b", + NM_ACTIVE_CONNECTION_DEFAULT6), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Ip6Config", + "o", + NM_ACTIVE_CONNECTION_IP6_CONFIG), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Dhcp6Config", + "o", + NM_ACTIVE_CONNECTION_DHCP6_CONFIG), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Vpn", "b", NM_ACTIVE_CONNECTION_VPN), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Master", + "o", + NM_ACTIVE_CONNECTION_MASTER), ), ), }; static void diff --git a/src/core/nm-audit-manager.c b/src/core/nm-audit-manager.c index 8f419472..2ef5d860 100644 --- a/src/core/nm-audit-manager.c +++ b/src/core/nm-audit-manager.c @@ -11,14 +11,18 @@ #include #endif -#include "nm-libnm-core-intern/nm-auth-subject.h" +#define NM_VALUE_TYPE_DEFINE_FUNCTIONS + +#include "libnm-core-aux-intern/nm-auth-subject.h" +#include "libnm-glib-aux/nm-str-buf.h" +#include "libnm-glib-aux/nm-value-type.h" #include "nm-config.h" #include "nm-dbus-manager.h" #include "settings/nm-settings-connection.h" /*****************************************************************************/ -typedef enum { +typedef enum _nm_packed { BACKEND_LOG = (1 << 0), BACKEND_AUDITD = (1 << 1), _BACKEND_LAST, @@ -26,10 +30,11 @@ typedef enum { } AuditBackend; typedef struct { - const char * name; - GValue value; - gboolean need_encoding; - AuditBackend backends; + const char * name; + AuditBackend backends; + bool need_encoding; + NMValueType value_type; + NMValueTypUnion value; } AuditField; /*****************************************************************************/ @@ -85,66 +90,77 @@ _audit_field_init_string(AuditField * field, 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); + *field = (AuditField){ + .name = name, + .need_encoding = need_encoding, + .backends = backends, + .value_type = NM_VALUE_TYPE_STRING, + .value.v_string = str, + }; } static void -_audit_field_init_uint(AuditField *field, const char *name, uint val, AuditBackend backends) +_audit_field_init_uint64(AuditField *field, const char *name, guint64 val, AuditBackend backends) { - field->name = name; - field->backends = backends; - g_value_init(&field->value, G_TYPE_UINT); - g_value_set_uint(&field->value, val); + *field = (AuditField){ + .name = name, + .backends = backends, + .value_type = NM_VALUE_TYPE_UINT64, + .value.v_uint64 = val, + }; } -static char * -build_message(GPtrArray *fields, AuditBackend backend) +static const char * +build_message(NMStrBuf *strbuf, AuditBackend backend, GPtrArray *fields) { - GString * string; - AuditField *field; - gboolean first = TRUE; - guint i; + guint i; - string = g_string_new(NULL); + if (strbuf->len == 0) { + /* preallocate a large buffer... */ + nm_str_buf_maybe_expand(strbuf, NM_UTILS_GET_NEXT_REALLOC_SIZE_232, FALSE); + } else + nm_str_buf_reset(strbuf); for (i = 0; i < fields->len; i++) { - field = fields->pdata[i]; + const AuditField *field = fields->pdata[i]; if (!NM_FLAGS_ANY(field->backends, backend)) continue; - if (first) - first = FALSE; - else - g_string_append_c(string, ' '); + nm_str_buf_append_required_delimiter(strbuf, ' '); - if (G_VALUE_HOLDS_STRING(&field->value)) { - const char *str = g_value_get_string(&field->value); + if (field->value_type == NM_VALUE_TYPE_STRING) { + const char *str = field->value.v_string; #if HAVE_LIBAUDIT if (backend == BACKEND_AUDITD) { if (field->need_encoding) { - char *value; + gs_free char *value = NULL; value = audit_encode_nv_string(field->name, str, 0); - g_string_append(string, value); - g_free(value); + nm_str_buf_append(strbuf, value); } else - g_string_append_printf(string, "%s=%s", field->name, str); + nm_str_buf_append_printf(strbuf, "%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(); + + nm_str_buf_append_printf(strbuf, "%s=\"%s\"", field->name, str); + continue; + } + + if (field->value_type == NM_VALUE_TYPE_UINT64) { + nm_str_buf_append_printf(strbuf, + "%s=%" G_GUINT64_FORMAT, + field->name, + field->value.v_uint64); + continue; + } + + g_return_val_if_reached(NULL); } - return g_string_free(string, FALSE); + + return nm_str_buf_get_str(strbuf); } static void @@ -155,10 +171,10 @@ nm_audit_log(NMAuditManager *self, const char * func, gboolean success) { + nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT(0, FALSE); #if HAVE_LIBAUDIT NMAuditManagerPrivate *priv; #endif - char *msg; g_return_if_fail(NM_IS_AUDIT_MANAGER(self)); @@ -166,16 +182,29 @@ nm_audit_log(NMAuditManager *self, 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); + audit_log_user_message(priv->auditd_fd, + AUDIT_USYS_CONFIG, + build_message(&strbuf, BACKEND_AUDITD, fields), + NULL, + NULL, + NULL, + success); } #endif if (nm_logging_enabled(AUDIT_LOG_LEVEL, LOGD_AUDIT)) { - msg = build_message(fields, BACKEND_LOG); - _NMLOG(AUDIT_LOG_LEVEL, LOGD_AUDIT, "%s", msg); - g_free(msg); + _nm_log_full(file, + line, + func, + !(NM_THREAD_SAFE_ON_MAIN_THREAD), + AUDIT_LOG_LEVEL, + LOGD_AUDIT, + 0, + NULL, + NULL, + "%s%s", + _NMLOG_PREFIX_NAME ": ", + build_message(&strbuf, BACKEND_LOG, fields)); } } @@ -190,9 +219,13 @@ _audit_log_helper(NMAuditManager *self, gpointer subject_context, const char * reason) { - AuditField op_field = {}, pid_field = {}, uid_field = {}; - AuditField result_field = {}, reason_field = {}; - gulong pid, uid; + AuditField op_field; + AuditField pid_field; + AuditField uid_field; + AuditField result_field; + AuditField reason_field; + gulong pid; + gulong uid; NMAuthSubject * subject = NULL; gs_unref_object NMAuthSubject *subject_free = NULL; @@ -213,11 +246,11 @@ _audit_log_helper(NMAuditManager *self, 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); + _audit_field_init_uint64(&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); + _audit_field_init_uint64(&uid_field, "uid", uid, BACKEND_ALL); g_ptr_array_add(fields, &uid_field); } } @@ -262,8 +295,10 @@ _nm_audit_manager_log_connection_op(NMAuditManager * self, gpointer subject_context, const char * reason) { - gs_unref_ptrarray GPtrArray *fields = NULL; - AuditField uuid_field = {}, name_field = {}, args_field = {}; + gs_unref_ptrarray GPtrArray *fields = NULL; + AuditField uuid_field; + AuditField name_field; + AuditField args_field; g_return_if_fail(op); @@ -304,8 +339,8 @@ _nm_audit_manager_log_generic_op(NMAuditManager *self, gpointer subject_context, const char * reason) { - gs_unref_ptrarray GPtrArray *fields = NULL; - AuditField arg_field = {}; + gs_unref_ptrarray GPtrArray *fields = NULL; + AuditField arg_field; g_return_if_fail(op); g_return_if_fail(arg); @@ -330,8 +365,10 @@ _nm_audit_manager_log_device_op(NMAuditManager *self, gpointer subject_context, const char * reason) { - gs_unref_ptrarray GPtrArray *fields = NULL; - AuditField interface_field = {}, ifindex_field = {}, args_field = {}; + gs_unref_ptrarray GPtrArray *fields = NULL; + AuditField interface_field; + AuditField ifindex_field; + AuditField args_field; int ifindex; g_return_if_fail(op); @@ -348,7 +385,7 @@ _nm_audit_manager_log_device_op(NMAuditManager *self, ifindex = nm_device_get_ip_ifindex(device); if (ifindex > 0) { - _audit_field_init_uint(&ifindex_field, "ifindex", ifindex, BACKEND_ALL); + _audit_field_init_uint64(&ifindex_field, "ifindex", ifindex, BACKEND_ALL); g_ptr_array_add(fields, &ifindex_field); } diff --git a/src/core/nm-auth-manager.c b/src/core/nm-auth-manager.c index 9470838c..5c0e465a 100644 --- a/src/core/nm-auth-manager.c +++ b/src/core/nm-auth-manager.c @@ -8,9 +8,9 @@ #include "nm-auth-manager.h" #include "c-list/src/c-list.h" -#include "nm-glib-aux/nm-dbus-aux.h" +#include "libnm-glib-aux/nm-dbus-aux.h" #include "nm-errors.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-dbus-manager.h" #include "NetworkManagerUtils.h" diff --git a/src/core/nm-auth-manager.h b/src/core/nm-auth-manager.h index 991083c1..0586322f 100644 --- a/src/core/nm-auth-manager.h +++ b/src/core/nm-auth-manager.h @@ -6,7 +6,7 @@ #ifndef NM_AUTH_MANAGER_H #define NM_AUTH_MANAGER_H -#include "nm-libnm-core-intern/nm-auth-subject.h" +#include "libnm-core-aux-intern/nm-auth-subject.h" #include "nm-config-data.h" /*****************************************************************************/ diff --git a/src/core/nm-auth-utils.c b/src/core/nm-auth-utils.c index 12da5749..006264dd 100644 --- a/src/core/nm-auth-utils.c +++ b/src/core/nm-auth-utils.c @@ -7,9 +7,9 @@ #include "nm-auth-utils.h" -#include "nm-glib-aux/nm-c-list.h" +#include "libnm-glib-aux/nm-c-list.h" #include "nm-setting-connection.h" -#include "nm-libnm-core-intern/nm-auth-subject.h" +#include "libnm-core-aux-intern/nm-auth-subject.h" #include "nm-auth-manager.h" #include "nm-session-monitor.h" #include "nm-dbus-manager.h" diff --git a/src/core/nm-checkpoint.c b/src/core/nm-checkpoint.c index 2088c247..164f4a86 100644 --- a/src/core/nm-checkpoint.c +++ b/src/core/nm-checkpoint.c @@ -9,7 +9,7 @@ #include "nm-active-connection.h" #include "nm-act-request.h" -#include "nm-libnm-core-intern/nm-auth-subject.h" +#include "libnm-core-aux-intern/nm-auth-subject.h" #include "nm-core-utils.h" #include "nm-dbus-interface.h" #include "devices/nm-device.h" @@ -229,14 +229,16 @@ restore_and_activate_connection(NMCheckpoint *self, DeviceCheckpoint *dev_checkp if (need_update) { _LOGD("rollback: updating connection %s", nm_settings_connection_get_uuid(connection)); persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP; - nm_settings_connection_update(connection, - dev_checkpoint->settings_connection, - persist_mode, - sett_flags, - sett_mask, - NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE, - "checkpoint-rollback", - NULL); + nm_settings_connection_update( + connection, + dev_checkpoint->settings_connection, + persist_mode, + sett_flags, + sett_mask, + NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_SYSTEM_SECRETS + | NM_SETTINGS_CONNECTION_UPDATE_REASON_UPDATE_NON_SECRET, + "checkpoint-rollback", + NULL); } } else { /* The connection was deleted, recreate it */ @@ -737,16 +739,12 @@ dispose(GObject *object) static const NMDBusInterfaceInfoExtended interface_info_checkpoint = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_CHECKPOINT, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Devices", - "ao", - NM_CHECKPOINT_DEVICES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Created", "x", NM_CHECKPOINT_CREATED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("RollbackTimeout", - "u", - NM_CHECKPOINT_ROLLBACK_TIMEOUT), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Devices", "ao", NM_CHECKPOINT_DEVICES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Created", "x", NM_CHECKPOINT_CREATED), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("RollbackTimeout", + "u", + NM_CHECKPOINT_ROLLBACK_TIMEOUT), ), ), }; static void diff --git a/src/core/nm-config-data.c b/src/core/nm-config-data.c index c62c6773..e127ea23 100644 --- a/src/core/nm-config-data.c +++ b/src/core/nm-config-data.c @@ -10,9 +10,9 @@ #include "nm-config.h" #include "devices/nm-device.h" -#include "nm-core-internal.h" -#include "nm-keyfile-internal.h" -#include "nm-keyfile-utils.h" +#include "libnm-core-intern/nm-core-internal.h" +#include "libnm-core-intern/nm-keyfile-internal.h" +#include "libnm-core-intern/nm-keyfile-utils.h" /*****************************************************************************/ @@ -26,6 +26,8 @@ typedef struct { gboolean has; GSList * spec; } match_device; + gsize lookup_len; + const NMUtilsNamedValue *lookup_idx; } MatchSectionInfo; struct _NMGlobalDnsDomain { @@ -97,6 +99,8 @@ typedef struct { NMGlobalDnsConfig *global_dns; bool systemd_resolved : 1; + + char *iwd_config_path; } NMConfigDataPrivate; struct _NMConfigData { @@ -114,6 +118,11 @@ G_DEFINE_TYPE(NMConfigData, nm_config_data, G_TYPE_OBJECT) /*****************************************************************************/ +static const char * +_match_section_info_get_str(const MatchSectionInfo *m, GKeyFile *keyfile, const char *property); + +/*****************************************************************************/ + const char * nm_config_data_get_config_main_file(const NMConfigData *self) { @@ -341,12 +350,18 @@ nm_config_data_get_systemd_resolved(const NMConfigData *self) return NM_CONFIG_DATA_GET_PRIVATE(self)->systemd_resolved; } +const char * +nm_config_data_get_iwd_config_path(const NMConfigData *self) +{ + return NM_CONFIG_DATA_GET_PRIVATE(self)->iwd_config_path; +} + gboolean nm_config_data_get_ignore_carrier(const NMConfigData *self, NMDevice *device) { - gs_free char *value = NULL; - gboolean has_match; - int m; + const char *value; + gboolean has_match; + int m; g_return_val_if_fail(NM_IS_CONFIG_DATA(self), FALSE); g_return_val_if_fail(NM_IS_DEVICE(device), FALSE); @@ -437,7 +452,7 @@ static NMAuthPolkitMode _config_data_get_main_auth_polkit(const NMConfigData *self, gboolean *out_invalid_config) { NMAuthPolkitMode auth_polkit_mode; - const char * str; + gs_free char * str = NULL; str = nm_config_data_get_value(self, NM_CONFIG_KEYFILE_GROUP_MAIN, @@ -576,7 +591,7 @@ _merge_keyfiles(GKeyFile *keyfile_user, GKeyFile *keyfile_intern) const char * key = keys[k]; gs_free char *value = NULL; - if (is_atomic && strcmp(key, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS) == 0) + if (is_atomic && nm_streq(key, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS)) continue; if (!is_intern && !is_atomic @@ -684,6 +699,7 @@ static const struct { NM_CONFIG_KEYFILE_KEY_MAIN_AUTH_POLKIT, NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT}, {NM_CONFIG_KEYFILE_GROUP_MAIN, NM_CONFIG_KEYFILE_KEY_MAIN_DHCP, NM_CONFIG_DEFAULT_MAIN_DHCP}, + {NM_CONFIG_KEYFILE_GROUP_MAIN, NM_CONFIG_KEYFILE_KEY_MAIN_IWD_CONFIG_PATH, ""}, {NM_CONFIG_KEYFILE_GROUP_LOGGING, "backend", NM_CONFIG_DEFAULT_LOGGING_BACKEND}, {NM_CONFIG_KEYFILE_GROUP_LOGGING, "audit", NM_CONFIG_DEFAULT_LOGGING_AUDIT}, }; @@ -1116,7 +1132,7 @@ load_global_dns(GKeyFile *keyfile, gboolean internal) g_hash_table_insert(dns_config->domains, strdup(name), domain); - if (!strcmp(name, "*")) + if (name[0] == '*' && name[1] == '\0') default_found = TRUE; } @@ -1213,7 +1229,7 @@ global_dns_domain_from_dbus(char *name, GVariant *variant) 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"))) { + if (nm_streq0(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++) { @@ -1230,7 +1246,7 @@ global_dns_domain_from_dbus(char *name, GVariant *variant) g_strfreev(domain->servers); domain->servers = strv; } - } else if (!g_strcmp0(key, "options") && g_variant_is_of_type(val, G_VARIANT_TYPE("as"))) { + } else if (nm_streq0(key, "options") && g_variant_is_of_type(val, G_VARIANT_TYPE("as"))) { strv = g_variant_dup_strv(val, NULL); g_strfreev(domain->options); domain->options = _nm_utils_strv_cleanup(strv, TRUE, TRUE, TRUE); @@ -1278,10 +1294,10 @@ nm_global_dns_config_from_dbus(const GValue *value, GError **error) 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"))) { + if (nm_streq0(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"))) { + } else if (nm_streq0(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); @@ -1297,7 +1313,7 @@ nm_global_dns_config_from_dbus(const GValue *value, GError **error) strv[j] = NULL; dns_config->options = strv; } - } else if (!g_strcmp0(key, "domains") + } else if (nm_streq0(key, "domains") && g_variant_is_of_type(val, G_VARIANT_TYPE("a{sv}"))) { NMGlobalDnsDomain *domain; GVariantIter domain_iter; @@ -1381,18 +1397,18 @@ _match_section_infos_lookup(const MatchSectionInfo *match_section_infos, NMDevice * device, const NMPlatformLink * pllink, const char * match_device_type, - char ** out_value) + const char ** out_value) { const char *match_dhcp_plugin; if (!match_section_infos) - return NULL; + goto out; match_dhcp_plugin = nm_dhcp_manager_get_config(nm_dhcp_manager_get()); for (; match_section_infos->group_name; match_section_infos++) { - char * value = NULL; - gboolean match; + const char *value; + gboolean match; /* FIXME: Here we use g_key_file_get_string(). This should be in sync with what keyfile-reader * does. @@ -1401,7 +1417,7 @@ _match_section_infos_lookup(const MatchSectionInfo *match_section_infos, * string_to_value(keyfile_to_string(keyfile)) in one. Optimally, keyfile library would * expose both functions, and we would return here keyfile_to_string(keyfile). * The caller then could convert the string to the proper value via string_to_value(value). */ - value = g_key_file_get_string(keyfile, match_section_infos->group_name, property, NULL); + value = _match_section_info_get_str(match_section_infos, keyfile, property); if (!value && !match_section_infos->stop_match) continue; @@ -1423,12 +1439,14 @@ _match_section_infos_lookup(const MatchSectionInfo *match_section_infos, *out_value = value; return match_section_infos; } - g_free(value); } + +out: + *out_value = NULL; return NULL; } -char * +const char * nm_config_data_get_device_config(const NMConfigData *self, const char * property, NMDevice * device, @@ -1436,7 +1454,7 @@ nm_config_data_get_device_config(const NMConfigData *self, { const NMConfigDataPrivate *priv; const MatchSectionInfo * connection_info; - char * value = NULL; + const char * value; NM_SET_OUT(has_match, FALSE); @@ -1456,7 +1474,7 @@ nm_config_data_get_device_config(const NMConfigData *self, return value; } -char * +const char * nm_config_data_get_device_config_by_pllink(const NMConfigData * self, const char * property, const NMPlatformLink *pllink, @@ -1465,7 +1483,7 @@ nm_config_data_get_device_config_by_pllink(const NMConfigData * self, { const NMConfigDataPrivate *priv; const MatchSectionInfo * connection_info; - char * value = NULL; + const char * value; g_return_val_if_fail(self, NULL); g_return_val_if_fail(property && *property, NULL); @@ -1490,8 +1508,8 @@ nm_config_data_get_device_config_boolean(const NMConfigData *self, int val_no_match, int val_invalid) { - gs_free char *value = NULL; - gboolean has_match; + const char *value; + gboolean has_match; value = nm_config_data_get_device_config(self, property, device, &has_match); if (!has_match) @@ -1499,13 +1517,34 @@ nm_config_data_get_device_config_boolean(const NMConfigData *self, return nm_config_parse_boolean(value, val_invalid); } -char * +gint64 +nm_config_data_get_device_config_int64(const NMConfigData *self, + const char * property, + NMDevice * device, + int base, + gint64 min, + gint64 max, + gint64 val_no_match, + gint64 val_invalid) +{ + const char *value; + gboolean has_match; + + value = nm_config_data_get_device_config(self, property, device, &has_match); + if (!has_match) { + errno = ENOENT; + return val_no_match; + } + return _nm_utils_ascii_str_to_int64(value, base, min, max, val_invalid); +} + +const char * nm_config_data_get_connection_default(const NMConfigData *self, const char * property, NMDevice * device) { const NMConfigDataPrivate *priv; - char * value = NULL; + const char * value; g_return_val_if_fail(self, NULL); g_return_val_if_fail(property && *property, NULL); @@ -1544,15 +1583,41 @@ nm_config_data_get_connection_default_int64(const NMConfigData *self, gint64 max, gint64 fallback) { - gs_free char *value = NULL; + const char *value; value = nm_config_data_get_connection_default(self, property, device); return _nm_utils_ascii_str_to_int64(value, 10, min, max, fallback); } +static const char * +_match_section_info_get_str(const MatchSectionInfo *m, GKeyFile *keyfile, const char *property) +{ + gssize idx; + const char *value; + + idx = nm_utils_named_value_list_find(m->lookup_idx, m->lookup_len, property, TRUE); + value = idx >= 0 ? m->lookup_idx[idx].value_str : NULL; + +#if NM_MORE_ASSERTS > 10 + { + gs_free char *value2 = g_key_file_get_string(keyfile, m->group_name, property, NULL); + + nm_assert(nm_streq0(value2, value)); + } +#endif + + return value; +} + static void -_get_connection_info_init(MatchSectionInfo *connection_info, GKeyFile *keyfile, char *group) +_match_section_info_init(MatchSectionInfo *connection_info, GKeyFile *keyfile, char *group) { + char ** keys = NULL; + gsize n_keys; + gsize i; + gsize j; + NMUtilsNamedValue *vals; + /* pass ownership of @group on... */ connection_info->group_name = group; @@ -1563,18 +1628,66 @@ _get_connection_info_init(MatchSectionInfo *connection_info, GKeyFile *keyfile, &connection_info->match_device.has); connection_info->stop_match = nm_config_keyfile_get_boolean(keyfile, group, NM_CONFIG_KEYFILE_KEY_STOP_MATCH, FALSE); + + keys = g_key_file_get_keys(keyfile, group, &n_keys, NULL); + nm_utils_strv_sort(keys, n_keys); + + vals = g_new(NMUtilsNamedValue, n_keys); + + for (i = 0, j = 0; i < n_keys; i++) { + gs_free char *key = g_steal_pointer(&keys[i]); + char * value; + + if (NM_IN_STRSET(key, NM_CONFIG_KEYFILE_KEY_STOP_MATCH, NM_CONFIG_KEYFILE_KEY_MATCH_DEVICE)) + continue; + + if (j > 0 && nm_streq(vals[j - 1].name, key)) + continue; + + value = g_key_file_get_string(keyfile, group, key, NULL); + if (!value) + continue; + + vals[j++] = (NMUtilsNamedValue){ + .name = g_steal_pointer(&key), + .value_str = value, + }; + } + + g_free(keys); + + if (n_keys != j) { + gs_free NMUtilsNamedValue *vals2 = vals; + + /* since this buffer will be kept around for a long time, + * get rid of the excess allocation. */ + vals = nm_memdup(vals2, sizeof(NMUtilsNamedValue) * j); + n_keys = j; + } + + if (n_keys == 0) + nm_clear_g_free(&vals); + + connection_info->lookup_idx = vals; + connection_info->lookup_len = n_keys; } static void _match_section_infos_free(MatchSectionInfo *match_section_infos) { - guint i; + MatchSectionInfo *m; + gsize i; if (!match_section_infos) return; - for (i = 0; match_section_infos[i].group_name; i++) { - g_free(match_section_infos[i].group_name); - g_slist_free_full(match_section_infos[i].match_device.spec, g_free); + for (m = match_section_infos; m->group_name; m++) { + g_free(m->group_name); + g_slist_free_full(m->match_device.spec, g_free); + for (i = 0; i < m->lookup_len; i++) { + g_free(m->lookup_idx[i].name_mutable); + g_free(m->lookup_idx[i].value_str_mutable); + } + g_free((gpointer) m->lookup_idx); } g_free(match_section_infos); } @@ -1619,11 +1732,11 @@ _match_section_infos_construct(GKeyFile *keyfile, const char *prefix) match_section_infos = g_new0(MatchSectionInfo, ngroups + 1 + (connection_tag ? 1 : 0)); for (i = 0; i < ngroups; i++) { /* pass ownership of @group on... */ - _get_connection_info_init(&match_section_infos[i], keyfile, groups[ngroups - i - 1]); + _match_section_info_init(&match_section_infos[i], keyfile, groups[ngroups - i - 1]); } if (connection_tag) { /* pass ownership of @connection_tag on... */ - _get_connection_info_init(&match_section_infos[i], keyfile, connection_tag); + _match_section_info_init(&match_section_infos[i], keyfile, connection_tag); } g_free(groups); @@ -1644,28 +1757,26 @@ 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_user, priv_new->keyfile_user, TRUE)) + if (!_nm_keyfile_equal(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)) + if (!_nm_keyfile_equal(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) + if (!nm_streq0(nm_config_data_get_config_main_file(old_data), + nm_config_data_get_config_main_file(new_data)) + || !nm_streq0(nm_config_data_get_config_description(old_data), + nm_config_data_get_config_description(new_data))) changes |= NM_CONFIG_CHANGE_CONFIG_FILES; if (nm_config_data_get_connectivity_enabled(old_data) != nm_config_data_get_connectivity_enabled(new_data) || nm_config_data_get_connectivity_interval(old_data) != nm_config_data_get_connectivity_interval(new_data) - || g_strcmp0(nm_config_data_get_connectivity_uri(old_data), - nm_config_data_get_connectivity_uri(new_data)) - || g_strcmp0(nm_config_data_get_connectivity_response(old_data), - nm_config_data_get_connectivity_response(new_data))) + || !nm_streq0(nm_config_data_get_connectivity_uri(old_data), + nm_config_data_get_connectivity_uri(new_data)) + || !nm_streq0(nm_config_data_get_connectivity_response(old_data), + nm_config_data_get_connectivity_response(new_data))) changes |= NM_CONFIG_CHANGE_CONNECTIVITY; if (nm_utils_g_slist_strlist_cmp(priv_old->no_auto_default.specs, @@ -1676,10 +1787,11 @@ nm_config_data_diff(NMConfigData *old_data, NMConfigData *new_data) != 0) changes |= NM_CONFIG_CHANGE_NO_AUTO_DEFAULT; - if (g_strcmp0(nm_config_data_get_dns_mode(old_data), nm_config_data_get_dns_mode(new_data))) + if (!nm_streq0(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))) + if (!nm_streq0(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)) @@ -1910,6 +2022,12 @@ constructed(GObject *object) if (!priv->global_dns) priv->global_dns = load_global_dns(priv->keyfile_intern, TRUE); + priv->iwd_config_path = + nm_strstrip(g_key_file_get_string(priv->keyfile, + NM_CONFIG_KEYFILE_GROUP_MAIN, + NM_CONFIG_KEYFILE_KEY_MAIN_IWD_CONFIG_PATH, + NULL)); + G_OBJECT_CLASS(nm_config_data_parent_class)->constructed(object); } @@ -1996,6 +2114,8 @@ finalize(GObject *gobject) nm_global_dns_config_free(priv->global_dns); + g_free(priv->iwd_config_path); + _match_section_infos_free(priv->connection_infos); _match_section_infos_free(priv->device_infos); diff --git a/src/core/nm-config-data.h b/src/core/nm-config-data.h index 07cffb43..42d69a8b 100644 --- a/src/core/nm-config-data.h +++ b/src/core/nm-config-data.h @@ -6,6 +6,8 @@ #ifndef NM_CONFIG_DATA_H #define NM_CONFIG_DATA_H +#include "libnm-platform/nmp-base.h" + /*****************************************************************************/ typedef enum { @@ -48,71 +50,71 @@ typedef enum { #define NM_CONFIG_DATA_NO_AUTO_DEFAULT "no-auto-default" #define NM_CONFIG_DATA_DNS_MODE "dns" -typedef enum { /*< flags >*/ - NM_CONFIG_GET_VALUE_NONE = 0, +typedef enum { + NM_CONFIG_GET_VALUE_NONE = 0, - /* use g_key_file_get_value() instead of g_key_file_get_string(). */ - NM_CONFIG_GET_VALUE_RAW = (1LL << 0), + /* use g_key_file_get_value() instead of g_key_file_get_string(). */ + NM_CONFIG_GET_VALUE_RAW = (1LL << 0), - /* strip whitespaces */ - NM_CONFIG_GET_VALUE_STRIP = (1LL << 1), + /* strip whitespaces */ + NM_CONFIG_GET_VALUE_STRIP = (1LL << 1), - /* if the returned string would be the empty word, return NULL. */ - NM_CONFIG_GET_VALUE_NO_EMPTY = (1LL << 2), + /* if the returned string would be the empty word, return NULL. */ + NM_CONFIG_GET_VALUE_NO_EMPTY = (1LL << 2), - /* special flag to read device spec. You want to use this before passing the + /* special flag to read device spec. You want to use this before passing the * value to nm_match_spec_split(). */ - NM_CONFIG_GET_VALUE_TYPE_SPEC = NM_CONFIG_GET_VALUE_RAW, + NM_CONFIG_GET_VALUE_TYPE_SPEC = NM_CONFIG_GET_VALUE_RAW, } NMConfigGetValueFlags; -typedef enum { /*< flags >*/ - NM_CONFIG_CHANGE_NONE = 0, +typedef enum { + NM_CONFIG_CHANGE_NONE = 0, - /************************************************************************** + /************************************************************************** * The external cause which triggered the reload/configuration-change *************************************************************************/ - NM_CONFIG_CHANGE_CAUSE_SIGHUP = (1L << 0), - NM_CONFIG_CHANGE_CAUSE_SIGUSR1 = (1L << 1), - NM_CONFIG_CHANGE_CAUSE_SIGUSR2 = (1L << 2), - NM_CONFIG_CHANGE_CAUSE_NO_AUTO_DEFAULT = (1L << 3), - NM_CONFIG_CHANGE_CAUSE_SET_VALUES = (1L << 4), - NM_CONFIG_CHANGE_CAUSE_CONF = (1L << 5), - NM_CONFIG_CHANGE_CAUSE_DNS_RC = (1L << 6), - NM_CONFIG_CHANGE_CAUSE_DNS_FULL = (1L << 7), + NM_CONFIG_CHANGE_CAUSE_SIGHUP = (1L << 0), + NM_CONFIG_CHANGE_CAUSE_SIGUSR1 = (1L << 1), + NM_CONFIG_CHANGE_CAUSE_SIGUSR2 = (1L << 2), + NM_CONFIG_CHANGE_CAUSE_NO_AUTO_DEFAULT = (1L << 3), + NM_CONFIG_CHANGE_CAUSE_SET_VALUES = (1L << 4), + NM_CONFIG_CHANGE_CAUSE_CONF = (1L << 5), + NM_CONFIG_CHANGE_CAUSE_DNS_RC = (1L << 6), + NM_CONFIG_CHANGE_CAUSE_DNS_FULL = (1L << 7), - NM_CONFIG_CHANGE_CAUSES = ((1L << 8) - 1), + NM_CONFIG_CHANGE_CAUSES = ((1L << 8) - 1), - /************************************************************************** + /************************************************************************** * Following flags describe which property of the configuration changed: *************************************************************************/ - /* main-file or config-description changed */ - NM_CONFIG_CHANGE_CONFIG_FILES = (1L << 10), + /* main-file or config-description changed */ + NM_CONFIG_CHANGE_CONFIG_FILES = (1L << 10), - /* any configuration on disk changed */ - NM_CONFIG_CHANGE_VALUES = (1L << 11), + /* any configuration on disk changed */ + NM_CONFIG_CHANGE_VALUES = (1L << 11), - /* any user configuration on disk changed (NetworkManager.conf) */ - NM_CONFIG_CHANGE_VALUES_USER = (1L << 12), + /* any user configuration on disk changed (NetworkManager.conf) */ + NM_CONFIG_CHANGE_VALUES_USER = (1L << 12), - /* any internal configuration on disk changed (NetworkManager-intern.conf) */ - NM_CONFIG_CHANGE_VALUES_INTERN = (1L << 13), + /* any internal configuration on disk changed (NetworkManager-intern.conf) */ + NM_CONFIG_CHANGE_VALUES_INTERN = (1L << 13), - /* configuration regarding connectivity changed */ - NM_CONFIG_CHANGE_CONNECTIVITY = (1L << 14), + /* configuration regarding connectivity changed */ + NM_CONFIG_CHANGE_CONNECTIVITY = (1L << 14), - /* configuration regarding no-auto-default changed */ - NM_CONFIG_CHANGE_NO_AUTO_DEFAULT = (1L << 15), + /* configuration regarding no-auto-default changed */ + NM_CONFIG_CHANGE_NO_AUTO_DEFAULT = (1L << 15), - /* configuration regarding dns-mode changed */ - NM_CONFIG_CHANGE_DNS_MODE = (1L << 16), + /* configuration regarding dns-mode changed */ + NM_CONFIG_CHANGE_DNS_MODE = (1L << 16), - /* configuration regarding rc-manager changed */ - NM_CONFIG_CHANGE_RC_MANAGER = (1L << 17), + /* configuration regarding rc-manager changed */ + NM_CONFIG_CHANGE_RC_MANAGER = (1L << 17), - /* configuration regarding global dns-config changed */ - NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG = (1L << 18), + /* configuration regarding global dns-config changed */ + NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG = (1L << 18), } NMConfigChangeFlags; @@ -188,6 +190,8 @@ int nm_config_data_get_sriov_num_vfs(const NMConfigData *self, NMDevice *de NMGlobalDnsConfig *nm_config_data_get_global_dns_config(const NMConfigData *self); +const char *nm_config_data_get_iwd_config_path(const NMConfigData *self); + extern const char *__start_connection_defaults[]; extern const char *__stop_connection_defaults[]; @@ -203,9 +207,9 @@ extern const char *__stop_connection_defaults[]; name; \ }) -char *nm_config_data_get_connection_default(const NMConfigData *self, - const char * property, - NMDevice * device); +const char *nm_config_data_get_connection_default(const NMConfigData *self, + const char * property, + NMDevice * device); gint64 nm_config_data_get_connection_default_int64(const NMConfigData *self, const char * property, @@ -214,22 +218,30 @@ gint64 nm_config_data_get_connection_default_int64(const NMConfigData *self, gint64 max, gint64 fallback); -char *nm_config_data_get_device_config(const NMConfigData *self, - const char * property, - NMDevice * device, - gboolean * has_match); +const char *nm_config_data_get_device_config(const NMConfigData *self, + const char * property, + NMDevice * device, + gboolean * has_match); -char *nm_config_data_get_device_config_by_pllink(const NMConfigData * self, - const char * property, - const NMPlatformLink *pllink, - const char * match_device_type, - gboolean * has_match); +const char *nm_config_data_get_device_config_by_pllink(const NMConfigData * self, + const char * property, + const NMPlatformLink *pllink, + const char * match_device_type, + gboolean * has_match); gboolean nm_config_data_get_device_config_boolean(const NMConfigData *self, const char * property, NMDevice * device, int val_no_match, int val_invalid); +gint64 nm_config_data_get_device_config_int64(const NMConfigData *self, + const char * property, + NMDevice * device, + int base, + gint64 min, + gint64 max, + gint64 val_no_match, + gint64 val_invalid); char ** nm_config_data_get_groups(const NMConfigData *self); char ** nm_config_data_get_keys(const NMConfigData *self, const char *group); diff --git a/src/core/nm-config.c b/src/core/nm-config.c index 55323919..fdc450a0 100644 --- a/src/core/nm-config.c +++ b/src/core/nm-config.c @@ -13,9 +13,9 @@ #include "nm-utils.h" #include "devices/nm-device.h" #include "NetworkManagerUtils.h" -#include "nm-core-internal.h" -#include "nm-keyfile-internal.h" -#include "nm-keyfile-utils.h" +#include "libnm-core-intern/nm-core-internal.h" +#include "libnm-core-intern/nm-keyfile-internal.h" +#include "libnm-core-intern/nm-keyfile-utils.h" #define DEFAULT_CONFIG_MAIN_FILE NMCONFDIR "/NetworkManager.conf" #define DEFAULT_CONFIG_DIR NMCONFDIR "/conf.d" @@ -433,13 +433,7 @@ nm_config_set_no_auto_default_for_device(NMConfig *self, NMDevice *device) len = NM_PTRARRAY_LEN(no_auto_default_current); - idx = nm_utils_ptrarray_find_binary_search((gconstpointer *) no_auto_default_current, - len, - spec, - nm_strcmp_with_data, - NULL, - NULL, - NULL); + idx = nm_utils_strv_find_binary_search(no_auto_default_current, len, spec); if (idx >= 0) { /* @spec is already blocked. We don't have to update our in-memory representation. * Maybe we should write to no_auto_default_file anew, but let's save that too. */ @@ -842,8 +836,10 @@ static const ConfigGroup config_groups[] = { NM_CONFIG_KEYFILE_KEY_MAIN_DEBUG, NM_CONFIG_KEYFILE_KEY_MAIN_DHCP, NM_CONFIG_KEYFILE_KEY_MAIN_DNS, + NM_CONFIG_KEYFILE_KEY_MAIN_FIREWALL_BACKEND, NM_CONFIG_KEYFILE_KEY_MAIN_HOSTNAME_MODE, NM_CONFIG_KEYFILE_KEY_MAIN_IGNORE_CARRIER, + NM_CONFIG_KEYFILE_KEY_MAIN_IWD_CONFIG_PATH, NM_CONFIG_KEYFILE_KEY_MAIN_MONITOR_CONNECTION_FILES, NM_CONFIG_KEYFILE_KEY_MAIN_NO_AUTO_DEFAULT, NM_CONFIG_KEYFILE_KEY_MAIN_PLUGINS, @@ -2115,7 +2111,7 @@ nm_config_set_values(NMConfig *self, ""); } - if (!_nm_keyfile_equals(keyfile_intern_current, keyfile_new, TRUE)) + if (!_nm_keyfile_equal(keyfile_intern_current, keyfile_new, TRUE)) new_data = nm_config_data_new_update_keyfile_intern(priv->config_data, keyfile_new); _LOGD("set values(): %s", new_data ? "has changes" : "no changes"); @@ -3149,7 +3145,7 @@ nm_config_class_init(NMConfigClass *config_class) NM_TYPE_CONFIG_DATA); G_STATIC_ASSERT_EXPR(sizeof(guint) == sizeof(NMConfigChangeFlags)); - G_STATIC_ASSERT_EXPR(((gint64)((NMConfigChangeFlags) -1)) > ((gint64) 0)); + G_STATIC_ASSERT_EXPR(((gint64) ((NMConfigChangeFlags) -1)) > ((gint64) 0)); } static void diff --git a/src/core/nm-config.h b/src/core/nm-config.h index 6f3f514c..7f1c0c4c 100644 --- a/src/core/nm-config.h +++ b/src/core/nm-config.h @@ -9,6 +9,8 @@ #include "nm-config-data.h" +#include "libnm-base/nm-config-base.h" + #define NM_TYPE_CONFIG (nm_config_get_type()) #define NM_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_CONFIG, NMConfig)) #define NM_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_CONFIG, NMConfigClass)) @@ -26,84 +28,6 @@ #define NM_CONFIG_DEFAULT_CONNECTIVITY_INTERVAL 300 #define NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE "NetworkManager is online" /* NOT LOCALIZED */ -#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_DEVICE "device" -#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_KEYFILE "keyfile" -#define NM_CONFIG_KEYFILE_GROUP_IFUPDOWN "ifupdown" -#define NM_CONFIG_KEYFILE_GROUP_GLOBAL_DNS "global-dns" -#define NM_CONFIG_KEYFILE_GROUP_CONFIG ".config" - -#define NM_CONFIG_KEYFILE_KEY_MAIN_ASSUME_IPV6LL_ONLY "assume-ipv6ll-only" -#define NM_CONFIG_KEYFILE_KEY_MAIN_AUTH_POLKIT "auth-polkit" -#define NM_CONFIG_KEYFILE_KEY_MAIN_AUTOCONNECT_RETRIES_DEFAULT "autoconnect-retries-default" -#define NM_CONFIG_KEYFILE_KEY_MAIN_CONFIGURE_AND_QUIT "configure-and-quit" -#define NM_CONFIG_KEYFILE_KEY_MAIN_DEBUG "debug" -#define NM_CONFIG_KEYFILE_KEY_MAIN_DHCP "dhcp" -#define NM_CONFIG_KEYFILE_KEY_MAIN_DNS "dns" -#define NM_CONFIG_KEYFILE_KEY_MAIN_HOSTNAME_MODE "hostname-mode" -#define NM_CONFIG_KEYFILE_KEY_MAIN_IGNORE_CARRIER "ignore-carrier" -#define NM_CONFIG_KEYFILE_KEY_MAIN_MONITOR_CONNECTION_FILES "monitor-connection-files" -#define NM_CONFIG_KEYFILE_KEY_MAIN_NO_AUTO_DEFAULT "no-auto-default" -#define NM_CONFIG_KEYFILE_KEY_MAIN_PLUGINS "plugins" -#define NM_CONFIG_KEYFILE_KEY_MAIN_RC_MANAGER "rc-manager" -#define NM_CONFIG_KEYFILE_KEY_MAIN_SLAVES_ORDER "slaves-order" -#define NM_CONFIG_KEYFILE_KEY_MAIN_SYSTEMD_RESOLVED "systemd-resolved" - -#define NM_CONFIG_KEYFILE_KEY_LOGGING_AUDIT "audit" -#define NM_CONFIG_KEYFILE_KEY_LOGGING_BACKEND "backend" -#define NM_CONFIG_KEYFILE_KEY_LOGGING_DOMAINS "domains" -#define NM_CONFIG_KEYFILE_KEY_LOGGING_LEVEL "level" - -#define NM_CONFIG_KEYFILE_KEY_CONNECTIVITY_ENABLED "enabled" -#define NM_CONFIG_KEYFILE_KEY_CONNECTIVITY_INTERVAL "interval" -#define NM_CONFIG_KEYFILE_KEY_CONNECTIVITY_RESPONSE "response" -#define NM_CONFIG_KEYFILE_KEY_CONNECTIVITY_URI "uri" - -#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_IFUPDOWN_MANAGED "managed" - -#define NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_SEARCHES "searches" -#define NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_OPTIONS "options" - -#define NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_DOMAIN_SERVERS "servers" -#define NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_DOMAIN_OPTIONS "options" - -#define NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED "managed" -#define NM_CONFIG_KEYFILE_KEY_DEVICE_IGNORE_CARRIER "ignore-carrier" -#define NM_CONFIG_KEYFILE_KEY_DEVICE_SRIOV_NUM_VFS "sriov-num-vfs" -#define NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_BACKEND "wifi.backend" -#define NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_SCAN_RAND_MAC_ADDRESS "wifi.scan-rand-mac-address" -#define NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_SCAN_GENERATE_MAC_ADDRESS_MASK \ - "wifi.scan-generate-mac-address-mask" -#define NM_CONFIG_KEYFILE_KEY_DEVICE_CARRIER_WAIT_TIMEOUT "carrier-wait-timeout" -#define NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_IWD_AUTOCONNECT "wifi.iwd.autoconnect" - -#define NM_CONFIG_KEYFILE_KEY_MATCH_DEVICE "match-device" -#define NM_CONFIG_KEYFILE_KEY_STOP_MATCH "stop-match" - -#define NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS ".was" /* check-config-options skip */ -#define NM_CONFIG_KEYFILE_KEY_CONFIG_ENABLE "enable" /* check-config-options skip */ - -#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; typedef enum { diff --git a/src/core/nm-connectivity.c b/src/core/nm-connectivity.c index f847c8f4..85d41b49 100644 --- a/src/core/nm-connectivity.c +++ b/src/core/nm-connectivity.c @@ -16,7 +16,7 @@ #include #include "c-list/src/c-list.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-config.h" #include "NetworkManagerUtils.h" #include "nm-dbus-manager.h" @@ -572,7 +572,7 @@ easy_write_cb(void *buffer, size_t size, size_t nmemb, void *userdata) * Continue receiving... */ cb_data->concheck.response_good_cnt += len; - if (cb_data->concheck.response_good_cnt > (gsize)(100 * 1024)) { + if (cb_data->concheck.response_good_cnt > (gsize) (100 * 1024)) { /* we expect an empty response. We accept either * 1) status code 204 and any response * 2) status code 200 and an empty response. @@ -764,7 +764,7 @@ resolve_cb(GObject *object, GAsyncResult *res, gpointer user_data) } #endif -#define SD_RESOLVED_DNS ((guint64)(1LL << 0)) +#define SD_RESOLVED_DNS ((guint64) (1LL << 0)) static NMConnectivityState check_platform_config(NMConnectivity *self, @@ -904,7 +904,7 @@ nm_connectivity_check_start(NMConnectivity * self, * This is relatively cumbersome to avoid, because we would have to go through * NMDnsSystemdResolved trying to asynchronously start the service, to ensure there * is only one attempt to start the service. */ - has_systemd_resolved = nm_dns_manager_has_systemd_resolved(nm_dns_manager_get()); + has_systemd_resolved = !!nm_dns_manager_get_systemd_resolved(nm_dns_manager_get()); if (has_systemd_resolved) { GDBusConnection *dbus_connection; diff --git a/src/core/nm-connectivity.h b/src/core/nm-connectivity.h index c67668ce..0985df97 100644 --- a/src/core/nm-connectivity.h +++ b/src/core/nm-connectivity.h @@ -8,6 +8,7 @@ #define __NETWORKMANAGER_CONNECTIVITY_H__ #include "nm-dbus-interface.h" +#include "libnm-platform/nmp-base.h" /*****************************************************************************/ diff --git a/src/core/nm-core-utils.c b/src/core/nm-core-utils.c index 9075c30d..41d22565 100644 --- a/src/core/nm-core-utils.c +++ b/src/core/nm-core-utils.c @@ -22,13 +22,16 @@ #include #include -#include "nm-std-aux/unaligned.h" -#include "nm-glib-aux/nm-random-utils.h" -#include "nm-glib-aux/nm-io-utils.h" -#include "nm-glib-aux/nm-secret-utils.h" -#include "nm-glib-aux/nm-time-utils.h" +#include "libnm-glib-aux/nm-uuid.h" +#include "libnm-platform/nmp-base.h" +#include "libnm-std-aux/unaligned.h" +#include "libnm-glib-aux/nm-random-utils.h" +#include "libnm-glib-aux/nm-io-utils.h" +#include "libnm-glib-aux/nm-secret-utils.h" +#include "libnm-glib-aux/nm-time-utils.h" +#include "libnm-glib-aux/nm-str-buf.h" #include "nm-utils.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-setting-connection.h" #include "nm-setting-ip4-config.h" #include "nm-setting-ip6-config.h" @@ -156,37 +159,6 @@ _nm_singleton_instance_register_destruction(GObject *instance) /*****************************************************************************/ -static double -_exp10(guint16 ex) -{ - double v; - - if (ex == 0) - return 1.0; - - v = _exp10(ex / 2); - v = v * v; - if (ex % 2) - v *= 10; - return v; -} - -/* - * nm_utils_exp10: - * @ex: the exponent - * - * Returns: 10^ex, or pow(10, ex), or exp10(ex). - */ -double -nm_utils_exp10(gint16 ex) -{ - if (ex >= 0) - return _exp10(ex); - return 1.0 / _exp10(-((gint32) ex)); -} - -/*****************************************************************************/ - gboolean nm_ether_addr_is_valid(const NMEtherAddr *addr) { @@ -304,85 +276,6 @@ nm_utils_array_remove_at_indexes(GArray *array, const guint *indexes_to_delete, g_array_set_size(array, res_length); } -static const char * -_trunk_first_line(char *str) -{ - char *s; - - s = strchr(str, '\n'); - if (s) - s[0] = '\0'; - return str; -} - -int -nm_utils_modprobe(GError **error, gboolean suppress_error_logging, const char *arg1, ...) -{ - gs_unref_ptrarray GPtrArray *argv = NULL; - int exit_status; - gs_free char * _log_str = NULL; -#define ARGV_TO_STR(argv) \ - (_log_str ? _log_str : (_log_str = g_strjoinv(" ", (char **) argv->pdata))) - GError * local = NULL; - va_list ap; - NMLogLevel llevel = suppress_error_logging ? LOGL_DEBUG : LOGL_ERR; - gs_free char *std_out = NULL, *std_err = NULL; - - g_return_val_if_fail(!error || !*error, -1); - g_return_val_if_fail(arg1, -1); - - /* construct the argument list */ - argv = g_ptr_array_sized_new(4); - g_ptr_array_add(argv, "/sbin/modprobe"); - g_ptr_array_add(argv, "--use-blacklist"); - g_ptr_array_add(argv, (char *) arg1); - - va_start(ap, arg1); - while ((arg1 = va_arg(ap, const char *))) - g_ptr_array_add(argv, (char *) arg1); - va_end(ap); - - g_ptr_array_add(argv, NULL); - - nm_log_dbg(LOGD_CORE, "modprobe: '%s'", ARGV_TO_STR(argv)); - if (!g_spawn_sync(NULL, - (char **) argv->pdata, - NULL, - 0, - NULL, - NULL, - &std_out, - &std_err, - &exit_status, - &local)) { - nm_log(llevel, - LOGD_CORE, - NULL, - NULL, - "modprobe: '%s' failed: %s", - ARGV_TO_STR(argv), - local->message); - g_propagate_error(error, local); - return -1; - } else if (exit_status != 0) { - nm_log(llevel, - LOGD_CORE, - NULL, - NULL, - "modprobe: '%s' exited with error %d%s%s%s%s%s%s", - ARGV_TO_STR(argv), - exit_status, - std_out && *std_out ? " (" : "", - std_out && *std_out ? _trunk_first_line(std_out) : "", - std_out && *std_out ? ")" : "", - std_err && *std_err ? " (" : "", - std_err && *std_err ? _trunk_first_line(std_err) : "", - std_err && *std_err ? ")" : ""); - } - - return exit_status; -} - /*****************************************************************************/ typedef struct { @@ -693,9 +586,10 @@ static gulong _sleep_duration_convert_ms_to_us(guint32 sleep_duration_msec) { if (sleep_duration_msec > 0) { - guint64 x = (gint64) sleep_duration_msec * (guint64) 1000L; + guint64 x = ((guint64) sleep_duration_msec) * 1000UL; - return x < G_MAXULONG ? (gulong) x : G_MAXULONG; + nm_assert(x < G_MAXULONG); + return x; } return G_USEC_PER_SEC / 20; } @@ -1269,7 +1163,7 @@ typedef struct { const char *value; gboolean is_parsed; guint len; - guint8 bin[NM_UTILS_HWADDR_LEN_MAX]; + guint8 bin[_NM_UTILS_HWADDR_LEN_MAX]; } hwaddr; struct { const char *value; @@ -1956,7 +1850,8 @@ nm_wildcard_match_check(const char *str, const char *const *patterns, guint num_ _pattern_parse(patterns[i], &p, &is_inverted, &is_mandatory); - match = (fnmatch(p, str, 0) == 0); + match = (fnmatch(p, str ?: "", 0) == 0); + if (is_inverted) match = !match; @@ -2051,65 +1946,6 @@ nm_utils_kernel_cmdline_match_check(const char *const *proc_cmdline, /*****************************************************************************/ -char * -nm_utils_new_vlan_name(const char *parent_iface, guint32 vlan_id) -{ - guint id_len; - gsize parent_len; - char *ifname; - - g_return_val_if_fail(parent_iface && *parent_iface, NULL); - - if (vlan_id < 10) - id_len = 2; - else if (vlan_id < 100) - id_len = 3; - else if (vlan_id < 1000) - id_len = 4; - else { - g_return_val_if_fail(vlan_id < 4095, NULL); - id_len = 5; - } - - ifname = g_new(char, IFNAMSIZ); - - parent_len = strlen(parent_iface); - parent_len = MIN(parent_len, IFNAMSIZ - 1 - id_len); - memcpy(ifname, parent_iface, parent_len); - g_snprintf(&ifname[parent_len], IFNAMSIZ - parent_len, ".%u", vlan_id); - - return ifname; -} - -/* nm_utils_new_infiniband_name: - * @name: the output-buffer where the value will be written. Must be - * not %NULL and point to a string buffer of at least IFNAMSIZ bytes. - * @parent_name: the parent interface name - * @p_key: the partition key. - * - * Returns: the infiniband name will be written to @name and @name - * is returned. - */ -const char * -nm_utils_new_infiniband_name(char *name, const char *parent_name, int p_key) -{ - g_return_val_if_fail(name, NULL); - g_return_val_if_fail(parent_name && parent_name[0], NULL); - g_return_val_if_fail(strlen(parent_name) < IFNAMSIZ, NULL); - - /* technically, p_key of 0x0000 and 0x8000 is not allowed either. But we don't - * want to assert against that in nm_utils_new_infiniband_name(). So be more - * resilient here, and accept those. */ - g_return_val_if_fail(p_key >= 0 && p_key <= 0xffff, NULL); - - /* If parent+suffix is too long, kernel would just truncate - * the name. We do the same. See ipoib_vlan_add(). */ - g_snprintf(name, IFNAMSIZ, "%s.%04x", parent_name, p_key); - return name; -} - -/*****************************************************************************/ - /** * nm_utils_cmp_connection_by_autoconnect_priority: * @a: @@ -2538,134 +2374,6 @@ out: g_array_free(sorted_hashes, TRUE); } -#define IPV6_PROPERTY_DIR "/proc/sys/net/ipv6/conf/" -#define IPV4_PROPERTY_DIR "/proc/sys/net/ipv4/conf/" -G_STATIC_ASSERT(sizeof(IPV4_PROPERTY_DIR) == sizeof(IPV6_PROPERTY_DIR)); -G_STATIC_ASSERT(NM_STRLEN(IPV6_PROPERTY_DIR) + IFNAMSIZ + 60 - == NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE); - -/** - * nm_utils_sysctl_ip_conf_path: - * @addr_family: either AF_INET or AF_INET6. - * @buf: the output buffer where to write the path. It - * must be at least NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE bytes - * long. - * @ifname: an interface name - * @property: a property name - * - * Returns: the path to IPv6 property @property on @ifname. Note that - * this returns the input argument @buf. - */ -const char * -nm_utils_sysctl_ip_conf_path(int addr_family, char *buf, const char *ifname, const char *property) -{ - int len; - - nm_assert(buf); - nm_assert_addr_family(addr_family); - - g_assert(nm_utils_ifname_valid_kernel(ifname, NULL)); - property = NM_ASSERT_VALID_PATH_COMPONENT(property); - - len = g_snprintf(buf, - NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE, - "%s%s/%s", - addr_family == AF_INET6 ? IPV6_PROPERTY_DIR : IPV4_PROPERTY_DIR, - ifname, - property); - g_assert(len < NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE - 1); - return buf; -} - -gboolean -nm_utils_sysctl_ip_conf_is_path(int addr_family, - const char *path, - const char *ifname, - const char *property) -{ - g_return_val_if_fail(path, FALSE); - NM_ASSERT_VALID_PATH_COMPONENT(property); - g_assert(!ifname || nm_utils_ifname_valid_kernel(ifname, NULL)); - - if (addr_family == AF_INET) { - if (!g_str_has_prefix(path, IPV4_PROPERTY_DIR)) - return FALSE; - path += NM_STRLEN(IPV4_PROPERTY_DIR); - } else if (addr_family == AF_INET6) { - if (!g_str_has_prefix(path, IPV6_PROPERTY_DIR)) - return FALSE; - path += NM_STRLEN(IPV6_PROPERTY_DIR); - } else - g_return_val_if_reached(FALSE); - - if (ifname) { - if (!g_str_has_prefix(path, ifname)) - return FALSE; - path += strlen(ifname); - if (path[0] != '/') - return FALSE; - path++; - } else { - const char *slash; - char buf[IFNAMSIZ]; - gsize l; - - slash = strchr(path, '/'); - if (!slash) - return FALSE; - l = slash - path; - if (l >= IFNAMSIZ) - return FALSE; - memcpy(buf, path, l); - buf[l] = '\0'; - if (!nm_utils_ifname_valid_kernel(buf, NULL)) - return FALSE; - path = slash + 1; - } - - if (!nm_streq(path, property)) - return FALSE; - - return TRUE; -} - -gboolean -nm_utils_is_valid_path_component(const char *name) -{ - const char *n; - - if (name == NULL || name[0] == '\0') - return FALSE; - - if (name[0] == '.') { - if (name[1] == '\0') - return FALSE; - if (name[1] == '.' && name[2] == '\0') - return FALSE; - } - n = name; - do { - if (*n == '/') - return FALSE; - } while (*(++n) != '\0'); - - return TRUE; -} - -const char * -NM_ASSERT_VALID_PATH_COMPONENT(const char *name) -{ - if (G_LIKELY(nm_utils_is_valid_path_component(name))) - return name; - - nm_log_err(LOGD_CORE, - "Failed asserting path component: %s%s%s", - NM_PRINT_FMT_QUOTED(name, "\"", name, "\"", "(null)")); - g_error("FATAL: Failed asserting path component: %s%s%s", - NM_PRINT_FMT_QUOTED(name, "\"", name, "\"", "(null)")); - g_assert_not_reached(); -} - /*****************************************************************************/ typedef struct { @@ -2697,7 +2405,7 @@ _uuid_data_init(UuidData *uuid_data, gboolean packed, gboolean is_fake, const NM nm_utils_bin2hexstr_full(uuid, sizeof(*uuid), '\0', FALSE, uuid_data->str); } else { G_STATIC_ASSERT_EXPR(sizeof(uuid_data->str) >= 37); - _nm_utils_uuid_unparse(uuid, uuid_data->str); + nm_uuid_unparse(uuid, uuid_data->str); } return uuid_data; } @@ -2750,7 +2458,7 @@ again: (guint8 *) &uuid, sizeof(uuid), NULL)) { - if (!nm_utils_uuid_is_null(&uuid)) { + if (!nm_uuid_is_null(&uuid)) { /* an all-zero machine-id is not valid. */ is_fake = FALSE; } @@ -2795,11 +2503,11 @@ again: /* the fake machine-id is based on secret-key/boot-id, but we hash it * again, so that they are not literally the same. */ - nm_utils_uuid_generate_from_string_bin(&uuid, - (const char *) seed_bin, - seed_len, - NM_UTILS_UUID_TYPE_VERSION5, - (gpointer) hash_seed); + nm_uuid_generate_from_string(&uuid, + (const char *) seed_bin, + seed_len, + NM_UUID_TYPE_VERSION5, + (gpointer) hash_seed); } if (!g_once_init_enter(&lock)) @@ -2884,7 +2592,7 @@ _host_id_read_timestamp(gboolean use_secret_key_file, now = time(NULL); *out_timestamp_ns = NM_MAX((gint64) 1, - (now * NM_UTILS_NSEC_PER_SEC) - ((gint64)(v % ((guint64)(EPOCH_TWO_YEARS))))); + (now * NM_UTILS_NSEC_PER_SEC) - ((gint64) (v % ((guint64) (EPOCH_TWO_YEARS))))); return FALSE; } @@ -3027,6 +2735,7 @@ _host_id_read(guint8 **out_host_id, gsize *out_host_id_len) len, 0600, NULL, + NULL, &error)) { nm_log_warn( LOGD_CORE, @@ -3148,10 +2857,10 @@ again: NULL, NULL, NULL); - if (!contents || !_nm_utils_uuid_parse(nm_strstrip(contents), &uuid)) { + if (!contents || !nm_uuid_parse(nm_strstrip(contents), &uuid)) { /* generate a random UUID instead. */ is_fake = TRUE; - _nm_utils_uuid_generate_random(&uuid); + nm_uuid_generate_random(&uuid); } if (!g_once_init_enter(&lock)) @@ -3407,89 +3116,6 @@ nm_utils_get_ipv6_interface_identifier(NMLinkType link_type, /*****************************************************************************/ -/** - * nm_utils_ipv6_addr_set_interface_identifier: - * @addr: output token encoded as %in6_addr - * @iid: %NMUtilsIPv6IfaceId interface identifier - * - * Converts the %NMUtilsIPv6IfaceId to an %in6_addr (suitable for use - * with Linux platform). This only copies the lower 8 bytes, ignoring - * the /64 network prefix which is expected to be all-zero for a valid - * token. - */ -void -nm_utils_ipv6_addr_set_interface_identifier(struct in6_addr *addr, const NMUtilsIPv6IfaceId iid) -{ - memcpy(addr->s6_addr + 8, &iid.id_u8, 8); -} - -/** - * nm_utils_ipv6_interface_identifier_get_from_addr: - * @iid: output %NMUtilsIPv6IfaceId interface identifier set from the token - * @addr: token encoded as %in6_addr - * - * Converts the %in6_addr encoded token (as used by Linux platform) to - * the interface identifier. - */ -void -nm_utils_ipv6_interface_identifier_get_from_addr(NMUtilsIPv6IfaceId * iid, - const struct in6_addr *addr) -{ - memcpy(iid, addr->s6_addr + 8, 8); -} - -/** - * nm_utils_ipv6_interface_identifier_get_from_token: - * @iid: output %NMUtilsIPv6IfaceId interface identifier set from the token - * @token: token encoded as string - * - * Converts the %in6_addr encoded token (as used in ip6 settings) to - * the interface identifier. - * - * Returns: %TRUE if the @token is a valid token, %FALSE otherwise - */ -gboolean -nm_utils_ipv6_interface_identifier_get_from_token(NMUtilsIPv6IfaceId *iid, const char *token) -{ - struct in6_addr i6_token; - - g_return_val_if_fail(token, FALSE); - - if (!inet_pton(AF_INET6, token, &i6_token)) - return FALSE; - - if (!_nm_utils_inet6_is_token(&i6_token)) - return FALSE; - - nm_utils_ipv6_interface_identifier_get_from_addr(iid, &i6_token); - return TRUE; -} - -/** - * nm_utils_inet6_interface_identifier_to_token: - * @iid: %NMUtilsIPv6IfaceId interface identifier - * @buf: the destination buffer of at least %NM_UTILS_INET_ADDRSTRLEN - * bytes. - * - * Converts the interface identifier to a string token. - * - * Returns: the input buffer filled with the id as string. - */ -const char * -nm_utils_inet6_interface_identifier_to_token(NMUtilsIPv6IfaceId iid, - char buf[static INET6_ADDRSTRLEN]) -{ - struct in6_addr i6_token = {.s6_addr = { - 0, - }}; - - nm_assert(buf); - nm_utils_ipv6_addr_set_interface_identifier(&i6_token, iid); - return _nm_utils_inet6_ntop(&i6_token, buf); -} - -/*****************************************************************************/ - char * nm_utils_stable_id_random(void) { @@ -4269,89 +3895,6 @@ nm_utils_g_value_set_strv(GValue *value, GPtrArray *strings) /*****************************************************************************/ -/** - * Takes a pair @timestamp and @duration, and returns the remaining duration based - * on the new timestamp @now. - */ -guint32 -nm_utils_lifetime_rebase_relative_time_on_now(guint32 timestamp, guint32 duration, gint32 now) -{ - gint64 t; - - nm_assert(now >= 0); - - if (duration == NM_PLATFORM_LIFETIME_PERMANENT) - return NM_PLATFORM_LIFETIME_PERMANENT; - - if (timestamp == 0) { - /* if the @timestamp is zero, assume it was just left unset and that the relative - * @duration starts counting from @now. This is convenient to construct an address - * and print it in nm_platform_ip4_address_to_string(). - * - * In general it does not make sense to set the @duration without anchoring at - * @timestamp because you don't know the absolute expiration time when looking - * at the address at a later moment. */ - timestamp = now; - } - - /* For timestamp > now, just accept it and calculate the expected(?) result. */ - t = (gint64) timestamp + (gint64) duration - (gint64) now; - - if (t <= 0) - return 0; - if (t >= NM_PLATFORM_LIFETIME_PERMANENT) - return NM_PLATFORM_LIFETIME_PERMANENT - 1; - return t; -} - -guint32 -nm_utils_lifetime_get(guint32 timestamp, - guint32 lifetime, - guint32 preferred, - gint32 now, - guint32 *out_preferred) -{ - guint32 t_lifetime, t_preferred; - - nm_assert(now >= 0); - - if (timestamp == 0 && lifetime == 0) { - /* We treat lifetime==0 && timestamp==0 addresses as permanent addresses to allow easy - * creation of such addresses (without requiring to set the lifetime fields to - * NM_PLATFORM_LIFETIME_PERMANENT). The real lifetime==0 addresses (E.g. DHCP6 telling us - * to drop an address will have timestamp set. - */ - NM_SET_OUT(out_preferred, NM_PLATFORM_LIFETIME_PERMANENT); - g_return_val_if_fail(preferred == 0, NM_PLATFORM_LIFETIME_PERMANENT); - return NM_PLATFORM_LIFETIME_PERMANENT; - } - - if (now <= 0) - now = nm_utils_get_monotonic_timestamp_sec(); - - t_lifetime = nm_utils_lifetime_rebase_relative_time_on_now(timestamp, lifetime, now); - if (!t_lifetime) { - NM_SET_OUT(out_preferred, 0); - return 0; - } - - t_preferred = nm_utils_lifetime_rebase_relative_time_on_now(timestamp, preferred, now); - - NM_SET_OUT(out_preferred, MIN(t_preferred, t_lifetime)); - - /* Assert that non-permanent addresses have a (positive) @timestamp. nm_utils_lifetime_rebase_relative_time_on_now() - * treats addresses with timestamp 0 as *now*. Addresses passed to _address_get_lifetime() always - * should have a valid @timestamp, otherwise on every re-sync, their lifetime will be extended anew. - */ - g_return_val_if_fail(timestamp != 0 - || (lifetime == NM_PLATFORM_LIFETIME_PERMANENT - && preferred == NM_PLATFORM_LIFETIME_PERMANENT), - t_lifetime); - g_return_val_if_fail(t_preferred <= t_lifetime, t_lifetime); - - return t_lifetime; -} - const char * nm_utils_dnsmasq_status_to_string(int status, char *dest, gsize size) { @@ -5065,9 +4608,12 @@ nm_wifi_utils_parse_ies(const guint8 *bytes, case WLAN_EID_VENDOR_SPECIFIC: if (len == 8 && bytes[0] == 0x00 /* OUI: Microsoft */ && bytes[1] == 0x50 && bytes[2] == 0xf2 - && bytes[3] == 0x11) /* OUI type: Network cost */ - NM_SET_OUT(out_metered, (bytes[7] > 1)); /* Cost level > 1 */ - if (elem_len >= 10 && bytes[0] == 0x50 /* OUI: WiFi Alliance */ + && bytes[3] == 0x11) /* OUI type: Network cost */ + { + /* https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nct/ */ + NM_SET_OUT(out_metered, (bytes[4] > 1)); /* Cost level > 1 */ + } + if (elem_len >= 10 && bytes[0] == 0x50 /* OUI: WiFi Alliance */ && bytes[1] == 0x6f && bytes[2] == 0x9a && bytes[3] == 0x1c) /* OUI type: OWE Transition Mode */ NM_SET_OUT(out_owe_transition_mode, TRUE); @@ -5102,16 +4648,329 @@ nm_wifi_utils_level_to_quality(int val) /*****************************************************************************/ -NM_UTILS_ENUM2STR_DEFINE(nm_icmpv6_router_pref_to_string, - NMIcmpv6RouterPref, - NM_UTILS_ENUM2STR(NM_ICMPV6_ROUTER_PREF_LOW, "low"), - NM_UTILS_ENUM2STR(NM_ICMPV6_ROUTER_PREF_MEDIUM, "medium"), - NM_UTILS_ENUM2STR(NM_ICMPV6_ROUTER_PREF_HIGH, "high"), - NM_UTILS_ENUM2STR(NM_ICMPV6_ROUTER_PREF_INVALID, "invalid"), ); - NM_UTILS_LOOKUP_STR_DEFINE(nm_activation_type_to_string, NMActivationType, NM_UTILS_LOOKUP_DEFAULT_WARN("(unknown)"), NM_UTILS_LOOKUP_STR_ITEM(NM_ACTIVATION_TYPE_MANAGED, "managed"), NM_UTILS_LOOKUP_STR_ITEM(NM_ACTIVATION_TYPE_ASSUME, "assume"), NM_UTILS_LOOKUP_STR_ITEM(NM_ACTIVATION_TYPE_EXTERNAL, "external"), ); + +/*****************************************************************************/ + +typedef struct { + GPid pid; + GTask * task; + gulong cancellable_id; + GSource *child_watch_source; + GSource *timeout_source; + + int child_stdin; + int child_stdout; + GSource *input_source; + GSource *output_source; + + NMStrBuf in_buffer; + NMStrBuf out_buffer; + gsize out_buffer_offset; +} HelperInfo; + +#define _NMLOG_PREFIX_NAME "helper" +#define _NMLOG_DOMAIN LOGD_CORE +#define _NMLOG2(level, info, ...) \ + G_STMT_START \ + { \ + if (nm_logging_enabled((level), (_NMLOG_DOMAIN))) { \ + HelperInfo *_info = (info); \ + \ + _nm_log((level), \ + (_NMLOG_DOMAIN), \ + 0, \ + NULL, \ + NULL, \ + _NMLOG_PREFIX_NAME "[" NM_HASH_OBFUSCATE_PTR_FMT \ + ",%d]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + NM_HASH_OBFUSCATE_PTR(_info), \ + _info->pid _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } \ + G_STMT_END + +static void +helper_info_free(gpointer data) +{ + HelperInfo *info = data; + + nm_clear_g_source_inst(&info->child_watch_source); + nm_clear_g_source_inst(&info->timeout_source); + g_object_unref(info->task); + + nm_str_buf_destroy(&info->in_buffer); + nm_str_buf_destroy(&info->out_buffer); + nm_clear_g_source_inst(&info->input_source); + nm_clear_g_source_inst(&info->output_source); + + if (info->child_stdout != -1) + nm_close(info->child_stdout); + if (info->child_stdin != -1) + nm_close(info->child_stdin); + + if (info->pid != -1) { + nm_assert(info->pid > 1); + nm_utils_kill_child_async(info->pid, SIGKILL, LOGD_CORE, _NMLOG_PREFIX_NAME, 0, NULL, NULL); + } + + g_free(info); +} + +static void +helper_complete(HelperInfo *info, GError *error) +{ + if (error) { + nm_clear_g_cancellable_disconnect(g_task_get_cancellable(info->task), + &info->cancellable_id); + g_task_return_error(info->task, error); + helper_info_free(info); + return; + } + + if (info->input_source || info->output_source || info->pid != -1) { + /* Wait that pipes are closed and process has terminated */ + return; + } + + nm_clear_g_cancellable_disconnect(g_task_get_cancellable(info->task), &info->cancellable_id); + g_task_return_pointer(info->task, nm_str_buf_finalize(&info->in_buffer, NULL), g_free); + helper_info_free(info); +} + +static gboolean +helper_can_write(int fd, GIOCondition condition, gpointer user_data) +{ + HelperInfo *info = user_data; + gssize n_written; + int errsv; + + if (NM_FLAGS_HAS(condition, G_IO_ERR)) { + errsv = EIO; + goto out_error; + } else if (NM_FLAGS_HAS(condition, G_IO_HUP)) { + errsv = EPIPE; + goto out_error; + } + + n_written = write(info->child_stdin, + &((nm_str_buf_get_str_unsafe(&info->out_buffer))[info->out_buffer_offset]), + info->out_buffer.len - info->out_buffer_offset); + errsv = errno; + + if (n_written < 0 && errsv != EAGAIN) + goto out_error; + + if (n_written > 0) { + if ((gsize) n_written >= (info->out_buffer.len - info->out_buffer_offset)) { + nm_assert((gsize) n_written == (info->out_buffer.len - info->out_buffer_offset)); + nm_clear_g_source_inst(&info->output_source); + nm_close(info->child_stdin); + info->child_stdin = -1; + return G_SOURCE_CONTINUE; + } + info->out_buffer_offset += (gsize) n_written; + } + + return G_SOURCE_CONTINUE; + +out_error: + nm_clear_g_source_inst(&info->output_source); + helper_complete(info, + g_error_new(NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + "error writing to helper: %d (%s)", + errsv, + nm_strerror_native(errsv))); + return G_SOURCE_CONTINUE; +} + +static gboolean +helper_have_data(int fd, GIOCondition condition, gpointer user_data) +{ + HelperInfo *info = user_data; + gssize n_read; + GError * error = NULL; + + n_read = nm_utils_fd_read(fd, &info->in_buffer); + _LOG2T(info, "read returns %ld", (long) n_read); + + if (n_read > 0) + return G_SOURCE_CONTINUE; + + nm_clear_g_source_inst(&info->input_source); + nm_close(info->child_stdout); + info->child_stdout = -1; + + _LOG2T(info, "stdout closed"); + + if (n_read < 0) { + error = g_error_new(NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + "read from process returned %d (%s)", + (int) -n_read, + nm_strerror_native((int) -n_read)); + } + + helper_complete(info, error); + return G_SOURCE_CONTINUE; +} + +static void +helper_child_terminated(GPid pid, int status, gpointer user_data) +{ + HelperInfo * info = user_data; + GError * error = NULL; + gs_free char *status_desc = NULL; + + _LOG2D(info, "process %s", (status_desc = nm_utils_get_process_exit_status_desc(status))); + + info->pid = -1; + nm_clear_g_source_inst(&info->child_watch_source); + + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + if (!status_desc) + status_desc = nm_utils_get_process_exit_status_desc(status); + error = + g_error_new(NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "helper process %s", status_desc); + } + + helper_complete(info, error); +} + +static gboolean +helper_timeout(gpointer user_data) +{ + HelperInfo *info = user_data; + + nm_clear_g_source_inst(&info->timeout_source); + helper_complete(info, g_error_new_literal(NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "timed out")); + + return G_SOURCE_CONTINUE; +} + +static void +helper_cancelled(GObject *object, gpointer user_data) +{ + HelperInfo *info = user_data; + GError * error = NULL; + + nm_clear_g_signal_handler(g_task_get_cancellable(info->task), &info->cancellable_id); + nm_utils_error_set_cancelled(&error, FALSE, NULL); + helper_complete(info, error); +} + +void +nm_utils_spawn_helper(const char *const * args, + GCancellable * cancellable, + GAsyncReadyCallback callback, + gpointer cb_data) +{ + gs_free_error GError *error = NULL; + gs_free char * commands = NULL; + HelperInfo * info; + int fd_flags; + const char *const * arg; + + nm_assert(args && args[0]); + + info = g_new(HelperInfo, 1); + *info = (HelperInfo){ + .task = nm_g_task_new(NULL, cancellable, nm_utils_spawn_helper, callback, cb_data), + .child_stdin = -1, + .child_stdout = -1, + .pid = -1, + }; + + if (!g_spawn_async_with_pipes("/", + (char **) NM_MAKE_STRV(LIBEXECDIR "/nm-daemon-helper"), + (char **) NM_MAKE_STRV(), + G_SPAWN_DO_NOT_REAP_CHILD, + NULL, + NULL, + &info->pid, + &info->child_stdin, + &info->child_stdout, + NULL, + &error)) { + info->child_stdin = -1; + info->child_stdout = -1; + info->pid = -1; + g_task_return_error(info->task, + g_error_new(NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + "error spawning nm-helper: %s", + error->message)); + helper_info_free(info); + return; + } + + _LOG2D(info, "spawned process with args: %s", (commands = g_strjoinv(" ", (char **) args))); + + info->child_watch_source = g_child_watch_source_new(info->pid); + g_source_set_callback(info->child_watch_source, + G_SOURCE_FUNC(helper_child_terminated), + info, + NULL); + g_source_attach(info->child_watch_source, g_main_context_get_thread_default()); + + info->timeout_source = + nm_g_timeout_source_new_seconds(20, G_PRIORITY_DEFAULT, helper_timeout, info, NULL); + g_source_attach(info->timeout_source, g_main_context_get_thread_default()); + + /* Set file descriptors as non-blocking */ + fd_flags = fcntl(info->child_stdin, F_GETFD, 0); + fcntl(info->child_stdin, F_SETFL, fd_flags | O_NONBLOCK); + fd_flags = fcntl(info->child_stdout, F_GETFD, 0); + fcntl(info->child_stdout, F_SETFL, fd_flags | O_NONBLOCK); + + /* Watch process stdin */ + nm_str_buf_init(&info->out_buffer, 32, TRUE); + for (arg = args; *arg; arg++) { + nm_str_buf_append(&info->out_buffer, *arg); + nm_str_buf_append_c(&info->out_buffer, '\0'); + } + info->output_source = nm_g_unix_fd_source_new(info->child_stdin, + G_IO_OUT | G_IO_ERR | G_IO_HUP, + G_PRIORITY_DEFAULT, + helper_can_write, + info, + NULL); + g_source_attach(info->output_source, g_main_context_get_thread_default()); + + /* Watch process stdout */ + nm_str_buf_init(&info->in_buffer, NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE); + info->input_source = nm_g_unix_fd_source_new(info->child_stdout, + G_IO_IN | G_IO_ERR | G_IO_HUP, + G_PRIORITY_DEFAULT, + helper_have_data, + info, + NULL); + g_source_attach(info->input_source, g_main_context_get_thread_default()); + + if (cancellable) { + gulong signal_id; + + signal_id = g_cancellable_connect(cancellable, G_CALLBACK(helper_cancelled), info, NULL); + if (signal_id == 0) { + /* the request is already cancelled. Return. */ + return; + } + info->cancellable_id = signal_id; + } +} + +char * +nm_utils_spawn_helper_finish(GAsyncResult *result, GError **error) +{ + GTask *task = G_TASK(result); + + nm_assert(nm_g_task_is_valid(result, NULL, nm_utils_spawn_helper)); + + return g_task_propagate_pointer(task, error); +} diff --git a/src/core/nm-core-utils.h b/src/core/nm-core-utils.h index 5dc4d432..bcb182b8 100644 --- a/src/core/nm-core-utils.h +++ b/src/core/nm-core-utils.h @@ -12,12 +12,10 @@ #include "nm-connection.h" -#include "nm-glib-aux/nm-time-utils.h" +#include "libnm-glib-aux/nm-time-utils.h" /*****************************************************************************/ -#define NM_PLATFORM_LIFETIME_PERMANENT G_MAXUINT32 - #define NM_DEFINE_SINGLETON_INSTANCE(TYPE) static TYPE *singleton_instance #define NM_DEFINE_SINGLETON_REGISTER(TYPE) \ @@ -98,73 +96,6 @@ void _nm_singleton_instance_register_destruction(GObject *instance); gboolean nm_ether_addr_is_valid(const NMEtherAddr *addr); gboolean nm_ether_addr_is_valid_str(const char *str); -gconstpointer -nm_utils_ipx_address_clear_host_address(int family, gpointer dst, gconstpointer src, guint8 plen); -in_addr_t nm_utils_ip4_address_clear_host_address(in_addr_t addr, guint8 plen); -const struct in6_addr *nm_utils_ip6_address_clear_host_address(struct in6_addr * dst, - const struct in6_addr *src, - guint8 plen); - -static inline int -nm_utils_ip4_address_same_prefix_cmp(in_addr_t addr_a, in_addr_t addr_b, guint8 plen) -{ - NM_CMP_DIRECT(htonl(nm_utils_ip4_address_clear_host_address(addr_a, plen)), - htonl(nm_utils_ip4_address_clear_host_address(addr_b, plen))); - return 0; -} - -int nm_utils_ip6_address_same_prefix_cmp(const struct in6_addr *addr_a, - const struct in6_addr *addr_b, - guint8 plen); - -static inline int -nm_utils_ip_address_same_prefix_cmp(int addr_family, - gconstpointer addr_a, - gconstpointer addr_b, - guint8 plen) -{ - nm_assert_addr_family(addr_family); - - NM_CMP_SELF(addr_a, addr_b); - - if (NM_IS_IPv4(addr_family)) { - return nm_utils_ip4_address_same_prefix_cmp(*((const in_addr_t *) addr_a), - *((const in_addr_t *) addr_b), - plen); - } - - return nm_utils_ip6_address_same_prefix_cmp(addr_a, addr_b, plen); -} - -static inline gboolean -nm_utils_ip4_address_same_prefix(in_addr_t addr_a, in_addr_t addr_b, guint8 plen) -{ - return nm_utils_ip4_address_same_prefix_cmp(addr_a, addr_b, plen) == 0; -} - -static inline gboolean -nm_utils_ip6_address_same_prefix(const struct in6_addr *addr_a, - const struct in6_addr *addr_b, - guint8 plen) -{ - return nm_utils_ip6_address_same_prefix_cmp(addr_a, addr_b, plen) == 0; -} - -static inline gboolean -nm_utils_ip_address_same_prefix(int addr_family, - gconstpointer addr_a, - gconstpointer addr_b, - guint8 plen) -{ - return nm_utils_ip_address_same_prefix_cmp(addr_family, addr_a, addr_b, plen) == 0; -} - -#define NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX(a, b, plen) \ - NM_CMP_RETURN(nm_utils_ip4_address_same_prefix_cmp((a), (b), (plen))) - -#define NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX(a, b, plen) \ - NM_CMP_RETURN(nm_utils_ip6_address_same_prefix_cmp((a), (b), (plen))) - static inline void nm_hash_update_in6addr(NMHashState *h, const struct in6_addr *addr) { @@ -185,8 +116,6 @@ nm_hash_update_in6addr_prefix(NMHashState *h, const struct in6_addr *addr, guint nm_hash_update_in6addr(h, &a); } -double nm_utils_exp10(gint16 e); - /** * nm_utils_ip6_route_metric_normalize: * @metric: the route metric @@ -221,9 +150,6 @@ nm_utils_ip_route_metric_penalize(guint32 metric, guint32 penalty) return G_MAXUINT32; } -int nm_utils_modprobe(GError **error, gboolean suppress_error_loggin, const char *arg1, ...) - G_GNUC_NULL_TERMINATED; - void nm_utils_kill_process_sync(pid_t pid, guint64 start_time, int sig, @@ -291,9 +217,6 @@ gboolean nm_utils_connection_has_default_route(NMConnection *connection, int addr_family, gboolean * out_is_never_default); -char * nm_utils_new_vlan_name(const char *parent_iface, guint32 vlan_id); -const char *nm_utils_new_infiniband_name(char *name, const char *parent_name, int p_key); - int nm_utils_cmp_connection_by_autoconnect_priority(NMConnection *a, NMConnection *b); void nm_utils_log_connection_diff(NMConnection *connection, @@ -304,19 +227,6 @@ void nm_utils_log_connection_diff(NMConnection *connection, const char * prefix, const char * dbus_path); -gboolean nm_utils_is_valid_path_component(const char *name); -const char *NM_ASSERT_VALID_PATH_COMPONENT(const char *name); - -#define NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE 100 - -const char * -nm_utils_sysctl_ip_conf_path(int addr_family, char *buf, const char *ifname, const char *property); - -gboolean nm_utils_sysctl_ip_conf_is_path(int addr_family, - const char *path, - const char *ifname, - const char *property); - gboolean nm_utils_is_specific_hostname(const char *name); struct _NMUuid; @@ -344,49 +254,6 @@ nm_utils_arp_type_get_hwaddr_relevant_part(int arp_type, const guint8 **hwaddr, /*****************************************************************************/ -/* IPv6 Interface Identifier helpers */ - -/** - * NMUtilsIPv6IfaceId: - * @id: convenience member for validity checking; never use directly - * @id_u8: the 64-bit Interface Identifier - * - * Holds a 64-bit IPv6 Interface Identifier. The IID is a sequence of bytes - * and should not normally be treated as a %guint64, but this is done for - * convenience of validity checking and initialization. - */ -struct _NMUtilsIPv6IfaceId { - union { - guint64 id; - guint8 id_u8[8]; - }; -}; - -#define NM_UTILS_IPV6_IFACE_ID_INIT \ - { \ - { \ - .id = 0 \ - } \ - } - -void nm_utils_ipv6_addr_set_interface_identifier(struct in6_addr * addr, - const NMUtilsIPv6IfaceId iid); - -void nm_utils_ipv6_interface_identifier_get_from_addr(NMUtilsIPv6IfaceId * iid, - const struct in6_addr *addr); - -gboolean nm_utils_ipv6_interface_identifier_get_from_token(NMUtilsIPv6IfaceId *iid, - const char * token); - -const char *nm_utils_inet6_interface_identifier_to_token(NMUtilsIPv6IfaceId iid, - char buf[static INET6_ADDRSTRLEN]); - -gboolean nm_utils_get_ipv6_interface_identifier(NMLinkType link_type, - const guint8 * hwaddr, - guint len, - guint dev_id, - NMUtilsIPv6IfaceId *out_iid); - typedef enum { /* The stable type. Note that this value is encoded in the * generated addresses, thus the numbers MUST not change. @@ -501,33 +368,6 @@ void _nm_utils_set_testing(NMUtilsTestFlags flags); void nm_utils_g_value_set_strv(GValue *value, GPtrArray *strings); -guint32 -nm_utils_lifetime_rebase_relative_time_on_now(guint32 timestamp, guint32 duration, gint32 now); - -guint32 nm_utils_lifetime_get(guint32 timestamp, - guint32 lifetime, - guint32 preferred, - gint32 now, - guint32 *out_preferred); - -/*****************************************************************************/ - -#define NM_IPV4LL_NETWORK ((in_addr_t)(htonl(0xA9FE0000lu))) -#define NM_IPV4LL_NETMASK ((in_addr_t)(htonl(0xFFFF0000lu))) - -static inline gboolean -nm_utils_ip4_address_is_link_local(in_addr_t addr) -{ - return (addr & NM_IPV4LL_NETMASK) == NM_IPV4LL_NETWORK; -} - -static inline gboolean -nm_utils_ip4_address_is_zeronet(in_addr_t network) -{ - /* Same as ipv4_is_zeronet() from kernel's include/linux/in.h. */ - return (network & htonl(0xFF000000u)) == htonl(0x00000000u); -} - /*****************************************************************************/ const char *nm_utils_dnsmasq_status_to_string(int status, char *dest, gsize size); @@ -556,20 +396,6 @@ char * nm_utils_format_con_diff_for_audit(GHashTable *diff); /*****************************************************************************/ -/* this enum is compatible with ICMPV6_ROUTER_PREF_* (from , - * the values for netlink attribute RTA_PREF) and "enum ndp_route_preference" - * from . */ -typedef enum _nm_packed { - NM_ICMPV6_ROUTER_PREF_MEDIUM = 0x0, /* ICMPV6_ROUTER_PREF_MEDIUM */ - NM_ICMPV6_ROUTER_PREF_LOW = 0x3, /* ICMPV6_ROUTER_PREF_LOW */ - NM_ICMPV6_ROUTER_PREF_HIGH = 0x1, /* ICMPV6_ROUTER_PREF_HIGH */ - NM_ICMPV6_ROUTER_PREF_INVALID = 0x2, /* ICMPV6_ROUTER_PREF_INVALID */ -} NMIcmpv6RouterPref; - -const char *nm_icmpv6_router_pref_to_string(NMIcmpv6RouterPref pref, char *buf, gsize len); - -/*****************************************************************************/ - const char *nm_activation_type_to_string(NMActivationType activation_type); /*****************************************************************************/ @@ -594,4 +420,13 @@ guint8 nm_wifi_utils_level_to_quality(int val); #define NM_UTILS_ERROR_MSG_REQ_UID_UKNOWN "Unable to determine UID of the request" #define NM_UTILS_ERROR_MSG_INSUFF_PRIV "Insufficient privileges" +/*****************************************************************************/ + +void nm_utils_spawn_helper(const char *const * args, + GCancellable * cancellable, + GAsyncReadyCallback callback, + gpointer cb_data); + +char *nm_utils_spawn_helper_finish(GAsyncResult *result, GError **error); + #endif /* __NM_CORE_UTILS_H__ */ diff --git a/src/core/nm-dbus-manager.c b/src/core/nm-dbus-manager.c index 4f34ee52..c47d4dbf 100644 --- a/src/core/nm-dbus-manager.c +++ b/src/core/nm-dbus-manager.c @@ -13,13 +13,13 @@ #include #include "c-list/src/c-list.h" -#include "nm-glib-aux/nm-c-list.h" +#include "libnm-glib-aux/nm-c-list.h" #include "nm-dbus-interface.h" -#include "nm-core-internal.h" -#include "nm-std-aux/nm-dbus-compat.h" +#include "libnm-core-intern/nm-core-internal.h" +#include "libnm-std-aux/nm-dbus-compat.h" #include "nm-dbus-object.h" #include "NetworkManagerUtils.h" -#include "nm-libnm-core-intern/nm-auth-subject.h" +#include "libnm-core-aux-intern/nm-auth-subject.h" /* The base path for our GDBusObjectManagerServers. They do not contain * "NetworkManager" because GDBusObjectManagerServer requires that all @@ -1139,10 +1139,6 @@ _nm_dbus_manager_obj_notify(NMDBusObject *obj, guint n_pspecs, const GParamSpec NMDBusManagerPrivate *priv; RegistrationData * reg_data; guint i, p; - gboolean any_legacy_signals = FALSE; - gboolean any_legacy_properties = FALSE; - GVariantBuilder legacy_builder; - GVariant * device_statistics_args = NULL; nm_assert(NM_IS_DBUS_OBJECT(obj)); nm_assert(obj->internal.path); @@ -1159,13 +1155,6 @@ _nm_dbus_manager_obj_notify(NMDBusObject *obj, guint n_pspecs, const GParamSpec if (G_UNLIKELY(!priv->started)) return; - c_list_for_each_entry (reg_data, &obj->internal.registration_lst_head, registration_lst) { - if (_reg_data_get_interface_info(reg_data)->legacy_property_changed) { - any_legacy_signals = TRUE; - break; - } - } - /* do a naive search for the matching NMDBusPropertyInfoExtended infos. Since the number of * (interfaces x properties) is static and possibly small, this naive search is effectively * O(1). We might wanna introduce some index to lookup the properties in question faster. @@ -1196,18 +1185,6 @@ _nm_dbus_manager_obj_notify(NMDBusObject *obj, guint n_pspecs, const GParamSpec value = _obj_get_property(reg_data, i, TRUE); - if (property_info->include_in_legacy_property_changed && any_legacy_signals) { - /* also track the value in the legacy_builder to emit legacy signals below. */ - if (!any_legacy_properties) { - any_legacy_properties = TRUE; - g_variant_builder_init(&legacy_builder, G_VARIANT_TYPE("a{sv}")); - } - g_variant_builder_add(&legacy_builder, - "{sv}", - property_info->parent.name, - value); - } - if (!has_properties) { has_properties = TRUE; g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}")); @@ -1221,74 +1198,16 @@ _nm_dbus_manager_obj_notify(NMDBusObject *obj, guint n_pspecs, const GParamSpec args = g_variant_builder_end(&builder); - if (G_UNLIKELY(interface_info == &nm_interface_info_device_statistics)) { - /* we treat the Device.Statistics signal special, because we need to - * emit a signal also for it (below). */ - nm_assert(!device_statistics_args); - device_statistics_args = g_variant_ref_sink(args); - } - g_variant_builder_init(&invalidated_builder, G_VARIANT_TYPE("as")); g_dbus_connection_emit_signal( priv->main_dbus_connection, NULL, obj->internal.path, - "org.freedesktop.DBus.Properties", + DBUS_INTERFACE_PROPERTIES, "PropertiesChanged", g_variant_new("(s@a{sv}as)", interface_info->parent.name, args, &invalidated_builder), NULL); } - - if (G_UNLIKELY(device_statistics_args)) { - /* this is a special interface: it has a legacy PropertiesChanged signal, - * however, contrary to other interfaces with ~regular~ legacy signals, - * we only notify about properties that actually belong to this interface. */ - g_dbus_connection_emit_signal(priv->main_dbus_connection, - NULL, - obj->internal.path, - nm_interface_info_device_statistics.parent.name, - "PropertiesChanged", - g_variant_new("(@a{sv})", device_statistics_args), - NULL); - g_variant_unref(device_statistics_args); - } - - if (any_legacy_properties) { - gs_unref_variant GVariant *args = NULL; - - /* The legacy PropertyChanged signal on the NetworkManager D-Bus interface is - * deprecated for the standard signal on org.freedesktop.DBus.Properties. However, - * for backward compatibility, we still need to emit it. - * - * Due to a bug in dbus-glib in NetworkManager <= 1.0, the signal would - * not only notify about properties that were actually on the corresponding - * D-Bus interface. Instead, it would notify about all relevant properties - * on all interfaces that had such a signal. - * - * For example, "HwAddress" gets emitted both on "fdo.NM.Device.Ethernet" - * and "fdo.NM.Device.Veth" for veth interfaces, although only the former - * actually has such a property. - * Also note that "fdo.NM.Device" interface has no legacy signal. All notifications - * about its properties are instead emitted on the interfaces of the subtypes. - * - * See bgo#770629 and commit bef26a2e69f51259095fa080221db73de09fd38d. - */ - args = g_variant_ref_sink(g_variant_new("(a{sv})", &legacy_builder)); - c_list_for_each_entry (reg_data, &obj->internal.registration_lst_head, registration_lst) { - const NMDBusInterfaceInfoExtended *interface_info = - _reg_data_get_interface_info(reg_data); - - if (interface_info->legacy_property_changed) { - g_dbus_connection_emit_signal(priv->main_dbus_connection, - NULL, - obj->internal.path, - interface_info->parent.name, - "PropertiesChanged", - args, - NULL); - } - } - } } void diff --git a/src/core/nm-dbus-object.c b/src/core/nm-dbus-object.c index 6f294fe2..04149739 100644 --- a/src/core/nm-dbus-object.c +++ b/src/core/nm-dbus-object.c @@ -183,23 +183,25 @@ nm_dbus_object_unexport_on_idle(gpointer /* (NMDBusObject *) */ self_take) /*****************************************************************************/ -void +gboolean _nm_dbus_object_clear_and_unexport(NMDBusObject **location) { NMDBusObject *self; - g_return_if_fail(location); + g_return_val_if_fail(location, FALSE); + if (!*location) - return; + return FALSE; self = g_steal_pointer(location); - g_return_if_fail(NM_IS_DBUS_OBJECT(self)); + g_return_val_if_fail(NM_IS_DBUS_OBJECT(self), FALSE); if (self->internal.path) nm_dbus_object_unexport(self); g_object_unref(self); + return TRUE; } /*****************************************************************************/ diff --git a/src/core/nm-dbus-object.h b/src/core/nm-dbus-object.h index d94bd5df..ae089dd3 100644 --- a/src/core/nm-dbus-object.h +++ b/src/core/nm-dbus-object.h @@ -45,17 +45,6 @@ typedef struct { /*****************************************************************************/ -/* "org.freedesktop.NetworkManager.Device.Statistics" is a special interface, - * because although it has a legacy PropertiesChanged signal, it only notifies - * about properties that actually exist on that interface. That is, because it - * was added with 1.4.0 release, and thus didn't have the broken behavior like - * other legacy interfaces. Those notify about *all* properties, even if they - * are not part of that D-Bus interface. See also "include_in_legacy_property_changed" - * and "legacy_property_changed". */ -extern const NMDBusInterfaceInfoExtended nm_interface_info_device_statistics; - -/*****************************************************************************/ - #define NM_TYPE_DBUS_OBJECT (nm_dbus_object_get_type()) #define NM_DBUS_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DBUS_OBJECT, NMDBusObject)) #define NM_DBUS_OBJECT_CLASS(klass) \ @@ -166,9 +155,9 @@ void nm_dbus_object_unexport(gpointer /* (NMDBusObject *) */ self); void nm_dbus_object_unexport_on_idle(gpointer /* (NMDBusObject *) */ self_take); -void _nm_dbus_object_clear_and_unexport(NMDBusObject **location); +gboolean _nm_dbus_object_clear_and_unexport(NMDBusObject **location); #define nm_dbus_object_clear_and_unexport(location) \ - _nm_dbus_object_clear_and_unexport((NMDBusObject **) (location)) + _nm_dbus_object_clear_and_unexport(NM_CAST_PPTR(NMDBusObject, (location))) void nm_dbus_object_emit_signal_variant(NMDBusObject * self, const NMDBusInterfaceInfoExtended *interface_info, diff --git a/src/core/nm-dbus-utils.c b/src/core/nm-dbus-utils.c index 5890bdf2..d3e5612d 100644 --- a/src/core/nm-dbus-utils.c +++ b/src/core/nm-dbus-utils.c @@ -11,10 +11,6 @@ /*****************************************************************************/ -const GDBusSignalInfo nm_signal_info_property_changed_legacy = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT( - "PropertiesChanged", - .args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("properties", "a{sv}"), ), ); - GDBusPropertyInfo * nm_dbus_utils_interface_info_lookup_property(const GDBusInterfaceInfo *interface_info, const char * property_name, diff --git a/src/core/nm-dbus-utils.h b/src/core/nm-dbus-utils.h index 501e1996..6585d43d 100644 --- a/src/core/nm-dbus-utils.h +++ b/src/core/nm-dbus-utils.h @@ -14,11 +14,6 @@ struct _NMDBusMethodInfoExtended; struct _NMDBusPropertyInfoExtendedBase { GDBusPropertyInfo _parent; const char * property_name; - - /* Whether the properties needs to be notified on the legacy - * PropertyChanged signal. This is only to preserve API, new - * properties should not use this. */ - bool include_in_legacy_property_changed; }; struct _NMDBusPropertyInfoExtendedReadWritable { @@ -43,93 +38,46 @@ typedef struct { struct { GDBusPropertyInfo parent; const char * property_name; - - /* Whether the properties needs to be notified on the legacy - * PropertyChanged signal. This is only to preserve API, new - * properties should not use this. */ - bool include_in_legacy_property_changed; }; }; } NMDBusPropertyInfoExtended; G_STATIC_ASSERT(G_STRUCT_OFFSET(NMDBusPropertyInfoExtended, property_name) == G_STRUCT_OFFSET(struct _NMDBusPropertyInfoExtendedBase, property_name)); -G_STATIC_ASSERT(G_STRUCT_OFFSET(NMDBusPropertyInfoExtended, include_in_legacy_property_changed) - == G_STRUCT_OFFSET(struct _NMDBusPropertyInfoExtendedBase, - include_in_legacy_property_changed)); - -#define NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_FULL(m_name, \ - m_signature, \ - m_property_name, \ - m_include_in_legacy_property_changed) \ - ((GDBusPropertyInfo *) &((const struct _NMDBusPropertyInfoExtendedBase){ \ - ._parent = \ - { \ - .ref_count = -1, \ - .name = m_name, \ - .signature = m_signature, \ - .flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE, \ - }, \ - .property_name = m_property_name, \ - .include_in_legacy_property_changed = m_include_in_legacy_property_changed, \ - })) #define NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE(m_name, m_signature, m_property_name) \ - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_FULL(m_name, m_signature, m_property_name, FALSE) - -/* define a legacy property. Do not use for new code. */ -#define NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L(m_name, m_signature, m_property_name) \ - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_FULL(m_name, m_signature, m_property_name, TRUE) - -#define NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_FULL( \ - m_name, \ - m_signature, \ - m_property_name, \ - m_permission, \ - m_audit_op, \ - m_include_in_legacy_property_changed) \ - ((GDBusPropertyInfo *) &((const struct _NMDBusPropertyInfoExtendedReadWritable){ \ - ._base = \ - { \ - ._parent = \ - { \ - .ref_count = -1, \ - .name = m_name, \ - .signature = m_signature, \ - .flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE \ - | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE, \ - }, \ - .property_name = m_property_name, \ - .include_in_legacy_property_changed = m_include_in_legacy_property_changed, \ - }, \ - .permission = m_permission, \ - .audit_op = m_audit_op, \ + ((GDBusPropertyInfo *) &((const struct _NMDBusPropertyInfoExtendedBase){ \ + ._parent = \ + { \ + .ref_count = -1, \ + .name = m_name, \ + .signature = m_signature, \ + .flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE, \ + }, \ + .property_name = m_property_name, \ })) -#define NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE(m_name, \ - m_signature, \ - m_property_name, \ - m_permission, \ - m_audit_op) \ - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_FULL(m_name, \ - m_signature, \ - m_property_name, \ - m_permission, \ - m_audit_op, \ - FALSE) - -/* define a legacy property. Do not use for new code. */ -#define NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L(m_name, \ - m_signature, \ - m_property_name, \ - m_permission, \ - m_audit_op) \ - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_FULL(m_name, \ - m_signature, \ - m_property_name, \ - m_permission, \ - m_audit_op, \ - TRUE) +#define NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE(m_name, \ + m_signature, \ + m_property_name, \ + m_permission, \ + m_audit_op) \ + ((GDBusPropertyInfo *) &((const struct _NMDBusPropertyInfoExtendedReadWritable){ \ + ._base = \ + { \ + ._parent = \ + { \ + .ref_count = -1, \ + .name = m_name, \ + .signature = m_signature, \ + .flags = G_DBUS_PROPERTY_INFO_FLAGS_READABLE \ + | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE, \ + }, \ + .property_name = m_property_name, \ + }, \ + .permission = m_permission, \ + .audit_op = m_audit_op, \ + })) typedef struct _NMDBusMethodInfoExtended { GDBusMethodInfo parent; @@ -148,14 +96,8 @@ typedef struct _NMDBusMethodInfoExtended { typedef struct _NMDBusInterfaceInfoExtended { GDBusInterfaceInfo parent; - - /* Whether the interface has a legacy property changed signal (@nm_signal_info_property_changed_legacy). - * New interfaces should not use this. */ - bool legacy_property_changed : 1; } NMDBusInterfaceInfoExtended; -extern const GDBusSignalInfo nm_signal_info_property_changed_legacy; - #define NM_DBUS_INTERFACE_INFOS(...) \ ({ \ static const NMDBusInterfaceInfoExtended *const _interface_infos[] = { \ diff --git a/src/core/nm-dcb.c b/src/core/nm-dcb.c index b3958caa..930a1023 100644 --- a/src/core/nm-dcb.c +++ b/src/core/nm-dcb.c @@ -8,7 +8,7 @@ #include #include "nm-dcb.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "NetworkManagerUtils.h" static const char *helper_names[] = {"dcbtool", "fcoeadm"}; diff --git a/src/core/nm-default-daemon.h b/src/core/nm-default-daemon.h index 65ca4b54..57d4c6af 100644 --- a/src/core/nm-default-daemon.h +++ b/src/core/nm-default-daemon.h @@ -8,7 +8,7 @@ /*****************************************************************************/ -#include "nm-glib-aux/nm-default-glib-i18n-prog.h" +#include "libnm-glib-aux/nm-default-glib-i18n-prog.h" #undef NETWORKMANAGER_COMPILATION #define NETWORKMANAGER_COMPILATION NM_NETWORKMANAGER_COMPILATION_DAEMON @@ -19,7 +19,7 @@ #include "nm-core-types.h" #include "nm-types.h" -#include "nm-log-core/nm-logging.h" +#include "libnm-log-core/nm-logging.h" /*****************************************************************************/ diff --git a/src/core/nm-dhcp-config.c b/src/core/nm-dhcp-config.c index 718d3c90..1cbad49e 100644 --- a/src/core/nm-dhcp-config.c +++ b/src/core/nm-dhcp-config.c @@ -59,6 +59,7 @@ struct _NMDhcpConfig { struct _NMDhcpConfigClass { NMDBusObjectClass parent; + int addr_family; }; G_DEFINE_ABSTRACT_TYPE(NMDhcpConfig, nm_dhcp_config, NM_TYPE_DBUS_OBJECT) @@ -67,6 +68,14 @@ G_DEFINE_ABSTRACT_TYPE(NMDhcpConfig, nm_dhcp_config, NM_TYPE_DBUS_OBJECT) /*****************************************************************************/ +int +nm_dhcp_config_get_addr_family(NMDhcpConfig *self) +{ + return NM_DHCP_CONFIG_GET_CLASS(self)->addr_family; +} + +/*****************************************************************************/ + void nm_dhcp_config_set_options(NMDhcpConfig *self, GHashTable *options) { @@ -116,8 +125,7 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) switch (prop_id) { case PROP_OPTIONS: - g_value_set_variant(value, - priv->options ?: g_variant_new_array(G_VARIANT_TYPE("{sv}"), NULL, 0)); + g_value_set_variant(value, priv->options ?: nm_g_variant_singleton_aLsvI()); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); @@ -186,22 +194,23 @@ nm_dhcp4_config_init(NMDhcp4Config *self) static const NMDBusInterfaceInfoExtended interface_info_dhcp4_config = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DHCP4_CONFIG, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Options", - "a{sv}", - NM_DHCP_CONFIG_OPTIONS), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Options", + "a{sv}", + NM_DHCP_CONFIG_OPTIONS), ), ), }; static void nm_dhcp4_config_class_init(NMDhcp4ConfigClass *klass) { NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); + NMDhcpConfigClass *dhcp_config_class = NM_DHCP_CONFIG_CLASS(klass); dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED(NM_DBUS_PATH "/DHCP4Config"); dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_dhcp4_config); dbus_object_class->export_on_construction = TRUE; + + dhcp_config_class->addr_family = AF_INET; } /*****************************************************************************/ @@ -223,20 +232,21 @@ nm_dhcp6_config_init(NMDhcp6Config *self) static const NMDBusInterfaceInfoExtended interface_info_dhcp6_config = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_DHCP6_CONFIG, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Options", - "a{sv}", - NM_DHCP_CONFIG_OPTIONS), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Options", + "a{sv}", + NM_DHCP_CONFIG_OPTIONS), ), ), }; static void nm_dhcp6_config_class_init(NMDhcp6ConfigClass *klass) { NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); + NMDhcpConfigClass *dhcp_config_class = NM_DHCP_CONFIG_CLASS(klass); dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED(NM_DBUS_PATH "/DHCP6Config"); dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_dhcp6_config); dbus_object_class->export_on_construction = TRUE; + + dhcp_config_class->addr_family = AF_INET6; } diff --git a/src/core/nm-dispatcher.c b/src/core/nm-dispatcher.c index 0ab409f5..32c9db62 100644 --- a/src/core/nm-dispatcher.c +++ b/src/core/nm-dispatcher.c @@ -8,7 +8,7 @@ #include "nm-dispatcher.h" -#include "nm-libnm-core-aux/nm-dispatcher-api.h" +#include "libnm-core-aux-extern/nm-dispatcher-api.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" #include "nm-connectivity.h" @@ -20,8 +20,8 @@ #include "nm-ip6-config.h" #include "nm-manager.h" #include "settings/nm-settings-connection.h" -#include "platform/nm-platform.h" -#include "nm-core-internal.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-core-intern/nm-core-internal.h" #define CALL_TIMEOUT (1000 * 60 * 10) /* 10 minutes for all scripts */ @@ -206,10 +206,7 @@ dump_ip_to_props(NMIPConfig *ip, GVariantBuilder *builder) array[0] = addr->a4.address; array[1] = addr->a4.plen; array[2] = gw; - g_variant_builder_add( - &int_builder, - "@au", - g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, array, 3, sizeof(guint32))); + g_variant_builder_add(&int_builder, "@au", nm_g_variant_new_au(array, 3)); } else { const struct in6_addr *gw = &in6addr_any; @@ -278,10 +275,7 @@ dump_ip_to_props(NMIPConfig *ip, GVariantBuilder *builder) array[1] = route->r4.plen; array[2] = route->r4.gateway; array[3] = route->r4.metric; - g_variant_builder_add( - &int_builder, - "@au", - g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, array, 4, sizeof(guint32))); + g_variant_builder_add(&int_builder, "@au", nm_g_variant_new_au(array, 4)); } else { var1 = nm_g_variant_new_ay_in6addr(&route->r6.network); var2 = nm_g_variant_new_ay_in6addr(&route->r6.gateway); @@ -550,9 +544,9 @@ _dispatcher_call(NMDispatcherAction action, if (applied_connection) connection_dict = - nm_connection_to_dbus(applied_connection, NM_CONNECTION_SERIALIZE_NO_SECRETS); + nm_connection_to_dbus(applied_connection, NM_CONNECTION_SERIALIZE_WITH_NON_SECRET); else - connection_dict = g_variant_new_array(G_VARIANT_TYPE("{sa{sv}}"), NULL, 0); + connection_dict = nm_g_variant_singleton_aLsaLsvII(); g_variant_builder_init(&connection_props, G_VARIANT_TYPE_VARDICT); if (settings_connection) { @@ -620,8 +614,8 @@ _dispatcher_call(NMDispatcherAction action, &device_proxy_props, &device_ip4_props, &device_ip6_props, - device_dhcp4_props ?: g_variant_new_array(G_VARIANT_TYPE("{sv}"), NULL, 0), - device_dhcp6_props ?: g_variant_new_array(G_VARIANT_TYPE("{sv}"), NULL, 0), + device_dhcp4_props ?: nm_g_variant_singleton_aLsvI(), + device_dhcp6_props ?: nm_g_variant_singleton_aLsvI(), connectivity_state_string, vpn_iface ?: "", &vpn_proxy_props, diff --git a/src/core/nm-firewall-manager.c b/src/core/nm-firewall-manager.c deleted file mode 100644 index 8f476e51..00000000 --- a/src/core/nm-firewall-manager.c +++ /dev/null @@ -1,623 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2011 - 2015 Red Hat, Inc. - */ - -#include "src/core/nm-default-daemon.h" - -#include "nm-firewall-manager.h" - -#include "nm-glib-aux/nm-dbus-aux.h" -#include "c-list/src/c-list.h" - -#include "NetworkManagerUtils.h" -#include "nm-dbus-manager.h" - -#define FIREWALL_DBUS_SERVICE "org.fedoraproject.FirewallD1" -#define FIREWALL_DBUS_PATH "/org/fedoraproject/FirewallD1" -#define FIREWALL_DBUS_INTERFACE_ZONE "org.fedoraproject.FirewallD1.zone" - -/*****************************************************************************/ - -enum { STATE_CHANGED, LAST_SIGNAL }; - -static guint signals[LAST_SIGNAL] = {0}; - -typedef struct { - GDBusConnection *dbus_connection; - - GCancellable *get_name_owner_cancellable; - - CList pending_calls; - - guint name_owner_changed_id; - - bool dbus_inited : 1; - bool running : 1; -} NMFirewallManagerPrivate; - -struct _NMFirewallManager { - GObject parent; - NMFirewallManagerPrivate _priv; -}; - -struct _NMFirewallManagerClass { - GObjectClass parent; -}; - -G_DEFINE_TYPE(NMFirewallManager, nm_firewall_manager, G_TYPE_OBJECT) - -#define NM_FIREWALL_MANAGER_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMFirewallManager, NM_IS_FIREWALL_MANAGER) - -/*****************************************************************************/ - -NM_DEFINE_SINGLETON_GETTER(NMFirewallManager, nm_firewall_manager_get, NM_TYPE_FIREWALL_MANAGER); - -/*****************************************************************************/ - -typedef enum { - OPS_TYPE_ADD = 1, - OPS_TYPE_CHANGE, - OPS_TYPE_REMOVE, -} OpsType; - -struct _NMFirewallManagerCallId { - CList lst; - - NMFirewallManager *self; - - char *iface; - - NMFirewallManagerAddRemoveCallback callback; - gpointer user_data; - - union { - struct { - GCancellable *cancellable; - GVariant * arg; - } dbus; - struct { - guint id; - } idle; - }; - - OpsType ops_type; - - bool is_idle : 1; -}; - -/*****************************************************************************/ - -static const char * -_ops_type_to_string(OpsType ops_type) -{ - switch (ops_type) { - case OPS_TYPE_ADD: - return "add"; - case OPS_TYPE_REMOVE: - return "remove"; - case OPS_TYPE_CHANGE: - return "change"; - } - nm_assert_not_reached(); - return NULL; -} - -#define _NMLOG_DOMAIN LOGD_FIREWALL -#define _NMLOG_PREFIX_NAME "firewall" -#define _NMLOG(level, call_id, ...) \ - G_STMT_START \ - { \ - if (nm_logging_enabled((level), (_NMLOG_DOMAIN))) { \ - NMFirewallManagerCallId *_call_id = (call_id); \ - char _prefix_name[30]; \ - char _prefix_info[100]; \ - \ - _nm_log((level), \ - (_NMLOG_DOMAIN), \ - 0, \ - NULL, \ - NULL, \ - "%s: %s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - (self) != singleton_instance ? ({ \ - g_snprintf(_prefix_name, \ - sizeof(_prefix_name), \ - "%s[" NM_HASH_OBFUSCATE_PTR_FMT "]", \ - ""_NMLOG_PREFIX_NAME, \ - NM_HASH_OBFUSCATE_PTR(self)); \ - _prefix_name; \ - }) \ - : _NMLOG_PREFIX_NAME, \ - _call_id ? ({ \ - g_snprintf(_prefix_info, \ - sizeof(_prefix_info), \ - "[" NM_HASH_OBFUSCATE_PTR_FMT ",%s%s:%s%s%s]: ", \ - NM_HASH_OBFUSCATE_PTR(_call_id), \ - _ops_type_to_string(_call_id->ops_type), \ - _call_id->is_idle ? "*" : "", \ - NM_PRINT_FMT_QUOTE_STRING(_call_id->iface)); \ - _prefix_info; \ - }) \ - : "" _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } \ - G_STMT_END - -/*****************************************************************************/ - -static gboolean -_get_running(NMFirewallManagerPrivate *priv) -{ - /* when starting, we need to asynchronously check whether there is - * a name owner. During that time we optimistically assume that the - * service is indeed running. That is the time when we queue the - * requests, and they will be started once the get-name-owner call - * returns. */ - return priv->running || (priv->dbus_connection && !priv->dbus_inited); -} - -gboolean -nm_firewall_manager_get_running(NMFirewallManager *self) -{ - g_return_val_if_fail(NM_IS_FIREWALL_MANAGER(self), FALSE); - - return _get_running(NM_FIREWALL_MANAGER_GET_PRIVATE(self)); -} - -/*****************************************************************************/ - -static NMFirewallManagerCallId * -_cb_info_create(NMFirewallManager * self, - OpsType ops_type, - const char * iface, - const char * zone, - NMFirewallManagerAddRemoveCallback callback, - gpointer user_data) -{ - NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE(self); - NMFirewallManagerCallId * call_id; - - call_id = g_slice_new0(NMFirewallManagerCallId); - - call_id->self = g_object_ref(self); - call_id->ops_type = ops_type; - call_id->iface = g_strdup(iface); - call_id->callback = callback; - call_id->user_data = user_data; - - if (_get_running(priv)) { - call_id->is_idle = FALSE; - call_id->dbus.arg = g_variant_new("(ss)", zone ?: "", iface); - } else - call_id->is_idle = TRUE; - - c_list_link_tail(&priv->pending_calls, &call_id->lst); - - return call_id; -} - -static void -_cb_info_complete(NMFirewallManagerCallId *call_id, GError *error) -{ - c_list_unlink(&call_id->lst); - - if (call_id->callback) - call_id->callback(call_id->self, call_id, error, call_id->user_data); - - if (call_id->is_idle) - nm_clear_g_source(&call_id->idle.id); - else { - nm_g_variant_unref(call_id->dbus.arg); - nm_clear_g_cancellable(&call_id->dbus.cancellable); - } - g_free(call_id->iface); - g_object_unref(call_id->self); - nm_g_slice_free(call_id); -} - -static gboolean -_handle_idle_cb(gpointer user_data) -{ - NMFirewallManager * self; - NMFirewallManagerCallId *call_id = user_data; - - nm_assert(call_id); - nm_assert(NM_IS_FIREWALL_MANAGER(call_id->self)); - nm_assert(call_id->is_idle); - nm_assert(c_list_contains(&NM_FIREWALL_MANAGER_GET_PRIVATE(call_id->self)->pending_calls, - &call_id->lst)); - - self = call_id->self; - - _LOGD(call_id, "complete: fake success"); - - call_id->idle.id = 0; - - _cb_info_complete(call_id, NULL); - return G_SOURCE_REMOVE; -} - -static gboolean -_handle_idle_start(NMFirewallManager *self, NMFirewallManagerCallId *call_id) -{ - if (!call_id->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(call_id, "complete: drop request simulating success"); - _cb_info_complete(call_id, NULL); - return FALSE; - } - call_id->idle.id = g_idle_add(_handle_idle_cb, call_id); - return TRUE; -} - -static void -_handle_dbus_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - NMFirewallManager * self; - NMFirewallManagerCallId *call_id; - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *ret = NULL; - - ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error); - - if (!ret && nm_utils_error_is_cancelled(error)) - return; - - call_id = user_data; - - nm_assert(call_id); - nm_assert(NM_IS_FIREWALL_MANAGER(call_id->self)); - nm_assert(!call_id->is_idle); - nm_assert(c_list_contains(&NM_FIREWALL_MANAGER_GET_PRIVATE(call_id->self)->pending_calls, - &call_id->lst)); - - self = call_id->self; - - if (error) { - const char *non_error = NULL; - - g_dbus_error_strip_remote_error(error); - - switch (call_id->ops_type) { - case OPS_TYPE_ADD: - case OPS_TYPE_CHANGE: - non_error = "ZONE_ALREADY_SET"; - break; - case OPS_TYPE_REMOVE: - non_error = "UNKNOWN_INTERFACE"; - break; - } - if (error->message && non_error && g_str_has_prefix(error->message, non_error) - && NM_IN_SET(error->message[strlen(non_error)], '\0', ':')) { - _LOGD(call_id, "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(call_id, "complete: request failed (%s)", error->message); - } else - _LOGD(call_id, "complete: success"); - - g_clear_object(&call_id->dbus.cancellable); - - _cb_info_complete(call_id, error); -} - -static void -_handle_dbus_start(NMFirewallManager *self, NMFirewallManagerCallId *call_id) -{ - NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE(self); - const char * dbus_method = NULL; - GVariant * arg; - - nm_assert(call_id); - nm_assert(priv->running); - nm_assert(!call_id->is_idle); - nm_assert(c_list_contains(&priv->pending_calls, &call_id->lst)); - - switch (call_id->ops_type) { - case OPS_TYPE_ADD: - dbus_method = "addInterface"; - break; - case OPS_TYPE_CHANGE: - dbus_method = "changeZone"; - break; - case OPS_TYPE_REMOVE: - dbus_method = "removeInterface"; - break; - } - nm_assert(dbus_method); - - arg = g_steal_pointer(&call_id->dbus.arg); - - nm_assert(arg && g_variant_is_floating(arg)); - - nm_assert(!call_id->dbus.cancellable); - - call_id->dbus.cancellable = g_cancellable_new(); - - g_dbus_connection_call(priv->dbus_connection, - FIREWALL_DBUS_SERVICE, - FIREWALL_DBUS_PATH, - FIREWALL_DBUS_INTERFACE_ZONE, - dbus_method, - arg, - NULL, - G_DBUS_CALL_FLAGS_NONE, - 10000, - call_id->dbus.cancellable, - _handle_dbus_cb, - call_id); -} - -static NMFirewallManagerCallId * -_start_request(NMFirewallManager * self, - OpsType ops_type, - const char * iface, - const char * zone, - NMFirewallManagerAddRemoveCallback callback, - gpointer user_data) -{ - NMFirewallManagerPrivate *priv; - NMFirewallManagerCallId * call_id; - - 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); - - call_id = _cb_info_create(self, ops_type, iface, zone, callback, user_data); - - _LOGD(call_id, - "firewall zone %s %s:%s%s%s%s", - _ops_type_to_string(call_id->ops_type), - iface, - NM_PRINT_FMT_QUOTED(zone, "\"", zone, "\"", "default"), - call_id->is_idle ? " (not running, simulate success)" - : (!priv->running ? " (waiting to initialize)" : "")); - - if (!call_id->is_idle) { - if (priv->running) - _handle_dbus_start(self, call_id); - if (!call_id->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 - * (this function never fails and always starts a request). */ - return NULL; - } - } else { - if (!_handle_idle_start(self, call_id)) { - /* 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. */ - return NULL; - } - } - - return call_id; -} - -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) -{ - return _start_request(self, - add ? OPS_TYPE_ADD : OPS_TYPE_CHANGE, - iface, - zone, - callback, - user_data); -} - -NMFirewallManagerCallId * -nm_firewall_manager_remove_from_zone(NMFirewallManager * self, - const char * iface, - const char * zone, - NMFirewallManagerAddRemoveCallback callback, - gpointer user_data) -{ - return _start_request(self, OPS_TYPE_REMOVE, iface, zone, callback, user_data); -} - -void -nm_firewall_manager_cancel_call(NMFirewallManagerCallId *call_id) -{ - NMFirewallManager * self; - NMFirewallManagerPrivate *priv; - gs_free_error GError *error = NULL; - - g_return_if_fail(call_id); - g_return_if_fail(NM_IS_FIREWALL_MANAGER(call_id->self)); - g_return_if_fail(!c_list_is_empty(&call_id->lst)); - - self = call_id->self; - priv = NM_FIREWALL_MANAGER_GET_PRIVATE(self); - - nm_assert(c_list_contains(&priv->pending_calls, &call_id->lst)); - - nm_utils_error_set_cancelled(&error, FALSE, "NMFirewallManager"); - - _LOGD(call_id, "complete: cancel (%s)", error->message); - - _cb_info_complete(call_id, error); -} - -/*****************************************************************************/ - -static void -name_owner_changed(NMFirewallManager *self, const char *owner) -{ - _nm_unused gs_unref_object NMFirewallManager *self_keep_alive = g_object_ref(self); - NMFirewallManagerPrivate * priv = NM_FIREWALL_MANAGER_GET_PRIVATE(self); - gboolean was_running; - gboolean now_running; - gboolean just_initied; - - owner = nm_str_not_empty(owner); - - if (!owner) - _LOGT(NULL, "D-Bus name for firewalld has no owner (firewall stopped)"); - else - _LOGT(NULL, "D-Bus name for firewalld has owner %s (firewall started)", owner); - - was_running = _get_running(priv); - just_initied = !priv->dbus_inited; - - priv->dbus_inited = TRUE; - priv->running = !!owner; - - now_running = _get_running(priv); - - if (just_initied) { - NMFirewallManagerCallId *call_id_safe; - NMFirewallManagerCallId *call_id; - - /* We kick of the requests that we have pending. Note that this is - * entirely asynchronous and also we don't invoke any callbacks for - * the user. - * Even _handle_idle_start() just schedules an idle handler. That is, - * because we don't want to callback to the user before emitting the - * DISCONNECTED signal below. Also, emitting callbacks means the user - * can call back to modify the list of pending-calls and we'd have - * to handle reentrancy. */ - c_list_for_each_entry_safe (call_id, call_id_safe, &priv->pending_calls, lst) { - nm_assert(!call_id->is_idle); - nm_assert(call_id->dbus.arg); - - if (priv->running) { - _LOGD(call_id, "initalizing: make D-Bus call"); - _handle_dbus_start(self, call_id); - } else { - /* we don't want to invoke callbacks to the user right away. That is because - * the user might schedule/cancel more calls, which messes up the order. - * - * Instead, convert the pending calls to idle requests... */ - nm_clear_pointer(&call_id->dbus.arg, g_variant_unref); - call_id->is_idle = TRUE; - _LOGD(call_id, "initializing: fake success on idle"); - _handle_idle_start(self, call_id); - } - } - } - - if (was_running != now_running) - g_signal_emit(self, signals[STATE_CHANGED], 0, FALSE); -} - -static void -name_owner_changed_cb(GDBusConnection *connection, - const char * sender_name, - const char * object_path, - const char * interface_name, - const char * signal_name, - GVariant * parameters, - gpointer user_data) -{ - NMFirewallManager *self = user_data; - const char * new_owner; - - if (!g_variant_is_of_type(parameters, G_VARIANT_TYPE("(sss)"))) - return; - - g_variant_get(parameters, "(&s&s&s)", NULL, NULL, &new_owner); - - name_owner_changed(self, new_owner); -} - -static void -get_name_owner_cb(const char *name_owner, GError *error, gpointer user_data) -{ - NMFirewallManager * self; - NMFirewallManagerPrivate *priv; - - if (!name_owner && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = user_data; - priv = NM_FIREWALL_MANAGER_GET_PRIVATE(self); - - g_clear_object(&priv->get_name_owner_cancellable); - - name_owner_changed(self, name_owner); -} - -/*****************************************************************************/ - -static void -nm_firewall_manager_init(NMFirewallManager *self) -{ - NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE(self); - - c_list_init(&priv->pending_calls); - - priv->dbus_connection = nm_g_object_ref(NM_MAIN_DBUS_CONNECTION_GET); - - if (!priv->dbus_connection) { - _LOGD(NULL, "no D-Bus connection"); - return; - } - - priv->name_owner_changed_id = - nm_dbus_connection_signal_subscribe_name_owner_changed(priv->dbus_connection, - FIREWALL_DBUS_SERVICE, - name_owner_changed_cb, - self, - NULL); - - priv->get_name_owner_cancellable = g_cancellable_new(); - nm_dbus_connection_call_get_name_owner(priv->dbus_connection, - FIREWALL_DBUS_SERVICE, - -1, - priv->get_name_owner_cancellable, - get_name_owner_cb, - self); -} - -static void -dispose(GObject *object) -{ - NMFirewallManager * self = NM_FIREWALL_MANAGER(object); - NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE(self); - - /* as every pending operation takes a reference to the manager, - * we don't expect pending operations at this point. */ - nm_assert(c_list_is_empty(&priv->pending_calls)); - - nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->name_owner_changed_id); - - nm_clear_g_cancellable(&priv->get_name_owner_cancellable); - - G_OBJECT_CLASS(nm_firewall_manager_parent_class)->dispose(object); - - g_clear_object(&priv->dbus_connection); -} - -static void -nm_firewall_manager_class_init(NMFirewallManagerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - - object_class->dispose = dispose; - - signals[STATE_CHANGED] = g_signal_new(NM_FIREWALL_MANAGER_STATE_CHANGED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - g_cclosure_marshal_VOID__BOOLEAN, - G_TYPE_NONE, - 1, - G_TYPE_BOOLEAN /* initialized_now */); -} diff --git a/src/core/nm-firewall-manager.h b/src/core/nm-firewall-manager.h deleted file mode 100644 index 1ce802b2..00000000 --- a/src/core/nm-firewall-manager.h +++ /dev/null @@ -1,54 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2011 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_FIREWALL_MANAGER_H__ -#define __NETWORKMANAGER_FIREWALL_MANAGER_H__ - -#define NM_TYPE_FIREWALL_MANAGER (nm_firewall_manager_get_type()) -#define NM_FIREWALL_MANAGER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_FIREWALL_MANAGER, NMFirewallManager)) -#define NM_FIREWALL_MANAGER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_FIREWALL_MANAGER, NMFirewallManagerClass)) -#define NM_IS_FIREWALL_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_FIREWALL_MANAGER)) -#define NM_IS_FIREWALL_MANAGER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_FIREWALL_MANAGER)) -#define NM_FIREWALL_MANAGER_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_FIREWALL_MANAGER, NMFirewallManagerClass)) - -#define NM_FIREWALL_MANAGER_STATE_CHANGED "state-changed" - -typedef struct _NMFirewallManagerCallId NMFirewallManagerCallId; - -typedef struct _NMFirewallManager NMFirewallManager; -typedef struct _NMFirewallManagerClass NMFirewallManagerClass; - -GType nm_firewall_manager_get_type(void); - -NMFirewallManager *nm_firewall_manager_get(void); - -gboolean nm_firewall_manager_get_running(NMFirewallManager *self); - -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, - NMFirewallManagerAddRemoveCallback callback, - gpointer user_data); - -void nm_firewall_manager_cancel_call(NMFirewallManagerCallId *call_id); - -#endif /* __NETWORKMANAGER_FIREWALL_MANAGER_H__ */ diff --git a/src/core/nm-firewall-utils.c b/src/core/nm-firewall-utils.c new file mode 100644 index 00000000..3f225156 --- /dev/null +++ b/src/core/nm-firewall-utils.c @@ -0,0 +1,816 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2004 - 2016 Red Hat, Inc. + * Copyright (C) 2005 - 2008 Novell, Inc. + */ + +#include "src/core/nm-default-daemon.h" + +#include "nm-firewall-utils.h" + +#include "libnm-glib-aux/nm-str-buf.h" +#include "libnm-glib-aux/nm-io-utils.h" +#include "libnm-platform/nm-platform.h" + +#include "nm-config.h" +#include "NetworkManagerUtils.h" + +/*****************************************************************************/ + +static const struct { + const char *name; + const char *path; +} FirewallBackends[] = { + [NM_FIREWALL_BACKEND_NONE - 1] = + { + .name = "none", + }, + [NM_FIREWALL_BACKEND_NFTABLES - 1] = + { + .name = "nftables", + .path = NFT_PATH, + }, + [NM_FIREWALL_BACKEND_IPTABLES - 1] = + { + .name = "iptables", + .path = IPTABLES_PATH, + }, +}; + +/*****************************************************************************/ + +#define _SHARE_IPTABLES_SUBNET_TO_STR_LEN (INET_ADDRSTRLEN + 1 + 2 + 1) + +static const char * +_share_iptables_subnet_to_str(char buf[static _SHARE_IPTABLES_SUBNET_TO_STR_LEN], + in_addr_t addr, + guint8 plen) +{ + char buf_addr[INET_ADDRSTRLEN]; + in_addr_t netmask; + int l; + + netmask = _nm_utils_ip4_prefix_to_netmask(plen); + + l = g_snprintf(buf, + _SHARE_IPTABLES_SUBNET_TO_STR_LEN, + "%s/%u", + _nm_utils_inet4_ntop(addr & netmask, buf_addr), + plen); + nm_assert(l < _SHARE_IPTABLES_SUBNET_TO_STR_LEN); + return buf; +} + +static char * +_share_iptables_get_name(gboolean is_iptables_chain, const char *prefix, const char *ip_iface) +{ + NMStrBuf strbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_40, FALSE); + gsize ip_iface_len; + + nm_assert(prefix); + nm_assert(ip_iface); + + /* This function is used to generate iptables chain names and comments. + * Chain names must be shorter than 29 chars. Comments don't have this + * limitation. + * + * Below we sanitize the ip_iface. If it's all benign, we use + * - either "-$IP_IFACE" (at most 16 chars) + * - otherwise, we base64 encode the name as "$(base64 $IP_IFACE)", at + * most 20 chars. + * + * Since for benign names we already add a '-', prefix probably should not + * contain a '-'. The '-' is necessary to distinguish between base64 encoding + * an plain name. + * + * That means, for chain names the prefix must be at most 8 chars long. */ + nm_assert(!is_iptables_chain || (strlen(prefix) <= 8)); + + nm_str_buf_append(&strbuf, prefix); + + ip_iface_len = strlen(ip_iface); + G_STATIC_ASSERT_EXPR(NMP_IFNAMSIZ == 16); + if (ip_iface_len >= NMP_IFNAMSIZ) { + nm_assert_not_reached(); + ip_iface_len = NMP_IFNAMSIZ - 1; + } + + if (NM_STRCHAR_ALL(ip_iface, + ch, + (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z') || NM_IN_SET(ch, '.', '_', '-', '+'))) { + nm_str_buf_append_c(&strbuf, '-'); + nm_str_buf_append(&strbuf, ip_iface); + } else { + gs_free char *s = NULL; + + s = g_base64_encode((const guchar *) ip_iface, ip_iface_len); + nm_str_buf_append(&strbuf, s); + } + + return nm_str_buf_finalize(&strbuf, NULL); +} + +static gboolean +_share_iptables_call_v(const char *const *argv) +{ + gs_free_error GError *error = NULL; + gs_free char * argv_str = NULL; + int status; + + nm_log_dbg(LOGD_SHARING, "iptables: %s", (argv_str = g_strjoinv(" ", (char **) argv))); + + if (!g_spawn_sync("/", + (char **) argv, + (char **) NM_PTRARRAY_EMPTY(const char *), + G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL, + NULL, + NULL, + NULL, + NULL, + &status, + &error)) { + nm_log_warn(LOGD_SHARING, + "iptables: error executing command %s: %s", + argv[0], + error->message); + return FALSE; + } + + if (!g_spawn_check_exit_status(status, &error)) { + nm_log_warn(LOGD_SHARING, "iptables: command %s failed: %s", argv[0], error->message); + return FALSE; + } + + return TRUE; +} + +#define _share_iptables_call(...) _share_iptables_call_v(NM_MAKE_STRV(__VA_ARGS__)) + +static gboolean +_share_iptables_chain_op(const char *table, const char *chain, const char *op) +{ + return _share_iptables_call("" IPTABLES_PATH "", "--table", table, op, chain); +} + +static gboolean +_share_iptables_chain_delete(const char *table, const char *chain) +{ + _share_iptables_chain_op(table, chain, "--flush"); + return _share_iptables_chain_op(table, chain, "--delete-chain"); +} + +static gboolean +_share_iptables_chain_add(const char *table, const char *chain) +{ + if (_share_iptables_chain_op(table, chain, "--new-chain")) + return TRUE; + + _share_iptables_chain_delete(table, chain); + return _share_iptables_chain_op(table, chain, "--new-chain"); +} + +static void +_share_iptables_set_masquerade(gboolean add, const char *ip_iface, in_addr_t addr, guint8 plen) +{ + char str_subnet[_SHARE_IPTABLES_SUBNET_TO_STR_LEN]; + gs_free char *comment_name = NULL; + + comment_name = _share_iptables_get_name(FALSE, "nm-shared", ip_iface); + + _share_iptables_subnet_to_str(str_subnet, addr, plen); + _share_iptables_call("" IPTABLES_PATH "", + "--table", + "nat", + add ? "--insert" : "--delete", + "POSTROUTING", + "--source", + str_subnet, + "!", + "--destination", + str_subnet, + "--jump", + "MASQUERADE", + "-m", + "comment", + "--comment", + comment_name); +} + +static void +_share_iptables_set_shared_chains_add(const char *chain_input, + const char *chain_forward, + const char *ip_iface, + in_addr_t addr, + guint plen) +{ + const char *const input_params[][2] = { + { + "tcp", + "67", + }, + { + "udp", + "67", + }, + { + "tcp", + "53", + }, + { + "udp", + "53", + }, + }; + char str_subnet[_SHARE_IPTABLES_SUBNET_TO_STR_LEN]; + int i; + + _share_iptables_subnet_to_str(str_subnet, addr, plen); + + _share_iptables_chain_add("filter", chain_input); + + for (i = 0; i < (int) G_N_ELEMENTS(input_params); i++) { + _share_iptables_call("" IPTABLES_PATH "", + "--table", + "filter", + "--append", + chain_input, + "--protocol", + input_params[i][0], + "--destination-port", + input_params[i][1], + "--jump", + "ACCEPT"); + } + + _share_iptables_chain_add("filter", chain_forward); + + _share_iptables_call("" IPTABLES_PATH "", + "--table", + "filter", + "--append", + chain_forward, + "--destination", + str_subnet, + "--out-interface", + ip_iface, + "--match", + "state", + "--state", + "ESTABLISHED,RELATED", + "--jump", + "ACCEPT"); + _share_iptables_call("" IPTABLES_PATH "", + "--table", + "filter", + "--append", + chain_forward, + "--source", + str_subnet, + "--in-interface", + ip_iface, + "--jump", + "ACCEPT"); + _share_iptables_call("" IPTABLES_PATH "", + "--table", + "filter", + "--append", + chain_forward, + "--in-interface", + ip_iface, + "--out-interface", + ip_iface, + "--jump", + "ACCEPT"); + _share_iptables_call("" IPTABLES_PATH "", + "--table", + "filter", + "--append", + chain_forward, + "--out-interface", + ip_iface, + "--jump", + "REJECT"); + _share_iptables_call("" IPTABLES_PATH "", + "--table", + "filter", + "--append", + chain_forward, + "--in-interface", + ip_iface, + "--jump", + "REJECT"); +} + +static void +_share_iptables_set_shared_chains_delete(const char *chain_input, const char *chain_forward) +{ + _share_iptables_chain_delete("filter", chain_input); + _share_iptables_chain_delete("filter", chain_forward); +} + +_nm_unused static void +_share_iptables_set_shared(gboolean add, const char *ip_iface, in_addr_t addr, guint plen) +{ + gs_free char *comment_name = NULL; + gs_free char *chain_input = NULL; + gs_free char *chain_forward = NULL; + + comment_name = _share_iptables_get_name(FALSE, "nm-shared", ip_iface); + chain_input = _share_iptables_get_name(TRUE, "nm-sh-in", ip_iface); + chain_forward = _share_iptables_get_name(TRUE, "nm-sh-fw", ip_iface); + + if (add) + _share_iptables_set_shared_chains_add(chain_input, chain_forward, ip_iface, addr, plen); + + _share_iptables_call("" IPTABLES_PATH "", + "--table", + "filter", + add ? "--insert" : "--delete", + "INPUT", + "--in-interface", + ip_iface, + "--jump", + chain_input, + "-m", + "comment", + "--comment", + comment_name); + + _share_iptables_call("" IPTABLES_PATH "", + "--table", + "filter", + add ? "--insert" : "--delete", + "FORWARD", + "--jump", + chain_forward, + "-m", + "comment", + "--comment", + comment_name); + + if (!add) + _share_iptables_set_shared_chains_delete(chain_input, chain_forward); +} + +/*****************************************************************************/ + +typedef struct { + GTask * task; + GSubprocess * subprocess; + GSource * timeout_source; + GCancellable *intern_cancellable; + char * identifier; + gulong cancellable_id; +} FwNftCallData; + +static void +_fw_nft_call_data_free(FwNftCallData *call_data, GError *error_take) +{ + nm_clear_g_signal_handler(g_task_get_cancellable(call_data->task), &call_data->cancellable_id); + nm_clear_g_cancellable(&call_data->intern_cancellable); + nm_clear_g_source_inst(&call_data->timeout_source); + + if (error_take) + g_task_return_error(call_data->task, error_take); + else + g_task_return_boolean(call_data->task, TRUE); + + g_object_unref(call_data->task); + nm_g_object_unref(call_data->subprocess); + g_free(call_data->identifier); + + nm_g_slice_free(call_data); +} + +static void +_fw_nft_call_communicate_cb(GObject *source, GAsyncResult *result, gpointer user_data) +{ + FwNftCallData *call_data = user_data; + gs_free_error GError *error = NULL; + gs_unref_bytes GBytes *stdout_buf = NULL; + gs_unref_bytes GBytes *stderr_buf = NULL; + + nm_assert(source == (gpointer) call_data->subprocess); + + if (!g_subprocess_communicate_finish(G_SUBPROCESS(source), + result, + &stdout_buf, + &stderr_buf, + &error)) { + /* on any error, the process might still be running. We need to abort it in + * the background... */ + if (!nm_utils_error_is_cancelled(error)) { + nm_log_dbg(LOGD_SHARING, + "firewall: nft[%s]: communication failed: %s. Kill process", + call_data->identifier, + error->message); + } else if (!call_data->timeout_source) { + nm_log_dbg(LOGD_SHARING, + "firewall: ntf[%s]: communication timed out. Kill process", + call_data->identifier); + nm_clear_error(&error); + nm_utils_error_set(&error, NM_UTILS_ERROR_UNKNOWN, "timeout communicating with nft"); + } else { + nm_log_dbg(LOGD_SHARING, + "firewall: ntf[%s]: communication cancelled. Kill process", + call_data->identifier); + } + + { + _nm_unused nm_auto_pop_gmaincontext GMainContext *main_context = + nm_g_main_context_push_thread_default_if_necessary(NULL); + + nm_shutdown_wait_obj_register_object(call_data->subprocess, "nft-terminate"); + G_STATIC_ASSERT_EXPR(200 < NM_SHUTDOWN_TIMEOUT_MS_WATCHDOG * 2 / 3); + nm_g_subprocess_terminate_in_background(call_data->subprocess, 200); + } + } else if (g_subprocess_get_successful(call_data->subprocess)) { + nm_log_dbg(LOGD_SHARING, "firewall: nft[%s]: command successful", call_data->identifier); + } else { + gs_free char *ss_stdout = NULL; + gs_free char *ss_stderr = NULL; + gboolean print_stdout = (stdout_buf && g_bytes_get_size(stdout_buf) > 0); + gboolean print_stderr = (stderr_buf && g_bytes_get_size(stderr_buf) > 0); + + nm_log_warn(LOGD_SHARING, + "firewall: nft[%s]: command failed:%s%s%s%s%s%s%s", + call_data->identifier, + print_stdout || print_stderr ? "" : " unknown reason", + NM_PRINT_FMT_QUOTED( + print_stdout, + " (stdout: \"", + nm_utils_buf_utf8safe_escape_bytes(stdout_buf, + NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, + &ss_stdout), + "\")", + ""), + NM_PRINT_FMT_QUOTED( + print_stderr, + " (stderr: \"", + nm_utils_buf_utf8safe_escape_bytes(stderr_buf, + NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, + &ss_stderr), + "\")", + "")); + } + + _fw_nft_call_data_free(call_data, g_steal_pointer(&error)); +} + +static void +_fw_nft_call_cancelled_cb(GCancellable *cancellable, gpointer user_data) +{ + FwNftCallData *call_data = user_data; + + if (call_data->cancellable_id == 0) + return; + + nm_log_dbg(LOGD_SHARING, "firewall: nft[%s]: operation cancelled", call_data->identifier); + + nm_clear_g_signal_handler(g_task_get_cancellable(call_data->task), &call_data->cancellable_id); + nm_clear_g_cancellable(&call_data->intern_cancellable); +} + +static gboolean +_fw_nft_call_timeout_cb(gpointer user_data) +{ + FwNftCallData *call_data = user_data; + + nm_clear_g_source_inst(&call_data->timeout_source); + nm_log_dbg(LOGD_SHARING, + "firewall: nft[%s]: cancel operation after timeout", + call_data->identifier); + + nm_clear_g_cancellable(&call_data->intern_cancellable); + return G_SOURCE_CONTINUE; +} + +static void +_fw_nft_call(GBytes * stdin_buf, + GCancellable * cancellable, + GAsyncReadyCallback callback, + gpointer callback_user_data) +{ + gs_unref_object GSubprocessLauncher *subprocess_launcher = NULL; + gs_free_error GError *error = NULL; + FwNftCallData * call_data; + + call_data = g_slice_new(FwNftCallData); + *call_data = (FwNftCallData){ + .task = nm_g_task_new(NULL, cancellable, _fw_nft_call, callback, callback_user_data), + .subprocess = NULL, + .timeout_source = NULL, + }; + + if (cancellable) { + call_data->cancellable_id = g_cancellable_connect(cancellable, + G_CALLBACK(_fw_nft_call_cancelled_cb), + call_data, + NULL); + if (call_data->cancellable_id == 0) { + nm_log_dbg(LOGD_SHARING, "firewall: nft: already cancelled"); + nm_utils_error_set_cancelled(&error, FALSE, NULL); + _fw_nft_call_data_free(call_data, g_steal_pointer(&error)); + return; + } + } + + subprocess_launcher = + g_subprocess_launcher_new(G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE + | G_SUBPROCESS_FLAGS_STDERR_PIPE); + g_subprocess_launcher_set_environ(subprocess_launcher, NM_STRV_EMPTY()); + + call_data->subprocess = g_subprocess_launcher_spawnv(subprocess_launcher, + NM_MAKE_STRV(NFT_PATH, "-f", "-"), + &error); + + if (!call_data->subprocess) { + nm_log_dbg(LOGD_SHARING, "firewall: nft: spawning nft failed: %s", error->message); + _fw_nft_call_data_free(call_data, g_steal_pointer(&error)); + return; + } + + call_data->identifier = g_strdup(g_subprocess_get_identifier(call_data->subprocess)); + + nm_log_dbg(LOGD_SHARING, "firewall: nft[%s]: communicate with nft", call_data->identifier); + + nm_shutdown_wait_obj_register_object(call_data->task, "nft-call"); + + call_data->intern_cancellable = g_cancellable_new(), + + g_subprocess_communicate_async(call_data->subprocess, + stdin_buf, + call_data->intern_cancellable, + _fw_nft_call_communicate_cb, + call_data); + + call_data->timeout_source = + nm_g_source_attach(nm_g_timeout_source_new((NM_SHUTDOWN_TIMEOUT_MS * 2) / 3, + G_PRIORITY_DEFAULT, + _fw_nft_call_timeout_cb, + call_data, + NULL), + g_task_get_context(call_data->task)); +} + +static gboolean +_fw_nft_call_finish(GAsyncResult *result, GError **error) +{ + g_return_val_if_fail(nm_g_task_is_valid(result, NULL, _fw_nft_call), FALSE); + + return g_task_propagate_boolean(G_TASK(result), error); +} + +/*****************************************************************************/ + +typedef struct { + GMainLoop *loop; + GError ** error; + gboolean success; +} FwNftCallSyncData; + +static void +_fw_nft_call_sync_done(GObject *source, GAsyncResult *result, gpointer user_data) +{ + FwNftCallSyncData *data = user_data; + + data->success = _fw_nft_call_finish(result, data->error); + g_main_loop_quit(data->loop); +} + +static gboolean +_fw_nft_call_sync(GBytes *stdin_buf, GError **error) +{ + nm_auto_pop_and_unref_gmaincontext GMainContext *main_context = + nm_g_main_context_push_thread_default(g_main_context_new()); + nm_auto_unref_gmainloop GMainLoop *main_loop = g_main_loop_new(main_context, FALSE); + FwNftCallSyncData data = (FwNftCallSyncData){ + .loop = main_loop, + .error = error, + }; + + _fw_nft_call(stdin_buf, NULL, _fw_nft_call_sync_done, &data); + + g_main_loop_run(main_loop); + return data.success; +} + +/*****************************************************************************/ + +static void +_fw_nft_set(gboolean add, const char *ip_iface, in_addr_t addr, guint8 plen) +{ + nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE); + gs_unref_bytes GBytes *stdin_buf = NULL; + gs_free char * table_name = NULL; + gs_free char * ss1 = NULL; + char str_subnet[_SHARE_IPTABLES_SUBNET_TO_STR_LEN]; + + table_name = _share_iptables_get_name(FALSE, "nm-shared", ip_iface); + + _share_iptables_subnet_to_str(str_subnet, addr, plen); + +#define _append(p_strbuf, fmt, ...) nm_str_buf_append_printf((p_strbuf), "" fmt "\n", ##__VA_ARGS__) + + _append(&strbuf, "add table inet %s", table_name); + _append(&strbuf, "%s table inet %s", add ? "flush" : "delete", table_name); + + if (add) { + _append(&strbuf, + "add chain inet %s nat_postrouting {" + " type nat hook postrouting priority 100; policy accept; " + "};", + table_name); + _append(&strbuf, + "add rule inet %s nat_postrouting ip saddr %s ip daddr != %s masquerade;", + table_name, + str_subnet, + str_subnet); + + /* This filter_input chain serves no real purpose, because "accept" only stops + * evaluation of the current rule. It cannot fully accept the packet. Since + * this chain has no other rules, it is useless in this form. + */ + /* + _append(&strbuf, + "add chain inet %s filter_input {" + " type filter hook input priority 0; policy accept; " + "};", + table_name); + _append(&strbuf, "add rule inet %s filter_input tcp dport { 67, 53 } accept;", table_name); + _append(&strbuf, "add rule inet %s filter_input udp dport { 67, 53 } accept;", table_name); + */ + + _append(&strbuf, + "add chain inet %s filter_forward {" + " type filter hook forward priority 0; policy accept; " + "};", + table_name); + _append(&strbuf, + "add rule inet %s filter_forward ip daddr %s oifname \"%s\" " + " ct state { established, related } accept;", + table_name, + str_subnet, + ip_iface); + _append(&strbuf, + "add rule inet %s filter_forward ip saddr %s iifname \"%s\" accept;", + table_name, + str_subnet, + ip_iface); + _append(&strbuf, + "add rule inet %s filter_forward iifname \"%s\" oifname \"%s\" accept;", + table_name, + ip_iface, + ip_iface); + _append(&strbuf, + "add rule inet %s filter_forward iifname \"%s\" reject;", + table_name, + ip_iface); + _append(&strbuf, + "add rule inet %s filter_forward oifname \"%s\" reject;", + table_name, + ip_iface); + } + + nm_log_trace(LOGD_SHARING, + "firewall: nft command: [ %s ]", + nm_utils_str_utf8safe_escape(nm_str_buf_get_str(&strbuf), + NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, + &ss1)); + + stdin_buf = g_bytes_new_static(nm_str_buf_get_str(&strbuf), strbuf.len); + + _fw_nft_call_sync(stdin_buf, NULL); +} + +/*****************************************************************************/ + +struct _NMFirewallConfig { + char * ip_iface; + in_addr_t addr; + guint8 plen; +}; + +NMFirewallConfig * +nm_firewall_config_new(const char *ip_iface, in_addr_t addr, guint8 plen) +{ + NMFirewallConfig *self; + + nm_assert(ip_iface); + nm_assert(addr != 0u); + nm_assert(plen <= 32); + + self = g_slice_new(NMFirewallConfig); + *self = (NMFirewallConfig){ + .ip_iface = g_strdup(ip_iface), + .addr = addr, + .plen = plen, + }; + return self; +} + +void +nm_firewall_config_free(NMFirewallConfig *self) +{ + if (!self) + return; + + g_free(self->ip_iface); + nm_g_slice_free(self); +} + +void +nm_firewall_config_apply(NMFirewallConfig *self, gboolean shared) +{ + switch (nm_firewall_utils_get_backend()) { + case NM_FIREWALL_BACKEND_IPTABLES: + _share_iptables_set_masquerade(shared, self->ip_iface, self->addr, self->plen); + _share_iptables_set_shared(shared, self->ip_iface, self->addr, self->plen); + break; + case NM_FIREWALL_BACKEND_NFTABLES: + _fw_nft_set(shared, self->ip_iface, self->addr, self->plen); + break; + case NM_FIREWALL_BACKEND_NONE: + break; + default: + nm_assert_not_reached(); + break; + } +} + +/*****************************************************************************/ + +static NMFirewallBackend +_firewall_backend_detect(void) +{ + if (g_file_test(NFT_PATH, G_FILE_TEST_IS_EXECUTABLE)) + return NM_FIREWALL_BACKEND_NFTABLES; + if (g_file_test(IPTABLES_PATH, G_FILE_TEST_IS_EXECUTABLE)) + return NM_FIREWALL_BACKEND_IPTABLES; + + return NM_FIREWALL_BACKEND_NFTABLES; +} + +NMFirewallBackend +nm_firewall_utils_get_backend(void) +{ + static int backend = NM_FIREWALL_BACKEND_UNKNOWN; + int b; + +again: + b = g_atomic_int_get(&backend); + if (b == NM_FIREWALL_BACKEND_UNKNOWN) { + gs_free char *conf_value = NULL; + gboolean detect; + int i; + + conf_value = + nm_config_data_get_value(NM_CONFIG_GET_DATA_ORIG, + NM_CONFIG_KEYFILE_GROUP_MAIN, + NM_CONFIG_KEYFILE_KEY_MAIN_FIREWALL_BACKEND, + NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY); + + if (conf_value) { + for (i = 0; i < (int) G_N_ELEMENTS(FirewallBackends); i++) { + if (!g_ascii_strcasecmp(conf_value, FirewallBackends[i].name)) { + b = (i + 1); + break; + } + } + } + + detect = (b == NM_FIREWALL_BACKEND_UNKNOWN); + if (detect) + b = _firewall_backend_detect(); + + nm_assert(NM_IN_SET(b, + NM_FIREWALL_BACKEND_NONE, + NM_FIREWALL_BACKEND_IPTABLES, + NM_FIREWALL_BACKEND_NFTABLES)); + + if (!g_atomic_int_compare_and_exchange(&backend, NM_FIREWALL_BACKEND_UNKNOWN, b)) + goto again; + + nm_log_dbg(LOGD_SHARING, + "firewall: use %s backend%s%s%s%s%s%s%s", + FirewallBackends[b - 1].name, + NM_PRINT_FMT_QUOTED(FirewallBackends[b - 1].path, + " (", + FirewallBackends[b - 1].path, + ")", + ""), + detect ? " (detected)" : "", + NM_PRINT_FMT_QUOTED(detect && conf_value, + " (invalid setting \"", + conf_value, + "\")", + "")); + } + + nm_assert(NM_IN_SET(b, + NM_FIREWALL_BACKEND_NONE, + NM_FIREWALL_BACKEND_IPTABLES, + NM_FIREWALL_BACKEND_NFTABLES)); + return b; +} diff --git a/src/core/nm-firewall-utils.h b/src/core/nm-firewall-utils.h new file mode 100644 index 00000000..3d6c8a69 --- /dev/null +++ b/src/core/nm-firewall-utils.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2004 - 2016 Red Hat, Inc. + * Copyright (C) 2005 - 2008 Novell, Inc. + */ + +#ifndef __NM_FIREWALL_UTILS_H__ +#define __NM_FIREWALL_UTILS_H__ + +typedef enum { + NM_FIREWALL_BACKEND_UNKNOWN, + NM_FIREWALL_BACKEND_NONE, + NM_FIREWALL_BACKEND_IPTABLES, + NM_FIREWALL_BACKEND_NFTABLES, +} NMFirewallBackend; + +NMFirewallBackend nm_firewall_utils_get_backend(void); + +/*****************************************************************************/ + +typedef struct _NMFirewallConfig NMFirewallConfig; + +NMFirewallConfig *nm_firewall_config_new(const char *ip_iface, in_addr_t addr, guint8 plen); + +void nm_firewall_config_free(NMFirewallConfig *self); + +void nm_firewall_config_apply(NMFirewallConfig *self, gboolean shared); + +#endif /* __NM_FIREWALL_UTILS_H__ */ diff --git a/src/core/nm-firewalld-manager.c b/src/core/nm-firewalld-manager.c new file mode 100644 index 00000000..c562d978 --- /dev/null +++ b/src/core/nm-firewalld-manager.c @@ -0,0 +1,623 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2011 - 2015 Red Hat, Inc. + */ + +#include "src/core/nm-default-daemon.h" + +#include "nm-firewalld-manager.h" + +#include "libnm-glib-aux/nm-dbus-aux.h" +#include "c-list/src/c-list.h" + +#include "NetworkManagerUtils.h" +#include "nm-dbus-manager.h" + +#define FIREWALL_DBUS_SERVICE "org.fedoraproject.FirewallD1" +#define FIREWALL_DBUS_PATH "/org/fedoraproject/FirewallD1" +#define FIREWALL_DBUS_INTERFACE_ZONE "org.fedoraproject.FirewallD1.zone" + +/*****************************************************************************/ + +enum { STATE_CHANGED, LAST_SIGNAL }; + +static guint signals[LAST_SIGNAL] = {0}; + +typedef struct { + GDBusConnection *dbus_connection; + + GCancellable *get_name_owner_cancellable; + + CList pending_calls; + + guint name_owner_changed_id; + + bool dbus_inited : 1; + bool running : 1; +} NMFirewalldManagerPrivate; + +struct _NMFirewalldManager { + GObject parent; + NMFirewalldManagerPrivate _priv; +}; + +struct _NMFirewalldManagerClass { + GObjectClass parent; +}; + +G_DEFINE_TYPE(NMFirewalldManager, nm_firewalld_manager, G_TYPE_OBJECT) + +#define NM_FIREWALLD_MANAGER_GET_PRIVATE(self) \ + _NM_GET_PRIVATE(self, NMFirewalldManager, NM_IS_FIREWALLD_MANAGER) + +/*****************************************************************************/ + +NM_DEFINE_SINGLETON_GETTER(NMFirewalldManager, nm_firewalld_manager_get, NM_TYPE_FIREWALLD_MANAGER); + +/*****************************************************************************/ + +typedef enum { + OPS_TYPE_ADD = 1, + OPS_TYPE_CHANGE, + OPS_TYPE_REMOVE, +} OpsType; + +struct _NMFirewalldManagerCallId { + CList lst; + + NMFirewalldManager *self; + + char *iface; + + NMFirewalldManagerAddRemoveCallback callback; + gpointer user_data; + + union { + struct { + GCancellable *cancellable; + GVariant * arg; + } dbus; + struct { + guint id; + } idle; + }; + + OpsType ops_type; + + bool is_idle : 1; +}; + +/*****************************************************************************/ + +static const char * +_ops_type_to_string(OpsType ops_type) +{ + switch (ops_type) { + case OPS_TYPE_ADD: + return "add"; + case OPS_TYPE_REMOVE: + return "remove"; + case OPS_TYPE_CHANGE: + return "change"; + } + nm_assert_not_reached(); + return NULL; +} + +#define _NMLOG_DOMAIN LOGD_FIREWALL +#define _NMLOG_PREFIX_NAME "firewall" +#define _NMLOG(level, call_id, ...) \ + G_STMT_START \ + { \ + if (nm_logging_enabled((level), (_NMLOG_DOMAIN))) { \ + NMFirewalldManagerCallId *_call_id = (call_id); \ + char _prefix_name[30]; \ + char _prefix_info[100]; \ + \ + _nm_log((level), \ + (_NMLOG_DOMAIN), \ + 0, \ + NULL, \ + NULL, \ + "%s: %s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + (self) != singleton_instance ? ({ \ + g_snprintf(_prefix_name, \ + sizeof(_prefix_name), \ + "%s[" NM_HASH_OBFUSCATE_PTR_FMT "]", \ + ""_NMLOG_PREFIX_NAME, \ + NM_HASH_OBFUSCATE_PTR(self)); \ + _prefix_name; \ + }) \ + : _NMLOG_PREFIX_NAME, \ + _call_id ? ({ \ + g_snprintf(_prefix_info, \ + sizeof(_prefix_info), \ + "[" NM_HASH_OBFUSCATE_PTR_FMT ",%s%s:%s%s%s]: ", \ + NM_HASH_OBFUSCATE_PTR(_call_id), \ + _ops_type_to_string(_call_id->ops_type), \ + _call_id->is_idle ? "*" : "", \ + NM_PRINT_FMT_QUOTE_STRING(_call_id->iface)); \ + _prefix_info; \ + }) \ + : "" _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } \ + G_STMT_END + +/*****************************************************************************/ + +static gboolean +_get_running(NMFirewalldManagerPrivate *priv) +{ + /* when starting, we need to asynchronously check whether there is + * a name owner. During that time we optimistically assume that the + * service is indeed running. That is the time when we queue the + * requests, and they will be started once the get-name-owner call + * returns. */ + return priv->running || (priv->dbus_connection && !priv->dbus_inited); +} + +gboolean +nm_firewalld_manager_get_running(NMFirewalldManager *self) +{ + g_return_val_if_fail(NM_IS_FIREWALLD_MANAGER(self), FALSE); + + return _get_running(NM_FIREWALLD_MANAGER_GET_PRIVATE(self)); +} + +/*****************************************************************************/ + +static NMFirewalldManagerCallId * +_cb_info_create(NMFirewalldManager * self, + OpsType ops_type, + const char * iface, + const char * zone, + NMFirewalldManagerAddRemoveCallback callback, + gpointer user_data) +{ + NMFirewalldManagerPrivate *priv = NM_FIREWALLD_MANAGER_GET_PRIVATE(self); + NMFirewalldManagerCallId * call_id; + + call_id = g_slice_new0(NMFirewalldManagerCallId); + + call_id->self = g_object_ref(self); + call_id->ops_type = ops_type; + call_id->iface = g_strdup(iface); + call_id->callback = callback; + call_id->user_data = user_data; + + if (_get_running(priv)) { + call_id->is_idle = FALSE; + call_id->dbus.arg = g_variant_new("(ss)", zone ?: "", iface); + } else + call_id->is_idle = TRUE; + + c_list_link_tail(&priv->pending_calls, &call_id->lst); + + return call_id; +} + +static void +_cb_info_complete(NMFirewalldManagerCallId *call_id, GError *error) +{ + c_list_unlink(&call_id->lst); + + if (call_id->callback) + call_id->callback(call_id->self, call_id, error, call_id->user_data); + + if (call_id->is_idle) + nm_clear_g_source(&call_id->idle.id); + else { + nm_g_variant_unref(call_id->dbus.arg); + nm_clear_g_cancellable(&call_id->dbus.cancellable); + } + g_free(call_id->iface); + g_object_unref(call_id->self); + nm_g_slice_free(call_id); +} + +static gboolean +_handle_idle_cb(gpointer user_data) +{ + NMFirewalldManager * self; + NMFirewalldManagerCallId *call_id = user_data; + + nm_assert(call_id); + nm_assert(NM_IS_FIREWALLD_MANAGER(call_id->self)); + nm_assert(call_id->is_idle); + nm_assert(c_list_contains(&NM_FIREWALLD_MANAGER_GET_PRIVATE(call_id->self)->pending_calls, + &call_id->lst)); + + self = call_id->self; + + _LOGD(call_id, "complete: fake success"); + + call_id->idle.id = 0; + + _cb_info_complete(call_id, NULL); + return G_SOURCE_REMOVE; +} + +static gboolean +_handle_idle_start(NMFirewalldManager *self, NMFirewalldManagerCallId *call_id) +{ + if (!call_id->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(call_id, "complete: drop request simulating success"); + _cb_info_complete(call_id, NULL); + return FALSE; + } + call_id->idle.id = g_idle_add(_handle_idle_cb, call_id); + return TRUE; +} + +static void +_handle_dbus_cb(GObject *source, GAsyncResult *result, gpointer user_data) +{ + NMFirewalldManager * self; + NMFirewalldManagerCallId *call_id; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *ret = NULL; + + ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error); + + if (!ret && nm_utils_error_is_cancelled(error)) + return; + + call_id = user_data; + + nm_assert(call_id); + nm_assert(NM_IS_FIREWALLD_MANAGER(call_id->self)); + nm_assert(!call_id->is_idle); + nm_assert(c_list_contains(&NM_FIREWALLD_MANAGER_GET_PRIVATE(call_id->self)->pending_calls, + &call_id->lst)); + + self = call_id->self; + + if (error) { + const char *non_error = NULL; + + g_dbus_error_strip_remote_error(error); + + switch (call_id->ops_type) { + case OPS_TYPE_ADD: + case OPS_TYPE_CHANGE: + non_error = "ZONE_ALREADY_SET"; + break; + case OPS_TYPE_REMOVE: + non_error = "UNKNOWN_INTERFACE"; + break; + } + if (error->message && non_error && g_str_has_prefix(error->message, non_error) + && NM_IN_SET(error->message[strlen(non_error)], '\0', ':')) { + _LOGD(call_id, "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(call_id, "complete: request failed (%s)", error->message); + } else + _LOGD(call_id, "complete: success"); + + g_clear_object(&call_id->dbus.cancellable); + + _cb_info_complete(call_id, error); +} + +static void +_handle_dbus_start(NMFirewalldManager *self, NMFirewalldManagerCallId *call_id) +{ + NMFirewalldManagerPrivate *priv = NM_FIREWALLD_MANAGER_GET_PRIVATE(self); + const char * dbus_method = NULL; + GVariant * arg; + + nm_assert(call_id); + nm_assert(priv->running); + nm_assert(!call_id->is_idle); + nm_assert(c_list_contains(&priv->pending_calls, &call_id->lst)); + + switch (call_id->ops_type) { + case OPS_TYPE_ADD: + dbus_method = "addInterface"; + break; + case OPS_TYPE_CHANGE: + dbus_method = "changeZoneOfInterface"; + break; + case OPS_TYPE_REMOVE: + dbus_method = "removeInterface"; + break; + } + nm_assert(dbus_method); + + arg = g_steal_pointer(&call_id->dbus.arg); + + nm_assert(arg && g_variant_is_floating(arg)); + + nm_assert(!call_id->dbus.cancellable); + + call_id->dbus.cancellable = g_cancellable_new(); + + g_dbus_connection_call(priv->dbus_connection, + FIREWALL_DBUS_SERVICE, + FIREWALL_DBUS_PATH, + FIREWALL_DBUS_INTERFACE_ZONE, + dbus_method, + arg, + NULL, + G_DBUS_CALL_FLAGS_NONE, + 10000, + call_id->dbus.cancellable, + _handle_dbus_cb, + call_id); +} + +static NMFirewalldManagerCallId * +_start_request(NMFirewalldManager * self, + OpsType ops_type, + const char * iface, + const char * zone, + NMFirewalldManagerAddRemoveCallback callback, + gpointer user_data) +{ + NMFirewalldManagerPrivate *priv; + NMFirewalldManagerCallId * call_id; + + g_return_val_if_fail(NM_IS_FIREWALLD_MANAGER(self), NULL); + g_return_val_if_fail(iface && *iface, NULL); + + priv = NM_FIREWALLD_MANAGER_GET_PRIVATE(self); + + call_id = _cb_info_create(self, ops_type, iface, zone, callback, user_data); + + _LOGD(call_id, + "firewall zone %s %s:%s%s%s%s", + _ops_type_to_string(call_id->ops_type), + iface, + NM_PRINT_FMT_QUOTED(zone, "\"", zone, "\"", "default"), + call_id->is_idle ? " (not running, simulate success)" + : (!priv->running ? " (waiting to initialize)" : "")); + + if (!call_id->is_idle) { + if (priv->running) + _handle_dbus_start(self, call_id); + if (!call_id->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 + * (this function never fails and always starts a request). */ + return NULL; + } + } else { + if (!_handle_idle_start(self, call_id)) { + /* 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. */ + return NULL; + } + } + + return call_id; +} + +NMFirewalldManagerCallId * +nm_firewalld_manager_add_or_change_zone(NMFirewalldManager *self, + const char * iface, + const char * zone, + gboolean add, /* TRUE == add, FALSE == change */ + NMFirewalldManagerAddRemoveCallback callback, + gpointer user_data) +{ + return _start_request(self, + add ? OPS_TYPE_ADD : OPS_TYPE_CHANGE, + iface, + zone, + callback, + user_data); +} + +NMFirewalldManagerCallId * +nm_firewalld_manager_remove_from_zone(NMFirewalldManager * self, + const char * iface, + const char * zone, + NMFirewalldManagerAddRemoveCallback callback, + gpointer user_data) +{ + return _start_request(self, OPS_TYPE_REMOVE, iface, zone, callback, user_data); +} + +void +nm_firewalld_manager_cancel_call(NMFirewalldManagerCallId *call_id) +{ + NMFirewalldManager * self; + NMFirewalldManagerPrivate *priv; + gs_free_error GError *error = NULL; + + g_return_if_fail(call_id); + g_return_if_fail(NM_IS_FIREWALLD_MANAGER(call_id->self)); + g_return_if_fail(!c_list_is_empty(&call_id->lst)); + + self = call_id->self; + priv = NM_FIREWALLD_MANAGER_GET_PRIVATE(self); + + nm_assert(c_list_contains(&priv->pending_calls, &call_id->lst)); + + nm_utils_error_set_cancelled(&error, FALSE, "NMFirewalldManager"); + + _LOGD(call_id, "complete: cancel (%s)", error->message); + + _cb_info_complete(call_id, error); +} + +/*****************************************************************************/ + +static void +name_owner_changed(NMFirewalldManager *self, const char *owner) +{ + _nm_unused gs_unref_object NMFirewalldManager *self_keep_alive = g_object_ref(self); + NMFirewalldManagerPrivate * priv = NM_FIREWALLD_MANAGER_GET_PRIVATE(self); + gboolean was_running; + gboolean now_running; + gboolean just_initied; + + owner = nm_str_not_empty(owner); + + if (!owner) + _LOGT(NULL, "D-Bus name for firewalld has no owner (firewall stopped)"); + else + _LOGT(NULL, "D-Bus name for firewalld has owner %s (firewall started)", owner); + + was_running = _get_running(priv); + just_initied = !priv->dbus_inited; + + priv->dbus_inited = TRUE; + priv->running = !!owner; + + now_running = _get_running(priv); + + if (just_initied) { + NMFirewalldManagerCallId *call_id_safe; + NMFirewalldManagerCallId *call_id; + + /* We kick of the requests that we have pending. Note that this is + * entirely asynchronous and also we don't invoke any callbacks for + * the user. + * Even _handle_idle_start() just schedules an idle handler. That is, + * because we don't want to callback to the user before emitting the + * DISCONNECTED signal below. Also, emitting callbacks means the user + * can call back to modify the list of pending-calls and we'd have + * to handle reentrancy. */ + c_list_for_each_entry_safe (call_id, call_id_safe, &priv->pending_calls, lst) { + nm_assert(!call_id->is_idle); + nm_assert(call_id->dbus.arg); + + if (priv->running) { + _LOGD(call_id, "initalizing: make D-Bus call"); + _handle_dbus_start(self, call_id); + } else { + /* we don't want to invoke callbacks to the user right away. That is because + * the user might schedule/cancel more calls, which messes up the order. + * + * Instead, convert the pending calls to idle requests... */ + nm_clear_pointer(&call_id->dbus.arg, g_variant_unref); + call_id->is_idle = TRUE; + _LOGD(call_id, "initializing: fake success on idle"); + _handle_idle_start(self, call_id); + } + } + } + + if (was_running != now_running) + g_signal_emit(self, signals[STATE_CHANGED], 0, FALSE); +} + +static void +name_owner_changed_cb(GDBusConnection *connection, + const char * sender_name, + const char * object_path, + const char * interface_name, + const char * signal_name, + GVariant * parameters, + gpointer user_data) +{ + NMFirewalldManager *self = user_data; + const char * new_owner; + + if (!g_variant_is_of_type(parameters, G_VARIANT_TYPE("(sss)"))) + return; + + g_variant_get(parameters, "(&s&s&s)", NULL, NULL, &new_owner); + + name_owner_changed(self, new_owner); +} + +static void +get_name_owner_cb(const char *name_owner, GError *error, gpointer user_data) +{ + NMFirewalldManager * self; + NMFirewalldManagerPrivate *priv; + + if (!name_owner && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = user_data; + priv = NM_FIREWALLD_MANAGER_GET_PRIVATE(self); + + g_clear_object(&priv->get_name_owner_cancellable); + + name_owner_changed(self, name_owner); +} + +/*****************************************************************************/ + +static void +nm_firewalld_manager_init(NMFirewalldManager *self) +{ + NMFirewalldManagerPrivate *priv = NM_FIREWALLD_MANAGER_GET_PRIVATE(self); + + c_list_init(&priv->pending_calls); + + priv->dbus_connection = nm_g_object_ref(NM_MAIN_DBUS_CONNECTION_GET); + + if (!priv->dbus_connection) { + _LOGD(NULL, "no D-Bus connection"); + return; + } + + priv->name_owner_changed_id = + nm_dbus_connection_signal_subscribe_name_owner_changed(priv->dbus_connection, + FIREWALL_DBUS_SERVICE, + name_owner_changed_cb, + self, + NULL); + + priv->get_name_owner_cancellable = g_cancellable_new(); + nm_dbus_connection_call_get_name_owner(priv->dbus_connection, + FIREWALL_DBUS_SERVICE, + -1, + priv->get_name_owner_cancellable, + get_name_owner_cb, + self); +} + +static void +dispose(GObject *object) +{ + NMFirewalldManager * self = NM_FIREWALLD_MANAGER(object); + NMFirewalldManagerPrivate *priv = NM_FIREWALLD_MANAGER_GET_PRIVATE(self); + + /* as every pending operation takes a reference to the manager, + * we don't expect pending operations at this point. */ + nm_assert(c_list_is_empty(&priv->pending_calls)); + + nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->name_owner_changed_id); + + nm_clear_g_cancellable(&priv->get_name_owner_cancellable); + + G_OBJECT_CLASS(nm_firewalld_manager_parent_class)->dispose(object); + + g_clear_object(&priv->dbus_connection); +} + +static void +nm_firewalld_manager_class_init(NMFirewalldManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + + object_class->dispose = dispose; + + signals[STATE_CHANGED] = g_signal_new(NM_FIREWALLD_MANAGER_STATE_CHANGED, + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, + 1, + G_TYPE_BOOLEAN /* initialized_now */); +} diff --git a/src/core/nm-firewalld-manager.h b/src/core/nm-firewalld-manager.h new file mode 100644 index 00000000..febb9bac --- /dev/null +++ b/src/core/nm-firewalld-manager.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2011 Red Hat, Inc. + */ + +#ifndef __NM_FIREWALLD_MANAGER_H__ +#define __NM_FIREWALLD_MANAGER_H__ + +#define NM_TYPE_FIREWALLD_MANAGER (nm_firewalld_manager_get_type()) +#define NM_FIREWALLD_MANAGER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_FIREWALLD_MANAGER, NMFirewalldManager)) +#define NM_FIREWALLD_MANAGER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_FIREWALLD_MANAGER, NMFirewalldManagerClass)) +#define NM_IS_FIREWALLD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_FIREWALLD_MANAGER)) +#define NM_IS_FIREWALLD_MANAGER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_FIREWALLD_MANAGER)) +#define NM_FIREWALLD_MANAGER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_FIREWALLD_MANAGER, NMFirewalldManagerClass)) + +#define NM_FIREWALLD_MANAGER_STATE_CHANGED "state-changed" + +typedef struct _NMFirewalldManagerCallId NMFirewalldManagerCallId; + +typedef struct _NMFirewalldManager NMFirewalldManager; +typedef struct _NMFirewalldManagerClass NMFirewalldManagerClass; + +GType nm_firewalld_manager_get_type(void); + +NMFirewalldManager *nm_firewalld_manager_get(void); + +gboolean nm_firewalld_manager_get_running(NMFirewalldManager *self); + +typedef void (*NMFirewalldManagerAddRemoveCallback)(NMFirewalldManager * self, + NMFirewalldManagerCallId *call_id, + GError * error, + gpointer user_data); + +NMFirewalldManagerCallId * +nm_firewalld_manager_add_or_change_zone(NMFirewalldManager * mgr, + const char * iface, + const char * zone, + gboolean add, + NMFirewalldManagerAddRemoveCallback callback, + gpointer user_data); +NMFirewalldManagerCallId * +nm_firewalld_manager_remove_from_zone(NMFirewalldManager * mgr, + const char * iface, + const char * zone, + NMFirewalldManagerAddRemoveCallback callback, + gpointer user_data); + +void nm_firewalld_manager_cancel_call(NMFirewalldManagerCallId *call_id); + +#endif /* __NM_FIREWALLD_MANAGER_H__ */ diff --git a/src/core/nm-hostname-manager.c b/src/core/nm-hostname-manager.c index c99c8326..91e9baaa 100644 --- a/src/core/nm-hostname-manager.c +++ b/src/core/nm-hostname-manager.c @@ -14,11 +14,11 @@ #include #endif -#include "nm-libnm-core-intern/nm-common-macros.h" +#include "libnm-core-aux-intern/nm-common-macros.h" #include "nm-dbus-interface.h" #include "nm-connection.h" #include "nm-utils.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "NetworkManagerUtils.h" @@ -182,7 +182,7 @@ nm_hostname_manager_read_hostname(NMHostnameManager *self) #if defined(HOSTNAME_PERSIST_GENTOO) hostname = read_hostname_gentoo(HOSTNAME_FILE); #elif defined(HOSTNAME_PERSIST_SLACKWARE) - hostname = read_hostname_slackware(HOSTNAME_FILE); + hostname = read_hostname_slackware(HOSTNAME_FILE); #else if (g_file_get_contents(HOSTNAME_FILE, &hostname, NULL, NULL)) g_strchomp(hostname); diff --git a/src/core/nm-iface-helper.c b/src/core/nm-iface-helper.c index b6e9981d..296bf091 100644 --- a/src/core/nm-iface-helper.c +++ b/src/core/nm-iface-helper.c @@ -16,19 +16,19 @@ #include #include -#include "nm-glib-aux/nm-c-list.h" +#include "libnm-glib-aux/nm-c-list.h" #include "main-utils.h" #include "NetworkManagerUtils.h" -#include "platform/nm-linux-platform.h" -#include "nm-platform/nm-platform-utils.h" +#include "libnm-platform/nm-linux-platform.h" +#include "libnm-platform/nm-platform-utils.h" #include "dhcp/nm-dhcp-manager.h" #include "ndisc/nm-ndisc.h" #include "ndisc/nm-lndp-ndisc.h" #include "nm-utils.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-setting-ip6-config.h" -#include "systemd/nm-sd.h" +#include "libnm-systemd-core/nm-sd.h" #if !defined(NM_DIST_VERSION) #define NM_DIST_VERSION VERSION @@ -668,6 +668,7 @@ main(int argc, char *argv[]) global_opt.uuid, RT_TABLE_MAIN, global_opt.priority_v4, + NM_DHCP_CLIENT_FLAGS_NONE, !!global_opt.dhcp4_hostname, global_opt.dhcp4_hostname, global_opt.dhcp4_fqdn, diff --git a/src/core/nm-ip4-config.c b/src/core/nm-ip4-config.c index c49dfb4c..47f0ee3a 100644 --- a/src/core/nm-ip4-config.c +++ b/src/core/nm-ip4-config.c @@ -12,14 +12,14 @@ #include #include -#include "nm-glib-aux/nm-dedup-multi.h" +#include "libnm-glib-aux/nm-dedup-multi.h" #include "nm-utils.h" -#include "platform/nmp-object.h" -#include "platform/nm-platform.h" -#include "nm-platform/nm-platform-utils.h" +#include "libnm-platform/nmp-object.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-platform/nm-platform-utils.h" #include "NetworkManagerUtils.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-dbus-object.h" /*****************************************************************************/ @@ -649,21 +649,6 @@ nm_ip4_config_add_dependent_routes(NMIP4Config *self, if (my_addr->external) continue; - /* Pre-generate local route added by kernel */ - r = nmp_object_new(NMP_OBJECT_TYPE_IP4_ROUTE, NULL); - route = NMP_OBJECT_CAST_IP4_ROUTE(r); - route->ifindex = ifindex; - route->rt_source = NM_IP_CONFIG_SOURCE_KERNEL; - route->network = my_addr->address; - route->plen = 32; - route->pref_src = my_addr->address; - route->type_coerced = nm_platform_route_type_coerce(RTN_LOCAL); - route->scope_inv = nm_platform_route_scope_inv(RT_SCOPE_HOST); - route->table_coerced = - nm_platform_route_table_coerce(is_vrf ? route_table : RT_TABLE_LOCAL); - _add_route(self, r, NULL, NULL); - nm_clear_pointer(&r, nmp_object_unref); - if (nm_utils_ip4_address_is_zeronet(network)) { /* Kernel doesn't add device-routes for destinations that * start with 0.x.y.z. Skip them. */ @@ -1992,6 +1977,26 @@ nm_ip_config_dump(const NMIPConfig *self, const char *detail, NMLogLevel level, /*****************************************************************************/ +gconstpointer +nm_ip_config_find_first_address(const NMIPConfig *self, NMPlatformMatchFlags match_flag) +{ + NMDedupMultiIter iter; + const NMPlatformIPAddress *address; + + g_return_val_if_fail(NM_IS_IP_CONFIG(self), NULL); + + nm_assert(!NM_FLAGS_ANY( + match_flag, + ~(NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY | NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY))); + + nm_ip_config_iter_ip_address_for_each (&iter, self, &address) { + if (nm_platform_ip_address_match(nm_ip_config_get_addr_family(self), address, match_flag)) + return address; + } + + return NULL; +} + void nm_ip4_config_reset_addresses(NMIP4Config *self) { @@ -3031,11 +3036,9 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) g_value_take_variant(value, g_variant_builder_end(&builder_data)); break; case PROP_NAMESERVERS: - g_value_take_variant(value, - g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, - priv->nameservers->data, - priv->nameservers->len, - sizeof(guint32))); + g_value_take_variant( + value, + nm_g_variant_new_au((const guint32 *) priv->nameservers->data, priv->nameservers->len)); break; case PROP_DOMAINS: nm_utils_g_value_set_strv(value, priv->domains); @@ -3060,11 +3063,9 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) g_value_take_variant(value, g_variant_builder_end(&builder_data)); break; case PROP_WINS_SERVERS: - g_value_take_variant(value, - g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, - priv->wins->data, - priv->wins->len, - sizeof(guint32))); + g_value_take_variant( + value, + nm_g_variant_new_au((const guint32 *) priv->wins->data, priv->wins->len)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); @@ -3162,44 +3163,40 @@ finalize(GObject *object) static const NMDBusInterfaceInfoExtended interface_info_ip4_config = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_IP4_CONFIG, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Addresses", - "aau", - NM_IP4_CONFIG_ADDRESSES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("AddressData", - "aa{sv}", - NM_IP4_CONFIG_ADDRESS_DATA), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Gateway", "s", NM_IP4_CONFIG_GATEWAY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Routes", "aau", NM_IP4_CONFIG_ROUTES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("RouteData", - "aa{sv}", - NM_IP4_CONFIG_ROUTE_DATA), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Addresses", + "aau", + NM_IP4_CONFIG_ADDRESSES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("AddressData", + "aa{sv}", + NM_IP4_CONFIG_ADDRESS_DATA), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Gateway", "s", NM_IP4_CONFIG_GATEWAY), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Routes", "aau", NM_IP4_CONFIG_ROUTES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("RouteData", + "aa{sv}", + NM_IP4_CONFIG_ROUTE_DATA), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("NameserverData", "aa{sv}", NM_IP4_CONFIG_NAMESERVER_DATA), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Nameservers", - "au", - NM_IP4_CONFIG_NAMESERVERS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Domains", - "as", - NM_IP4_CONFIG_DOMAINS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Searches", - "as", - NM_IP4_CONFIG_SEARCHES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("DnsOptions", - "as", - NM_IP4_CONFIG_DNS_OPTIONS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("DnsPriority", - "i", - NM_IP4_CONFIG_DNS_PRIORITY), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Nameservers", + "au", + NM_IP4_CONFIG_NAMESERVERS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Domains", "as", NM_IP4_CONFIG_DOMAINS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Searches", + "as", + NM_IP4_CONFIG_SEARCHES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("DnsOptions", + "as", + NM_IP4_CONFIG_DNS_OPTIONS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("DnsPriority", + "i", + NM_IP4_CONFIG_DNS_PRIORITY), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("WinsServerData", "as", NM_IP4_CONFIG_WINS_SERVER_DATA), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("WinsServers", - "au", - NM_IP4_CONFIG_WINS_SERVERS), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("WinsServers", + "au", + NM_IP4_CONFIG_WINS_SERVERS), ), ), }; static void diff --git a/src/core/nm-ip4-config.h b/src/core/nm-ip4-config.h index a795e152..fdaa6d46 100644 --- a/src/core/nm-ip4-config.h +++ b/src/core/nm-ip4-config.h @@ -10,8 +10,8 @@ #include "nm-setting-ip4-config.h" -#include "nm-glib-aux/nm-dedup-multi.h" -#include "platform/nmp-object.h" +#include "libnm-glib-aux/nm-dedup-multi.h" +#include "libnm-platform/nmp-object.h" #include "nm-ip-config.h" /*****************************************************************************/ @@ -664,4 +664,7 @@ nm_ip_config_intersect_alloc(const NMIPConfig *a, } } +gconstpointer nm_ip_config_find_first_address(const NMIPConfig * self, + NMPlatformMatchFlags match_flag); + #endif /* __NETWORKMANAGER_IP4_CONFIG_H__ */ diff --git a/src/core/nm-ip6-config.c b/src/core/nm-ip6-config.c index 1f7def34..d2ecf175 100644 --- a/src/core/nm-ip6-config.c +++ b/src/core/nm-ip6-config.c @@ -13,13 +13,13 @@ #include #include -#include "nm-glib-aux/nm-dedup-multi.h" +#include "libnm-glib-aux/nm-dedup-multi.h" #include "nm-utils.h" -#include "platform/nmp-object.h" -#include "platform/nm-platform.h" -#include "nm-platform/nm-platform-utils.h" -#include "nm-core-internal.h" +#include "libnm-platform/nmp-object.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-platform/nm-platform-utils.h" +#include "libnm-core-intern/nm-core-internal.h" #include "NetworkManagerUtils.h" #include "nm-ip4-config.h" #include "ndisc/nm-ndisc.h" @@ -396,23 +396,6 @@ nm_ip6_config_add_dependent_routes(NMIP6Config *self, * * For manually added IPv6 routes, add the device routes explicitly. */ - /* Pre-generate multicast route */ - { - nm_auto_nmpobj NMPObject *r = NULL; - NMPlatformIP6Route * route; - - r = nmp_object_new(NMP_OBJECT_TYPE_IP6_ROUTE, NULL); - route = NMP_OBJECT_CAST_IP6_ROUTE(r); - route->ifindex = ifindex; - route->network.s6_addr[0] = 0xffu; - route->plen = 8; - route->table_coerced = nm_platform_route_table_coerce(RT_TABLE_LOCAL); - route->type_coerced = nm_platform_route_type_coerce(RTN_UNICAST); - route->metric = 256; - - _add_route(self, r, NULL, NULL); - } - nm_ip_config_iter_ip6_address_for_each (&iter, self, &my_addr) { NMPlatformIP6Route *route; gboolean has_peer; @@ -421,22 +404,6 @@ nm_ip6_config_add_dependent_routes(NMIP6Config *self, if (my_addr->external) continue; - { - nm_auto_nmpobj NMPObject *r = NULL; - - /* Pre-generate local route added by kernel */ - r = nmp_object_new(NMP_OBJECT_TYPE_IP6_ROUTE, NULL); - route = NMP_OBJECT_CAST_IP6_ROUTE(r); - route->ifindex = ifindex; - route->network = my_addr->address; - route->plen = 128; - route->type_coerced = nm_platform_route_type_coerce(RTN_LOCAL); - route->metric = 0; - route->table_coerced = - nm_platform_route_table_coerce(is_vrf ? route_table : RT_TABLE_LOCAL); - _add_route(self, r, NULL, NULL); - } - if (NM_FLAGS_HAS(my_addr->n_ifa_flags, IFA_F_NOPREFIXROUTE)) continue; if (my_addr->plen == 0) @@ -1661,28 +1628,6 @@ nm_ip6_config_lookup_address(const NMIP6Config *self, const struct in6_addr *add return entry ? NMP_OBJECT_CAST_IP6_ADDRESS(entry->obj) : NULL; } -const NMPlatformIP6Address * -nm_ip6_config_find_first_address(const NMIP6Config *self, NMPlatformMatchFlags match_flag) -{ - const NMPlatformIP6Address *addr; - NMDedupMultiIter iter; - - g_return_val_if_fail(NM_IS_IP6_CONFIG(self), NULL); - - nm_assert(!NM_FLAGS_ANY( - match_flag, - ~(NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY | NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY))); - - nm_assert(NM_FLAGS_ANY(match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY)); - nm_assert(NM_FLAGS_ANY(match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY)); - - nm_ip_config_iter_ip6_address_for_each (&iter, self, &addr) { - if (nm_platform_ip6_address_match(addr, match_flag)) - return addr; - } - return NULL; -} - /** * nm_ip6_config_has_dad_pending_addresses * @self: configuration containing the addresses to check @@ -2442,9 +2387,7 @@ nameservers_to_gvalue(GArray *array, GValue *value) struct in6_addr *addr; 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_variant_builder_add(&builder, "@ay", nm_g_variant_new_ay_in6addr(addr)); } g_value_take_variant(value, g_variant_builder_end(&builder)); @@ -2620,37 +2563,33 @@ finalize(GObject *object) static const NMDBusInterfaceInfoExtended interface_info_ip6_config = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_IP6_CONFIG, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Addresses", - "a(ayuay)", - NM_IP6_CONFIG_ADDRESSES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("AddressData", - "aa{sv}", - NM_IP6_CONFIG_ADDRESS_DATA), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Gateway", "s", NM_IP6_CONFIG_GATEWAY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Routes", - "a(ayuayu)", - NM_IP6_CONFIG_ROUTES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("RouteData", - "aa{sv}", - NM_IP6_CONFIG_ROUTE_DATA), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Nameservers", - "aay", - NM_IP6_CONFIG_NAMESERVERS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Domains", - "as", - NM_IP6_CONFIG_DOMAINS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Searches", - "as", - NM_IP6_CONFIG_SEARCHES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("DnsOptions", - "as", - NM_IP6_CONFIG_DNS_OPTIONS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("DnsPriority", - "i", - NM_IP6_CONFIG_DNS_PRIORITY), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Addresses", + "a(ayuay)", + NM_IP6_CONFIG_ADDRESSES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("AddressData", + "aa{sv}", + NM_IP6_CONFIG_ADDRESS_DATA), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Gateway", "s", NM_IP6_CONFIG_GATEWAY), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Routes", + "a(ayuayu)", + NM_IP6_CONFIG_ROUTES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("RouteData", + "aa{sv}", + NM_IP6_CONFIG_ROUTE_DATA), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Nameservers", + "aay", + NM_IP6_CONFIG_NAMESERVERS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Domains", "as", NM_IP6_CONFIG_DOMAINS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Searches", + "as", + NM_IP6_CONFIG_SEARCHES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("DnsOptions", + "as", + NM_IP6_CONFIG_DNS_OPTIONS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("DnsPriority", + "i", + NM_IP6_CONFIG_DNS_PRIORITY), ), ), }; static void diff --git a/src/core/nm-ip6-config.h b/src/core/nm-ip6-config.h index 398186da..8694ab0c 100644 --- a/src/core/nm-ip6-config.h +++ b/src/core/nm-ip6-config.h @@ -10,8 +10,8 @@ #include "nm-setting-ip6-config.h" -#include "nm-glib-aux/nm-dedup-multi.h" -#include "platform/nmp-object.h" +#include "libnm-glib-aux/nm-dedup-multi.h" +#include "libnm-platform/nmp-object.h" #include "nm-ip-config.h" /*****************************************************************************/ @@ -125,8 +125,6 @@ void _nmtst_ip6_config_del_address(NMIP6Config *self, guint i); guint nm_ip6_config_get_num_addresses(const NMIP6Config *self); const NMPlatformIP6Address *nm_ip6_config_get_first_address(const NMIP6Config *self); const NMPlatformIP6Address *_nmtst_ip6_config_get_address(const NMIP6Config *self, guint i); -const NMPlatformIP6Address *nm_ip6_config_find_first_address(const NMIP6Config * self, - NMPlatformMatchFlags match_flag); gboolean nm_ip6_config_address_exists(const NMIP6Config *self, const NMPlatformIP6Address *address); const NMPlatformIP6Address *nm_ip6_config_lookup_address(const NMIP6Config * self, const struct in6_addr *addr); diff --git a/src/core/nm-keep-alive.c b/src/core/nm-keep-alive.c index 197e30ea..6275544c 100644 --- a/src/core/nm-keep-alive.c +++ b/src/core/nm-keep-alive.c @@ -8,7 +8,7 @@ #include "nm-keep-alive.h" #include "settings/nm-settings-connection.h" -#include "nm-glib-aux/nm-dbus-aux.h" +#include "libnm-glib-aux/nm-dbus-aux.h" /*****************************************************************************/ diff --git a/src/core/nm-l3-config-data.c b/src/core/nm-l3-config-data.c index 5f9af7ac..f2ec040b 100644 --- a/src/core/nm-l3-config-data.c +++ b/src/core/nm-l3-config-data.c @@ -8,11 +8,12 @@ #include #include -#include "nm-glib-aux/nm-enum-utils.h" -#include "nm-core-internal.h" -#include "platform/nm-platform.h" -#include "nm-platform/nm-platform-utils.h" -#include "platform/nmp-object.h" +#include "libnm-core-intern/nm-core-internal.h" +#include "libnm-glib-aux/nm-enum-utils.h" +#include "libnm-glib-aux/nm-ref-string.h" +#include "libnm-platform/nm-platform-utils.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-platform/nmp-object.h" #include "NetworkManagerUtils.h" /*****************************************************************************/ @@ -52,7 +53,9 @@ struct _NML3ConfigData { GArray *wins; GArray *nis_servers; - char *nis_domain; + NMRefString *nis_domain; + NMRefString *proxy_pac_url; + NMRefString *proxy_pac_script; union { struct { @@ -130,6 +133,10 @@ struct _NML3ConfigData { NMTernary metered : 3; + NMTernary proxy_browser_only : 3; + + NMProxyConfigMethod proxy_method : 4; + NMSettingIP6ConfigPrivacy ip6_privacy : 4; bool is_sealed : 1; @@ -251,7 +258,7 @@ _garray_inaddr_get(GArray *arr, guint *out_len) } static gconstpointer -_garray_inaddr_at(GArray *arr, guint idx, gboolean IS_IPv4) +_garray_inaddr_at(GArray *arr, gboolean IS_IPv4, guint idx) { nm_assert(arr); nm_assert(idx < arr->len); @@ -507,7 +514,7 @@ nm_l3_config_data_log(const NML3ConfigData *self, _nm_utils_inet4_ntop(g_array_index(self->nis_servers, in_addr_t, i), sbuf_addr)); } if (self->nis_domain) - _L("nis-domain: %s", self->nis_domain); + _L("nis-domain: %s", self->nis_domain->str); } if (self->dhcp_lease_x[IS_IPv4]) { @@ -556,10 +563,20 @@ nm_l3_config_data_log(const NML3ConfigData *self, NULL))); } - if (self->metered != NM_TERNARY_DEFAULT) { + if (self->metered != NM_TERNARY_DEFAULT) _L("metered: %s", self->metered ? "yes" : "no"); - } + if (self->proxy_browser_only != NM_TERNARY_DEFAULT) + _L("proxy-browser-only: %s", self->proxy_browser_only ? "yes" : "no"); + + if (self->proxy_method != NM_PROXY_CONFIG_METHOD_UNKNOWN) + _L("proxy-method: %s", self->proxy_method == NM_PROXY_CONFIG_METHOD_AUTO ? "auto" : "none"); + + if (self->proxy_pac_url) + _L("proxy-pac-url: %s", self->proxy_pac_url->str); + + if (self->proxy_pac_script) + _L("proxy-pac-script: %s", self->proxy_pac_script->str); #undef _L } @@ -642,6 +659,8 @@ nm_l3_config_data_new(NMDedupMultiIndex *multi_idx, int ifindex) .llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT, .flags = NM_L3_CONFIG_DAT_FLAGS_NONE, .metered = NM_TERNARY_DEFAULT, + .proxy_browser_only = NM_TERNARY_DEFAULT, + .proxy_method = NM_PROXY_CONFIG_METHOD_UNKNOWN, .route_table_sync_4 = NM_IP_ROUTE_TABLE_SYNC_MODE_NONE, .route_table_sync_6 = NM_IP_ROUTE_TABLE_SYNC_MODE_NONE, .source = NM_IP_CONFIG_SOURCE_UNKNOWN, @@ -742,7 +761,9 @@ nm_l3_config_data_unref(const NML3ConfigData *self) nm_dedup_multi_index_unref(mutable->multi_idx); - g_free(mutable->nis_domain); + nm_ref_string_unref(mutable->nis_domain); + nm_ref_string_unref(mutable->proxy_pac_url); + nm_ref_string_unref(mutable->proxy_pac_script); nm_g_slice_free(mutable); } @@ -796,8 +817,8 @@ nm_l3_config_data_lookup_route(const NML3ConfigData * self, int addr_family, const NMPlatformIPRoute *needle) { - const gboolean IS_IPv4 = NM_IS_IPv4(addr_family); - NMPObject obj_stack; + const int IS_IPv4 = NM_IS_IPv4(addr_family); + NMPObject obj_stack; nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); nm_assert_addr_family(addr_family); @@ -895,7 +916,7 @@ nmtst_l3_config_data_get_obj_at(const NML3ConfigData *self, NMPObjectType obj_ty gboolean nm_l3_config_data_has_routes_with_type_local(const NML3ConfigData *self, int addr_family) { - const gboolean IS_IPv4 = NM_IS_IPv4(addr_family); + const int IS_IPv4 = NM_IS_IPv4(addr_family); NML3ConfigData * self_mutable; NMDedupMultiIter iter; const NMPObject *obj; @@ -1178,7 +1199,7 @@ _l3_config_best_default_route_find_better(const NMPObject *obj_cur, const NMPObj return c < 0 ? obj_cur : obj_cmp; /* as last resort, compare pointers. */ - if (((uintptr_t)((void *) (obj_cmp))) < ((uintptr_t)((void *) (obj_cur)))) + if (((uintptr_t) ((void *) (obj_cmp))) < ((uintptr_t) ((void *) (obj_cur)))) return obj_cmp; } } @@ -1230,7 +1251,7 @@ nm_l3_config_data_add_route_full(NML3ConfigData * self, const NMPObject ** out_obj_new, gboolean * out_changed_best_default_route) { - const gboolean IS_IPv4 = NM_IS_IPv4(addr_family); + const int IS_IPv4 = NM_IS_IPv4(addr_family); nm_auto_nmpobj const NMPObject *obj_old = NULL; const NMPObject * obj_new_2; gboolean changed = FALSE; @@ -1364,6 +1385,14 @@ nm_l3_config_data_add_wins(NML3ConfigData *self, in_addr_t wins) return _garray_inaddr_add(&self->wins, AF_INET, &wins); } +const in_addr_t * +nm_l3_config_data_get_nis_servers(const NML3ConfigData *self, guint *out_len) +{ + nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); + + return _garray_inaddr_get(self->nis_servers, out_len); +} + gboolean nm_l3_config_data_add_nis_server(NML3ConfigData *self, in_addr_t nis_server) { @@ -1372,18 +1401,26 @@ nm_l3_config_data_add_nis_server(NML3ConfigData *self, in_addr_t nis_server) return _garray_inaddr_add(&self->nis_servers, AF_INET, &nis_server); } +const char * +nm_l3_config_data_get_nis_domain(const NML3ConfigData *self) +{ + nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); + + return nm_ref_string_get_str(self->nis_domain); +} + gboolean nm_l3_config_data_set_nis_domain(NML3ConfigData *self, const char *nis_domain) { nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); - return nm_utils_strdup_reset(&self->nis_domain, nis_domain); + return nm_ref_string_reset_str(&self->nis_domain, nis_domain); } const char *const * nm_l3_config_data_get_domains(const NML3ConfigData *self, int addr_family, guint *out_len) { - nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); + nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); nm_assert_addr_family(addr_family); nm_assert(out_len); @@ -1452,10 +1489,57 @@ nm_l3_config_data_add_dns_option(NML3ConfigData *self, int addr_family, const ch return TRUE; } +const char *const * +nm_l3_config_data_get_dns_options(const NML3ConfigData *self, int addr_family, guint *out_len) +{ + nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); + nm_assert_addr_family(addr_family); + nm_assert(out_len); + + return nm_strv_ptrarray_get_unsafe(self->dns_options_x[NM_IS_IPv4(addr_family)], out_len); +} + +gboolean +nm_l3_config_data_get_dns_priority(const NML3ConfigData *self, int addr_family, int *out_prio) +{ + switch (addr_family) { + case AF_UNSPEC: + if (NM_FLAGS_ANY(self->flags, NM_L3_CONFIG_DAT_FLAGS_HAS_DNS_PRIORITY_4)) { + if (NM_FLAGS_ANY(self->flags, NM_L3_CONFIG_DAT_FLAGS_HAS_DNS_PRIORITY_6)) { + NM_SET_OUT(out_prio, MIN(self->dns_priority_4, self->dns_priority_6)); + return TRUE; + } + NM_SET_OUT(out_prio, self->dns_priority_4); + return TRUE; + } + if (NM_FLAGS_ANY(self->flags, NM_L3_CONFIG_DAT_FLAGS_HAS_DNS_PRIORITY_6)) { + NM_SET_OUT(out_prio, self->dns_priority_6); + return TRUE; + } + break; + case AF_INET: + if (NM_FLAGS_ANY(self->flags, NM_L3_CONFIG_DAT_FLAGS_HAS_DNS_PRIORITY_4)) { + NM_SET_OUT(out_prio, self->dns_priority_4); + return TRUE; + } + break; + case AF_INET6: + if (NM_FLAGS_ANY(self->flags, NM_L3_CONFIG_DAT_FLAGS_HAS_DNS_PRIORITY_6)) { + NM_SET_OUT(out_prio, self->dns_priority_6); + return TRUE; + } + break; + default: + nm_assert_not_reached(); + } + NM_SET_OUT(out_prio, 0); + return FALSE; +} + gboolean nm_l3_config_data_set_dns_priority(NML3ConfigData *self, int addr_family, int dns_priority) { - const gboolean IS_IPv4 = NM_IS_IPv4(addr_family); + const int IS_IPv4 = NM_IS_IPv4(addr_family); const NML3ConfigDatFlags has_dns_priority_flag = NM_L3_CONFIG_DAT_FLAGS_HAS_DNS_PRIORITY(IS_IPv4); @@ -1471,6 +1555,14 @@ nm_l3_config_data_set_dns_priority(NML3ConfigData *self, int addr_family, int dn return TRUE; } +NMSettingConnectionMdns +nm_l3_config_data_get_mdns(const NML3ConfigData *self) +{ + nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); + + return self->mdns; +} + gboolean nm_l3_config_data_set_mdns(NML3ConfigData *self, NMSettingConnectionMdns mdns) { @@ -1483,6 +1575,14 @@ nm_l3_config_data_set_mdns(NML3ConfigData *self, NMSettingConnectionMdns mdns) return TRUE; } +NMSettingConnectionLlmnr +nm_l3_config_data_get_llmnr(const NML3ConfigData *self) +{ + nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); + + return self->llmnr; +} + gboolean nm_l3_config_data_set_llmnr(NML3ConfigData *self, NMSettingConnectionLlmnr llmnr) { @@ -1509,7 +1609,7 @@ nm_l3_config_data_set_route_table_sync(NML3ConfigData * self, int addr_family, NMIPRouteTableSyncMode route_table_sync) { - const gboolean IS_IPv4 = NM_IS_IPv4(addr_family); + const int IS_IPv4 = NM_IS_IPv4(addr_family); nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); nm_assert_addr_family(addr_family); @@ -1533,7 +1633,7 @@ gboolean nm_l3_config_data_set_metered(NML3ConfigData *self, NMTernary metered) { nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); - nm_assert(NM_IN_SET(metered, NM_TERNARY_DEFAULT, NM_TERNARY_FALSE, NM_TERNARY_TRUE)); + nm_assert_is_ternary(metered); if (self->metered == metered) return FALSE; @@ -1619,6 +1719,83 @@ nm_l3_config_data_set_ip6_privacy(NML3ConfigData *self, NMSettingIP6ConfigPrivac return TRUE; } +NMProxyConfigMethod +nm_l3_config_data_get_proxy_method(const NML3ConfigData *self) +{ + nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); + + return self->proxy_method; +} + +gboolean +nm_l3_config_data_set_proxy_method(NML3ConfigData *self, NMProxyConfigMethod value) +{ + nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); + nm_assert(NM_IN_SET(value, + NM_PROXY_CONFIG_METHOD_UNKNOWN, + NM_PROXY_CONFIG_METHOD_NONE, + NM_PROXY_CONFIG_METHOD_AUTO)); + + if (self->proxy_method == value) + return FALSE; + + self->proxy_method = value; + return TRUE; +} + +NMTernary +nm_l3_config_data_get_proxy_browser_only(const NML3ConfigData *self) +{ + nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); + + return self->proxy_browser_only; +} + +gboolean +nm_l3_config_data_set_proxy_browser_only(NML3ConfigData *self, NMTernary value) +{ + nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); + nm_assert_is_ternary(value); + + if (value == self->proxy_browser_only) + return FALSE; + + self->proxy_browser_only = value; + return TRUE; +} + +const char * +nm_l3_config_data_get_proxy_pac_url(const NML3ConfigData *self) +{ + nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); + + return nm_ref_string_get_str(self->proxy_pac_url); +} + +gboolean +nm_l3_config_data_set_proxy_pac_url(NML3ConfigData *self, const char *value) +{ + nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); + + return nm_ref_string_reset_str(&self->proxy_pac_url, value); +} + +const char * +nm_l3_config_data_get_proxy_pac_script(const NML3ConfigData *self) +{ + nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE)); + + return nm_ref_string_get_str(self->proxy_pac_script); +} + +gboolean +nm_l3_config_data_set_proxy_pac_script(NML3ConfigData *self, const char *value) +{ + nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); + + return nm_ref_string_reset_str(&self->proxy_pac_script, value); +} + gboolean nm_l3_config_data_get_ndisc_hop_limit(const NML3ConfigData *self, int *out_val) { @@ -1780,13 +1957,16 @@ _dedup_multi_index_cmp(const NML3ConfigData *a, const NML3ConfigData *b, NMPObje } int -nm_l3_config_data_cmp(const NML3ConfigData *a, const NML3ConfigData *b) +nm_l3_config_data_cmp_full(const NML3ConfigData *a, + const NML3ConfigData *b, + NML3ConfigCmpFlags cmp_flags) { int IS_IPv4; NM_CMP_SELF(a, b); - NM_CMP_DIRECT(a->ifindex, b->ifindex); + if (!NM_FLAGS_HAS(cmp_flags, NM_L3_CONFIG_CMP_FLAGS_IGNORE_IFINDEX)) + NM_CMP_DIRECT(a->ifindex, b->ifindex); NM_CMP_DIRECT(a->flags, b->flags); @@ -1823,12 +2003,16 @@ nm_l3_config_data_cmp(const NML3ConfigData *a, const NML3ConfigData *b) NM_CMP_RETURN(_garray_inaddr_cmp(a->wins, b->wins, AF_INET)); NM_CMP_RETURN(_garray_inaddr_cmp(a->nis_servers, b->nis_servers, AF_INET)); - NM_CMP_FIELD_STR0(a, b, nis_domain); + NM_CMP_DIRECT_REF_STRING(a->nis_domain, b->nis_domain); NM_CMP_DIRECT(a->mdns, b->mdns); NM_CMP_DIRECT(a->llmnr, b->llmnr); NM_CMP_DIRECT(a->mtu, b->mtu); NM_CMP_DIRECT(a->ip6_mtu, b->ip6_mtu); NM_CMP_DIRECT_UNSAFE(a->metered, b->metered); + NM_CMP_DIRECT_UNSAFE(a->proxy_browser_only, b->proxy_browser_only); + NM_CMP_DIRECT_UNSAFE(a->proxy_method, b->proxy_method); + NM_CMP_DIRECT_REF_STRING(a->proxy_pac_url, b->proxy_pac_url); + NM_CMP_DIRECT_REF_STRING(a->proxy_pac_script, b->proxy_pac_script); NM_CMP_DIRECT_UNSAFE(a->ip6_privacy, b->ip6_privacy); NM_CMP_DIRECT_UNSAFE(a->ndisc_hop_limit_set, b->ndisc_hop_limit_set); @@ -1863,7 +2047,7 @@ _data_get_direct_route_for_host(const NML3ConfigData *self, gconstpointer host, guint32 route_table) { - const gboolean IS_IPv4 = NM_IS_IPv4(addr_family); + const int IS_IPv4 = NM_IS_IPv4(addr_family); const NMPObject * best_route_obj = NULL; const NMPlatformIPXRoute *best_route = NULL; const NMPObject * item_obj; @@ -1998,7 +2182,7 @@ nm_l3_config_data_add_dependent_routes(NML3ConfigData *self, guint32 route_metric, gboolean is_vrf) { - const gboolean IS_IPv4 = NM_IS_IPv4(addr_family); + const int IS_IPv4 = NM_IS_IPv4(addr_family); gs_unref_ptrarray GPtrArray *extra_onlink_routes = NULL; const NMPObject * my_addr_obj; const NMPObject * my_route_obj; @@ -2209,7 +2393,7 @@ _init_from_connection_ip(NML3ConfigData *self, guint32 route_table, guint32 route_metric) { - const gboolean IS_IPv4 = NM_IS_IPv4(addr_family); + const int IS_IPv4 = NM_IS_IPv4(addr_family); NMSettingIPConfig *s_ip; guint naddresses; guint nroutes; @@ -2388,11 +2572,28 @@ nm_l3_config_data_new_from_connection(NMDedupMultiIndex *multi_idx, guint32 route_metric_6) { NML3ConfigData *self; + NMSettingProxy *s_proxy; self = nm_l3_config_data_new(multi_idx, ifindex); _init_from_connection_ip(self, AF_INET, connection, route_table_4, route_metric_4); _init_from_connection_ip(self, AF_INET6, connection, route_table_6, route_metric_6); + + s_proxy = _nm_connection_get_setting(connection, NM_TYPE_SETTING_PROXY); + if (s_proxy) { + switch (nm_setting_proxy_get_method(s_proxy)) { + case NM_SETTING_PROXY_METHOD_NONE: + self->proxy_method = NM_PROXY_CONFIG_METHOD_NONE; + break; + case NM_SETTING_PROXY_METHOD_AUTO: + self->proxy_method = NM_PROXY_CONFIG_METHOD_AUTO; + self->proxy_pac_url = nm_ref_string_new(nm_setting_proxy_get_pac_url(s_proxy)); + self->proxy_pac_script = nm_ref_string_new(nm_setting_proxy_get_pac_script(s_proxy)); + break; + } + self->proxy_browser_only = (!!nm_setting_proxy_get_browser_only(s_proxy)); + } + return self; } @@ -2433,7 +2634,7 @@ _init_from_platform(NML3ConfigData * self, NMPlatform * platform, NMSettingIP6ConfigPrivacy ipv6_privacy_rfc4941) { - const gboolean IS_IPv4 = NM_IS_IPv4(addr_family); + const int IS_IPv4 = NM_IS_IPv4(addr_family); const NMDedupMultiHeadEntry *head_entry; const NMPObject * plobj = NULL; NMDedupMultiIter iter; @@ -2534,6 +2735,9 @@ nm_l3_config_data_merge(NML3ConfigData * self, nm_assert(default_route_table_x[1] != 0); nm_assert(default_route_metric_x[0] != 0); /* IPv6 route metric cannot be zero. */ + nm_assert(!NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_CLONE) + || nm_utils_is_power_of_two(merge_flags)); + for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) { const int addr_family = IS_IPv4 ? AF_INET : AF_INET6; const NML3ConfigDatFlags has_dns_priority_flag = @@ -2588,28 +2792,31 @@ nm_l3_config_data_merge(NML3ConfigData * self, } \ G_STMT_END - if (r_src->table_any) { - _ensure_r(); - r.rx.table_any = FALSE; - r.rx.table_coerced = default_route_table_x[IS_IPv4]; - } - - if (r_src->metric_any) { - _ensure_r(); - r.rx.metric_any = FALSE; - r.rx.metric = nm_add_clamped_u32(r.rx.metric, default_route_metric_x[IS_IPv4]); - } + if (!NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_CLONE)) { + if (r_src->table_any) { + _ensure_r(); + r.rx.table_any = FALSE; + r.rx.table_coerced = default_route_table_x[IS_IPv4]; + } - if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(r_src)) { - if (NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_NO_DEFAULT_ROUTES) - && !NM_FLAGS_HAS(src->flags, - NM_L3_CONFIG_DAT_FLAGS_IGNORE_MERGE_NO_DEFAULT_ROUTES)) - continue; - if (default_route_penalty_x && default_route_penalty_x[IS_IPv4] > 0) { + if (r_src->metric_any) { _ensure_r(); + r.rx.metric_any = FALSE; r.rx.metric = - nm_utils_ip_route_metric_penalize(r.rx.metric, - default_route_penalty_x[IS_IPv4]); + nm_add_clamped_u32(r.rx.metric, default_route_metric_x[IS_IPv4]); + } + + if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(r_src)) { + if (NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_NO_DEFAULT_ROUTES) + && !NM_FLAGS_HAS(src->flags, + NM_L3_CONFIG_DAT_FLAGS_IGNORE_MERGE_NO_DEFAULT_ROUTES)) + continue; + if (default_route_penalty_x && default_route_penalty_x[IS_IPv4] > 0) { + _ensure_r(); + r.rx.metric = + nm_utils_ip_route_metric_penalize(r.rx.metric, + default_route_penalty_x[IS_IPv4]); + } } } @@ -2653,8 +2860,8 @@ nm_l3_config_data_merge(NML3ConfigData * self, _garray_inaddr_merge(&self->wins, src->wins, AF_INET); _garray_inaddr_merge(&self->nis_servers, src->nis_servers, AF_INET); - if (!self->nis_domain && src->nis_domain) - self->nis_domain = g_strdup(src->nis_domain); + if (!self->nis_domain) + self->nis_domain = nm_ref_string_ref(src->nis_domain); } if (self->mdns == NM_SETTING_CONNECTION_MDNS_DEFAULT) @@ -2665,6 +2872,18 @@ nm_l3_config_data_merge(NML3ConfigData * self, self->metered = NM_MAX((NMTernary) self->metered, (NMTernary) src->metered); + if (self->proxy_method == NM_PROXY_CONFIG_METHOD_UNKNOWN) + self->proxy_method = src->proxy_method; + + if (self->proxy_browser_only == NM_TERNARY_DEFAULT) + self->proxy_browser_only = src->proxy_browser_only; + + if (!self->proxy_pac_url) + self->proxy_pac_url = nm_ref_string_ref(src->proxy_pac_url); + + if (!self->proxy_pac_script) + self->proxy_pac_script = nm_ref_string_ref(src->proxy_pac_script); + if (self->ip6_privacy == NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) self->ip6_privacy = src->ip6_privacy; @@ -2689,8 +2908,16 @@ nm_l3_config_data_merge(NML3ConfigData * self, if (self->ip6_mtu == 0u) self->ip6_mtu = src->ip6_mtu; - /* self->source does not get merged. */ - /* self->dhcp_lease_x does not get merged. */ + if (NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_CLONE)) { + _nm_unused nm_auto_unref_dhcplease NMDhcpLease *dhcp_lease_6 = + g_steal_pointer(&self->dhcp_lease_x[0]); + _nm_unused nm_auto_unref_dhcplease NMDhcpLease *dhcp_lease_4 = + g_steal_pointer(&self->dhcp_lease_x[1]); + + self->source = src->source; + self->dhcp_lease_x[0] = nm_dhcp_lease_ref(self->dhcp_lease_x[0]); + self->dhcp_lease_x[1] = nm_dhcp_lease_ref(self->dhcp_lease_x[1]); + } } NML3ConfigData * @@ -2707,6 +2934,17 @@ nm_l3_config_data_new_clone(const NML3ConfigData *src, int ifindex) ifindex = src->ifindex; self = nm_l3_config_data_new(src->multi_idx, ifindex); - nm_l3_config_data_merge(self, src, NM_L3_CONFIG_MERGE_FLAGS_NONE, NULL, NULL, NULL, NULL, NULL); + nm_l3_config_data_merge(self, + src, + NM_L3_CONFIG_MERGE_FLAGS_CLONE, + NULL, + NULL, + NULL, + NULL, + NULL); + + nm_assert(nm_l3_config_data_cmp_full(src, self, NM_L3_CONFIG_CMP_FLAGS_IGNORE_IFINDEX) == 0); + nm_assert(nm_l3_config_data_get_ifindex(self) == ifindex); + return self; } diff --git a/src/core/nm-l3-config-data.h b/src/core/nm-l3-config-data.h index b3d9cd32..9bed47e0 100644 --- a/src/core/nm-l3-config-data.h +++ b/src/core/nm-l3-config-data.h @@ -3,11 +3,17 @@ #ifndef __NM_L3_CONFIG_DATA_H__ #define __NM_L3_CONFIG_DATA_H__ -#include "nm-glib-aux/nm-dedup-multi.h" +#include "libnm-glib-aux/nm-dedup-multi.h" #include "nm-setting-connection.h" #include "nm-setting-ip6-config.h" -#include "platform/nm-platform.h" -#include "platform/nmp-object.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-platform/nmp-object.h" + +typedef enum { + NM_PROXY_CONFIG_METHOD_UNKNOWN, + NM_PROXY_CONFIG_METHOD_NONE, + NM_PROXY_CONFIG_METHOD_AUTO, +} NMProxyConfigMethod; typedef enum { NM_L3_CONFIG_DAT_FLAGS_NONE = 0, @@ -60,6 +66,8 @@ typedef enum { * Note that if the respective NML3ConfigData has NM_L3_CONFIG_DAT_FLAGS_IGNORE_MERGE_NO_DEFAULT_ROUTES * set, this flag gets ignored during merge. * @NM_L3_CONFIG_MERGE_FLAGS_NO_DNS: don't merge DNS information + * @NM_L3_CONFIG_MERGE_FLAGS_CLONE: clone is also implemented via "merge". + * In that case, it takes all settings. */ typedef enum _nm_packed { NM_L3_CONFIG_MERGE_FLAGS_NONE = 0, @@ -67,6 +75,7 @@ typedef enum _nm_packed { NM_L3_CONFIG_MERGE_FLAGS_NO_ROUTES = (1LL << 1), NM_L3_CONFIG_MERGE_FLAGS_NO_DEFAULT_ROUTES = (1LL << 2), NM_L3_CONFIG_MERGE_FLAGS_NO_DNS = (1LL << 3), + NM_L3_CONFIG_MERGE_FLAGS_CLONE = (1LL << 4), } NML3ConfigMergeFlags; /*****************************************************************************/ @@ -191,7 +200,20 @@ NMDedupMultiIndex *nm_l3_config_data_get_multi_idx(const NML3ConfigData *self); /*****************************************************************************/ -int nm_l3_config_data_cmp(const NML3ConfigData *a, const NML3ConfigData *b); +typedef enum { + NM_L3_CONFIG_CMP_FLAGS_NONE, + NM_L3_CONFIG_CMP_FLAGS_IGNORE_IFINDEX = (1LL << 0), +} NML3ConfigCmpFlags; + +int nm_l3_config_data_cmp_full(const NML3ConfigData *a, + const NML3ConfigData *b, + NML3ConfigCmpFlags cmp_flags); + +static inline int +nm_l3_config_data_cmp(const NML3ConfigData *a, const NML3ConfigData *b) +{ + return nm_l3_config_data_cmp_full(a, b, NM_L3_CONFIG_CMP_FLAGS_NONE); +} static inline gboolean nm_l3_config_data_equal(const NML3ConfigData *a, const NML3ConfigData *b) @@ -236,6 +258,11 @@ nm_l3_config_data_lookup_routes(const NML3ConfigData *self, int addr_family) for (nm_dedup_multi_iter_init((iter), nm_l3_config_data_lookup_objs((self), (type))); \ nm_platform_dedup_multi_iter_next_obj((iter), (obj), (type));) +#define nm_l3_config_data_iter_ip_address_for_each(iter, self, addr_family, address) \ + for (nm_dedup_multi_iter_init((iter), \ + nm_l3_config_data_lookup_addresses((self), (addr_family))); \ + nm_platform_dedup_multi_iter_next_ip_address((iter), (address));) + #define nm_l3_config_data_iter_ip4_address_for_each(iter, self, address) \ for (nm_dedup_multi_iter_init((iter), nm_l3_config_data_lookup_addresses((self), AF_INET)); \ nm_platform_dedup_multi_iter_next_ip4_address((iter), (address));) @@ -244,6 +271,10 @@ nm_l3_config_data_lookup_routes(const NML3ConfigData *self, int addr_family) for (nm_dedup_multi_iter_init((iter), nm_l3_config_data_lookup_addresses((self), AF_INET6)); \ nm_platform_dedup_multi_iter_next_ip6_address((iter), (address));) +#define nm_l3_config_data_iter_ip_route_for_each(iter, self, addr_family, route) \ + for (nm_dedup_multi_iter_init((iter), nm_l3_config_data_lookup_routes((self), (addr_family))); \ + nm_platform_dedup_multi_iter_next_ip_route((iter), (route));) + #define nm_l3_config_data_iter_ip4_route_for_each(iter, self, route) \ for (nm_dedup_multi_iter_init((iter), nm_l3_config_data_lookup_routes((self), AF_INET)); \ nm_platform_dedup_multi_iter_next_ip4_route((iter), (route));) @@ -409,8 +440,12 @@ nm_l3_config_data_add_route_6(NML3ConfigData *self, const NMPlatformIP6Route *rt const NMPObject *nm_l3_config_data_get_best_default_route(const NML3ConfigData *self, int addr_family); +NMSettingConnectionMdns nm_l3_config_data_get_mdns(const NML3ConfigData *self); + gboolean nm_l3_config_data_set_mdns(NML3ConfigData *self, NMSettingConnectionMdns mdns); +NMSettingConnectionLlmnr nm_l3_config_data_get_llmnr(const NML3ConfigData *self); + gboolean nm_l3_config_data_set_llmnr(NML3ConfigData *self, NMSettingConnectionLlmnr llmnr); NMIPRouteTableSyncMode nm_l3_config_data_get_route_table_sync(const NML3ConfigData *self, @@ -445,13 +480,17 @@ gboolean nm_l3_config_data_add_nameserver(NML3ConfigData * gboolean nm_l3_config_data_clear_nameservers(NML3ConfigData *self, int addr_family); +const in_addr_t *nm_l3_config_data_get_nis_servers(const NML3ConfigData *self, guint *out_len); + gboolean nm_l3_config_data_add_nis_server(NML3ConfigData *self, in_addr_t nis_server); -const char *const * -nm_l3_config_data_get_domains(const NML3ConfigData *self, int addr_family, guint *out_len); +const char *nm_l3_config_data_get_nis_domain(const NML3ConfigData *self); gboolean nm_l3_config_data_set_nis_domain(NML3ConfigData *self, const char *nis_domain); +const char *const * +nm_l3_config_data_get_domains(const NML3ConfigData *self, int addr_family, guint *out_len); + gboolean nm_l3_config_data_add_domain(NML3ConfigData *self, int addr_family, const char *domain); const char *const * @@ -464,6 +503,12 @@ gboolean nm_l3_config_data_add_search(NML3ConfigData *self, int addr_family, con gboolean nm_l3_config_data_add_dns_option(NML3ConfigData *self, int addr_family, const char *dns_option); +const char *const * +nm_l3_config_data_get_dns_options(const NML3ConfigData *self, int addr_family, guint *out_len); + +gboolean +nm_l3_config_data_get_dns_priority(const NML3ConfigData *self, int addr_family, int *out_prio); + gboolean nm_l3_config_data_set_dns_priority(NML3ConfigData *self, int addr_family, int dns_priority); @@ -472,6 +517,22 @@ NMSettingIP6ConfigPrivacy nm_l3_config_data_get_ip6_privacy(const NML3ConfigData gboolean nm_l3_config_data_set_ip6_privacy(NML3ConfigData * self, NMSettingIP6ConfigPrivacy ip6_privacy); +NMProxyConfigMethod nm_l3_config_data_get_proxy_method(const NML3ConfigData *self); + +gboolean nm_l3_config_data_set_proxy_method(NML3ConfigData *self, NMProxyConfigMethod value); + +NMTernary nm_l3_config_data_get_proxy_browser_only(const NML3ConfigData *self); + +gboolean nm_l3_config_data_set_proxy_browser_only(NML3ConfigData *self, NMTernary value); + +const char *nm_l3_config_data_get_proxy_pac_url(const NML3ConfigData *self); + +gboolean nm_l3_config_data_set_proxy_pac_url(NML3ConfigData *self, const char *value); + +const char *nm_l3_config_data_get_proxy_pac_script(const NML3ConfigData *self); + +gboolean nm_l3_config_data_set_proxy_pac_script(NML3ConfigData *self, const char *value); + gboolean nm_l3_config_data_get_ndisc_hop_limit(const NML3ConfigData *self, int *out_val); gboolean nm_l3_config_data_set_ndisc_hop_limit(NML3ConfigData *self, int val); diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c index 839213ad..93e92673 100644 --- a/src/core/nm-l3cfg.c +++ b/src/core/nm-l3cfg.c @@ -9,8 +9,9 @@ #include #include -#include "platform/nm-platform.h" -#include "platform/nmp-object.h" +#include "libnm-glib-aux/nm-time-utils.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-platform/nmp-object.h" #include "nm-netns.h" #include "n-acd/src/n-acd.h" #include "nm-l3-ipv4ll.h" @@ -21,7 +22,7 @@ G_STATIC_ASSERT(NM_ACD_TIMEOUT_RFC5227_MSEC == N_ACD_TIMEOUT_RFC5227); #define ACD_SUPPORTED_ETH_ALEN ETH_ALEN #define ACD_ENSURE_RATELIMIT_MSEC ((guint32) 4000u) -#define ACD_WAIT_PROBING_EXTRA_TIME_MSEC ((guint32)(1000u + ACD_ENSURE_RATELIMIT_MSEC)) +#define ACD_WAIT_PROBING_EXTRA_TIME_MSEC ((guint32) (1000u + ACD_ENSURE_RATELIMIT_MSEC)) #define ACD_WAIT_PROBING_EXTRA_TIME2_MSEC ((guint32) 1000u) #define ACD_MAX_TIMEOUT_MSEC ((guint32) 30000u) #define ACD_WAIT_TIME_PROBING_FULL_RESTART_MSEC ((guint32) 30000u) @@ -301,6 +302,7 @@ static NM_UTILS_ENUM2STR_DEFINE( NML3ConfigNotifyType, NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_ACD_EVENT, "acd-event"), NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_IPV4LL_EVENT, "ipv4ll-event"), + NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_L3CD_CHANGED, "l3cd-changed"), NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE, "platform-change"), NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE, "platform-change-on-idle"), NM_UTILS_ENUM2STR(NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT, "post-commit"), @@ -347,6 +349,7 @@ _l3_config_notify_data_to_string(const NML3ConfigNotifyData *notify_data, { char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; char sbuf100[100]; + char sbufobf[NM_HASH_OBFUSCATE_PTR_STR_BUF_SIZE]; char * s = sbuf; gsize l = sbuf_size; in_addr_t addr4; @@ -358,6 +361,19 @@ _l3_config_notify_data_to_string(const NML3ConfigNotifyData *notify_data, nm_utils_strbuf_seek_end(&s, &l); switch (notify_data->notify_type) { + case NM_L3_CONFIG_NOTIFY_TYPE_L3CD_CHANGED: + nm_utils_strbuf_append( + &s, + &l, + ", l3cd-old=%s", + NM_HASH_OBFUSCATE_PTR_STR(notify_data->l3cd_changed.l3cd_old, sbufobf)); + nm_utils_strbuf_append( + &s, + &l, + ", l3cd-new=%s", + NM_HASH_OBFUSCATE_PTR_STR(notify_data->l3cd_changed.l3cd_new, sbufobf)); + nm_utils_strbuf_append(&s, &l, ", commited=%d", notify_data->l3cd_changed.commited); + break; case NM_L3_CONFIG_NOTIFY_TYPE_ACD_EVENT: nm_utils_strbuf_append(&s, &l, @@ -423,6 +439,23 @@ _nm_l3cfg_emit_signal_notify_simple(NML3Cfg *self, NML3ConfigNotifyType notify_t _nm_l3cfg_emit_signal_notify(self, ¬ify_data); } +static void +_nm_l3cfg_emit_signal_notify_l3cd_changed(NML3Cfg * self, + const NML3ConfigData *l3cd_old, + const NML3ConfigData *l3cd_new, + gboolean commited) +{ + NML3ConfigNotifyData notify_data; + + notify_data.notify_type = NM_L3_CONFIG_NOTIFY_TYPE_L3CD_CHANGED; + notify_data.l3cd_changed = (typeof(notify_data.l3cd_changed)){ + .l3cd_old = l3cd_old, + .l3cd_new = l3cd_new, + .commited = commited, + }; + _nm_l3cfg_emit_signal_notify(self, ¬ify_data); +} + /*****************************************************************************/ static void @@ -1478,7 +1511,7 @@ _l3_acd_data_add(NML3Cfg * self, if (!acd_data) { if (G_UNLIKELY(!self->priv.p->acd_lst_hash)) { G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(AcdData, info.addr) == 0); - self->priv.p->acd_lst_hash = g_hash_table_new(nm_puint32_hash, nm_puint32_equals); + self->priv.p->acd_lst_hash = g_hash_table_new(nm_puint32_hash, nm_puint32_equal); } acd_data = g_slice_new(AcdData); @@ -2549,18 +2582,19 @@ _l3_commit_on_idle_cb(gpointer user_data) return G_SOURCE_REMOVE; } -void +gboolean nm_l3cfg_commit_on_idle_schedule(NML3Cfg *self) { nm_assert(NM_IS_L3CFG(self)); if (self->priv.p->commit_on_idle_source) - return; + return FALSE; _LOGT("commit on idle (scheduled)"); self->priv.p->commit_on_idle_source = nm_g_idle_source_new(G_PRIORITY_DEFAULT, _l3_commit_on_idle_cb, self, NULL); g_source_attach(self->priv.p->commit_on_idle_source, NULL); + return TRUE; } /*****************************************************************************/ @@ -3008,6 +3042,12 @@ _l3cfg_update_combined_config(NML3Cfg * self, l3cd_old = g_steal_pointer(&self->priv.p->combined_l3cd_merged); self->priv.p->combined_l3cd_merged = nm_l3_config_data_seal(g_steal_pointer(&l3cd)); merged_changed = TRUE; + + _nm_l3cfg_emit_signal_notify_l3cd_changed(self, + l3cd_old, + self->priv.p->combined_l3cd_merged, + FALSE); + if (!to_commit) { NM_SET_OUT(out_old, g_steal_pointer(&l3cd_old)); NM_SET_OUT(out_changed_combined_l3cd, TRUE); @@ -3019,6 +3059,12 @@ out: self->priv.p->combined_l3cd_commited = nm_l3_config_data_ref(self->priv.p->combined_l3cd_merged); commited_changed = TRUE; + + _nm_l3cfg_emit_signal_notify_l3cd_changed(self, + l3cd_commited_old, + self->priv.p->combined_l3cd_commited, + TRUE); + NM_SET_OUT(out_old, g_steal_pointer(&l3cd_commited_old)); NM_SET_OUT(out_changed_combined_l3cd, TRUE); } @@ -3652,6 +3698,23 @@ _nm_l3cfg_unregister_ipv4ll(NML3Cfg *self) /*****************************************************************************/ +gboolean +nm_l3cfg_is_ready(NML3Cfg *self) +{ + g_return_val_if_fail(NM_IS_L3CFG(self), FALSE); + + if (self->priv.p->changed_configs_configs) + return FALSE; + if (self->priv.p->changed_configs_acd_state) + return FALSE; + if (self->priv.p->commit_on_idle_source) + return FALSE; + + return TRUE; +} + +/*****************************************************************************/ + static void set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { diff --git a/src/core/nm-l3cfg.h b/src/core/nm-l3cfg.h index 5cfc93f6..037f2178 100644 --- a/src/core/nm-l3cfg.h +++ b/src/core/nm-l3cfg.h @@ -3,7 +3,7 @@ #ifndef __NM_L3CFG_H__ #define __NM_L3CFG_H__ -#include "platform/nmp-object.h" +#include "libnm-platform/nmp-object.h" #include "nm-l3-config-data.h" #define NM_L3CFG_CONFIG_PRIORITY_IPV4LL 0 @@ -88,11 +88,18 @@ nm_l3_acd_addr_info_find_track_info(const NML3AcdAddrInfo *addr_info, } typedef enum { + /* emitted when the merged/commited NML3ConfigData instance changes. + * Note that this gets emitted "under unsafe circumstances". That means, + * you should not perform complex operations inside this callback, + * and neither should you call into NML3Cfg again (reentrancy). */ + NM_L3_CONFIG_NOTIFY_TYPE_L3CD_CHANGED, + NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED, NM_L3_CONFIG_NOTIFY_TYPE_ACD_EVENT, - /* emitted at the end of nm_l3cfg_platform_commit(). */ + /* emitted at the end of nm_l3cfg_platform_commit(). This signals also that + * nm_l3cfg_is_ready() might have switched to TRUE. */ NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT, /* NML3Cfg hooks to the NMPlatform signals for link, addresses and routes. @@ -117,6 +124,12 @@ struct _NML3IPv4LL; typedef struct { NML3ConfigNotifyType notify_type; union { + struct { + const NML3ConfigData *l3cd_old; + const NML3ConfigData *l3cd_new; + bool commited; + } l3cd_changed; + struct { NML3AcdAddrInfo info; } acd_event; @@ -158,6 +171,8 @@ NML3Cfg *nm_l3cfg_new(NMNetns *netns, int ifindex); /*****************************************************************************/ +gboolean nm_l3cfg_is_ready(NML3Cfg *self); + void _nm_l3cfg_notify_platform_change_on_idle(NML3Cfg *self, guint32 obj_type_flags); void _nm_l3cfg_notify_platform_change(NML3Cfg * self, @@ -173,6 +188,8 @@ struct _NMDedupMultiIndex *nm_netns_get_multi_idx(NMNetns *self); static inline struct _NMDedupMultiIndex * nm_l3cfg_get_multi_idx(const NML3Cfg *self) { + g_return_val_if_fail(NM_IS_L3CFG(self), NULL); + return nm_netns_get_multi_idx(self->priv.netns); } @@ -181,7 +198,7 @@ nm_l3cfg_get_multi_idx(const NML3Cfg *self) static inline int nm_l3cfg_get_ifindex(const NML3Cfg *self) { - nm_assert(NM_IS_L3CFG(self)); + g_return_val_if_fail(NM_IS_L3CFG(self), 0); return self->priv.ifindex; } @@ -314,7 +331,7 @@ typedef enum _nm_packed { void nm_l3cfg_commit(NML3Cfg *self, NML3CfgCommitType commit_type); -void nm_l3cfg_commit_on_idle_schedule(NML3Cfg *self); +gboolean nm_l3cfg_commit_on_idle_schedule(NML3Cfg *self); /*****************************************************************************/ diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c index 5a6e05a9..b66f7fbb 100644 --- a/src/core/nm-manager.c +++ b/src/core/nm-manager.c @@ -16,15 +16,15 @@ #include #include -#include "nm-glib-aux/nm-c-list.h" +#include "libnm-glib-aux/nm-c-list.h" -#include "nm-libnm-core-intern/nm-common-macros.h" +#include "libnm-core-aux-intern/nm-common-macros.h" #include "nm-dbus-manager.h" #include "vpn/nm-vpn-manager.h" #include "devices/nm-device.h" #include "devices/nm-device-generic.h" -#include "platform/nm-platform.h" -#include "platform/nmp-object.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-platform/nmp-object.h" #include "nm-hostname-manager.h" #include "nm-keep-alive.h" #include "nm-rfkill-manager.h" @@ -40,10 +40,10 @@ #include "nm-policy.h" #include "nm-session-monitor.h" #include "nm-act-request.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-config.h" #include "nm-audit-manager.h" -#include "nm-std-aux/nm-dbus-compat.h" +#include "libnm-std-aux/nm-dbus-compat.h" #include "nm-checkpoint.h" #include "nm-checkpoint-manager.h" #include "nm-dbus-object.h" @@ -363,6 +363,7 @@ static NMActiveConnection *active_connection_find(NMManager * self, NMSettingsConnection * sett_conn, const char * uuid, NMActiveConnectionState max_state, + gboolean also_waiting_auth, GPtrArray ** out_all_matching); static NMConnectivity *concheck_get_mgr(NMManager *self); @@ -833,6 +834,7 @@ _delete_volatile_connection_do(NMManager *self, NMSettingsConnection *connection connection, NULL, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED, + TRUE, NULL)) return; @@ -978,6 +980,7 @@ active_connection_find( NMSettingsConnection * sett_conn, const char * uuid, NMActiveConnectionState max_state /* candidates in state @max_state will be found */, + gboolean also_waiting_auth /* return also ACs waiting authorization */, GPtrArray ** out_all_matching) { NMManagerPrivate * priv = NM_MANAGER_GET_PRIVATE(self); @@ -1017,11 +1020,14 @@ active_connection_find( if (!best_ac) { AsyncOpData *async_op_data; + if (!also_waiting_auth) + return NULL; + c_list_for_each_entry (async_op_data, &priv->async_op_lst_head, async_op_lst) { NMSettingsConnection *ac_conn; ac = async_op_data->ac_auth.active; - ac_conn = nm_active_connection_get_settings_connection(ac); + ac_conn = _nm_active_connection_get_settings_connection(ac); if (sett_conn && sett_conn != ac_conn) continue; if (uuid && !nm_streq0(uuid, nm_settings_connection_get_uuid(ac_conn))) @@ -1078,6 +1084,7 @@ active_connection_find_by_connection(NMManager * self, sett_conn, sett_conn ? NULL : nm_connection_get_uuid(connection), max_state, + FALSE, out_all_matching); } @@ -1112,6 +1119,7 @@ _get_activatable_connections_filter(NMSettings * settings, sett_conn, NULL, NM_ACTIVE_CONNECTION_STATE_ACTIVATED, + FALSE, NULL); } @@ -1305,7 +1313,7 @@ find_device_by_permanent_hw_addr(NMManager *self, const char *hwaddr) NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self); NMDevice * device; const char * device_addr; - guint8 hwaddr_bin[NM_UTILS_HWADDR_LEN_MAX]; + guint8 hwaddr_bin[_NM_UTILS_HWADDR_LEN_MAX]; gsize hwaddr_len; g_return_val_if_fail(hwaddr != NULL, NULL); @@ -1991,16 +1999,16 @@ nm_manager_remove_device(NMManager *self, const char *ifname, NMDeviceType devic static NMDevice * system_create_virtual_device(NMManager *self, NMConnection *connection) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self); - NMDeviceFactory * factory; - gs_free NMSettingsConnection **connections = NULL; - guint i; - gs_free char * iface = NULL; - const char * parent_spec; - NMDevice * device = NULL, *parent = NULL; - NMDevice * dev_candidate; - GError * error = NULL; - NMLogLevel log_level; + NMManagerPrivate * priv = NM_MANAGER_GET_PRIVATE(self); + NMDeviceFactory * factory; + NMSettingsConnection *const *connections; + guint i; + gs_free char * iface = NULL; + const char * parent_spec; + NMDevice * device = NULL, *parent = NULL; + NMDevice * dev_candidate; + GError * error = NULL; + NMLogLevel log_level; g_return_val_if_fail(NM_IS_MANAGER(self), NULL); g_return_val_if_fail(NM_IS_CONNECTION(connection), NULL); @@ -2083,13 +2091,7 @@ system_create_virtual_device(NMManager *self, NMConnection *connection) } /* Create backing resources if the device has any autoconnect connections */ - connections = nm_settings_get_connections_clone( - priv->settings, - NULL, - NULL, - NULL, - nm_settings_connection_cmp_autoconnect_priority_p_with_data, - NULL); + connections = nm_settings_get_connections_sorted_by_autoconnect_priority(priv->settings, NULL); for (i = 0; connections[i]; i++) { NMConnection * candidate = nm_settings_connection_get_connection(connections[i]); NMSettingConnection *s_con; @@ -2128,19 +2130,13 @@ system_create_virtual_device(NMManager *self, NMConnection *connection) static void retry_connections_for_parent_device(NMManager *self, NMDevice *device) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self); - gs_free NMSettingsConnection **connections = NULL; - guint i; + NMManagerPrivate * priv = NM_MANAGER_GET_PRIVATE(self); + NMSettingsConnection *const *connections; + guint i; g_return_if_fail(device); - connections = nm_settings_get_connections_clone( - priv->settings, - NULL, - NULL, - NULL, - nm_settings_connection_cmp_autoconnect_priority_p_with_data, - NULL); + connections = nm_settings_get_connections_sorted_by_autoconnect_priority(priv->settings, NULL); for (i = 0; connections[i]; i++) { NMSettingsConnection *sett_conn = connections[i]; NMConnection * connection = nm_settings_connection_get_connection(sett_conn); @@ -2245,6 +2241,7 @@ connection_flags_changed(NMSettings *settings, NMSettingsConnection *connection, connection, NULL, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED, + FALSE, NULL)) { /* the connection still has an active-connection. It will be purged * when the active connection(s) get(s) removed. */ @@ -2564,6 +2561,7 @@ new_activation_allowed_for_connection(NMManager *self, NMSettingsConnection *con connection, NULL, NM_ACTIVE_CONNECTION_STATE_ACTIVATED, + FALSE, NULL); } @@ -2839,14 +2837,16 @@ recheck_assume_connection(NMManager *self, NMDevice *device) g_return_val_if_fail(NM_IS_DEVICE(device), FALSE); if (!nm_device_get_managed(device, FALSE)) { - nm_device_assume_state_reset(device); + /* If the device is only unmanaged by NM_UNMANAGED_PLATFORM_INIT, + * don't reset the state now but wait until it becomes managed. */ + if (nm_device_get_unmanaged_flags(device, NM_UNMANAGED_ALL) != NM_UNMANAGED_PLATFORM_INIT) + nm_device_assume_state_reset(device); _LOG2D(LOGD_DEVICE, device, "assume: don't assume because %s", "not managed"); return FALSE; } state = nm_device_get_state(device); if (state > NM_DEVICE_STATE_DISCONNECTED) { - nm_device_assume_state_reset(device); _LOG2D(LOGD_DEVICE, device, "assume: don't assume due to device state %s", @@ -2892,15 +2892,16 @@ recheck_assume_connection(NMManager *self, NMDevice *device) NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL)); - nm_settings_connection_update(sett_conn, - con2, - NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP, - NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, - NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE - | NM_SETTINGS_CONNECTION_INT_FLAGS_EXTERNAL, - NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE, - "assume-initrd", - NULL); + nm_settings_connection_update( + sett_conn, + con2, + NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP, + NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, + NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE + | NM_SETTINGS_CONNECTION_INT_FLAGS_EXTERNAL, + NM_SETTINGS_CONNECTION_UPDATE_REASON_UPDATE_NON_SECRET, + "assume-initrd", + NULL); } } } @@ -3161,7 +3162,10 @@ _device_realize_finish(NMManager *self, NMDevice *device, const NMPlatformLink * nm_device_realize_finish(device, plink); if (!nm_device_get_managed(device, FALSE)) { - nm_device_assume_state_reset(device); + /* If the device is only unmanaged by NM_UNMANAGED_PLATFORM_INIT, + * don't reset the state now but wait until it becomes managed. */ + if (nm_device_get_unmanaged_flags(device, NM_UNMANAGED_ALL) != NM_UNMANAGED_PLATFORM_INIT) + nm_device_assume_state_reset(device); return; } @@ -3509,6 +3513,45 @@ typedef struct { guint idle_id; } PlatformLinkCbData; +static gboolean +_check_remove_dev_on_link_deleted(NMManager *self, NMDevice *device) +{ + NMManagerPrivate * priv = NM_MANAGER_GET_PRIVATE(self); + NMSettingsConnection *const *scons = NULL; + NMConnection * con; + guint i; + + nm_assert(nm_device_is_software(device)); + + /* In general, software devices stick around as unrealized + * until their connection is removed. However, we don't want + * that a NM-generated connection keeps the device alive. + * If there are no other compatible connections, the device + * should be also removed. + */ + + scons = nm_settings_get_connections(priv->settings, NULL); + + for (i = 0; scons[i]; i++) { + con = nm_settings_connection_get_connection(scons[i]); + if (!nm_connection_is_virtual(con)) + continue; + + if (NM_FLAGS_HAS(nm_settings_connection_get_flags(scons[i]), + NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) + continue; + + if (!nm_device_check_connection_compatible(device, con, NULL)) + continue; + + /* Found a virtual connection compatible, the device must + * stay around unrealized. */ + return FALSE; + } + + return TRUE; +} + static gboolean _platform_link_cb_idle(PlatformLinkCbData *data) { @@ -3534,13 +3577,15 @@ _platform_link_cb_idle(PlatformLinkCbData *data) if (device) { if (nm_device_is_software(device)) { nm_device_sys_iface_state_set(device, NM_DEVICE_SYS_IFACE_STATE_REMOVED); - /* Our software devices stick around until their connection is removed */ if (!nm_device_unrealize(device, FALSE, &error)) { _LOG2W(LOGD_DEVICE, device, "failed to unrealize: %s", error->message); g_clear_error(&error); remove_device(self, device, FALSE); } else { - nm_device_update_from_platform_link(device, NULL); + if (_check_remove_dev_on_link_deleted(self, device)) + remove_device(self, device, FALSE); + else + nm_device_update_from_platform_link(device, NULL); } } else { /* Hardware and external devices always get removed when their kernel link is gone */ @@ -4134,6 +4179,7 @@ find_master(NMManager * self, master_connection, NULL, NM_ACTIVE_CONNECTION_STATE_DEACTIVATING, + FALSE, NULL); } @@ -4367,13 +4413,13 @@ find_slaves(NMManager * manager, guint * out_n_slaves, gboolean for_user_request) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(manager); - gs_free NMSettingsConnection **all_connections = NULL; - guint n_all_connections; - guint i; - SlaveConnectionInfo * slaves = NULL; - guint n_slaves = 0; - NMSettingConnection * s_con; + NMManagerPrivate * priv = NM_MANAGER_GET_PRIVATE(manager); + NMSettingsConnection *const *all_connections = NULL; + guint n_all_connections; + guint i; + SlaveConnectionInfo * slaves = NULL; + guint n_slaves = 0; + NMSettingConnection * s_con; gs_unref_hashtable GHashTable *devices = NULL; nm_assert(out_n_slaves); @@ -4387,13 +4433,9 @@ find_slaves(NMManager * manager, * even if a slave was already active, it might be deactivated during * master reactivation. */ - all_connections = nm_settings_get_connections_clone( - priv->settings, - &n_all_connections, - NULL, - NULL, - nm_settings_connection_cmp_autoconnect_priority_p_with_data, - NULL); + all_connections = + nm_settings_get_connections_sorted_by_autoconnect_priority(priv->settings, + &n_all_connections); for (i = 0; i < n_all_connections; i++) { NMSettingsConnection *master_connection = NULL; NMDevice * master_device = NULL, *slave_device; @@ -4985,6 +5027,7 @@ _internal_activate_device(NMManager *self, NMActiveConnection *active, GError ** sett_conn, NULL, NM_ACTIVE_CONNECTION_STATE_ACTIVATED, + FALSE, &all_ac_arr); if (ac) { n_all = all_ac_arr ? all_ac_arr->len : ((guint) 1); @@ -5637,7 +5680,7 @@ activation_add_done(NMSettings * settings, result_floating = g_variant_new("(oo@a{sv})", nm_dbus_object_get_path(NM_DBUS_OBJECT(new_connection)), nm_dbus_object_get_path(NM_DBUS_OBJECT(active)), - g_variant_new_array(G_VARIANT_TYPE("{sv}"), NULL, 0)); + nm_g_variant_singleton_aLsvI()); } g_dbus_method_invocation_return_value(context, result_floating); @@ -6859,9 +6902,9 @@ devices_inited_cb(gpointer user_data) gboolean nm_manager_start(NMManager *self, GError **error) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self); - gs_free NMSettingsConnection **connections = NULL; - guint i; + NMManagerPrivate * priv = NM_MANAGER_GET_PRIVATE(self); + NMSettingsConnection *const *connections; + guint i; nm_device_factory_manager_load_factories(_register_device_factory, self); @@ -6919,13 +6962,7 @@ nm_manager_start(NMManager *self, GError **error) NM_SETTINGS_SIGNAL_CONNECTION_UPDATED, G_CALLBACK(connection_updated_cb), self); - connections = nm_settings_get_connections_clone( - priv->settings, - NULL, - NULL, - NULL, - nm_settings_connection_cmp_autoconnect_priority_p_with_data, - NULL); + connections = nm_settings_get_connections_sorted_by_autoconnect_priority(priv->settings, NULL); for (i = 0; connections[i]; i++) connection_changed(self, connections[i]); @@ -7102,6 +7139,85 @@ typedef struct { #define NM_PERM_DENIED_ERROR "org.freedesktop.NetworkManager.PermissionDenied" +static const char * +_dbus_set_property_audit_log_get_args(NMDBusObject *obj, + const char * property_name, + GVariant * value, + char ** str_to_free) +{ + nm_assert(str_to_free && !*str_to_free); + + /* We assert here that the property is one of the few expected ones. + * + * Future properties should not made writable! Add a D-Bus method instead, + * they are more flexible (for example, you can set multiple properties at + * once). */ + + if (NM_IS_DEVICE(obj)) { + nm_assert(NM_IN_STRSET(property_name, + NM_DEVICE_MANAGED, + NM_DEVICE_AUTOCONNECT, + NM_DEVICE_STATISTICS_REFRESH_RATE_MS)); + return (*str_to_free = g_variant_print(value, FALSE)); + } + + nm_assert(NM_IS_MANAGER(obj)); + if (NM_IN_STRSET(property_name, + NM_MANAGER_WIRELESS_ENABLED, + NM_MANAGER_WWAN_ENABLED, + NM_MANAGER_WIMAX_ENABLED, + NM_MANAGER_CONNECTIVITY_CHECK_ENABLED)) { + return (*str_to_free = g_strdup_printf("%s:%s", + property_name, + g_variant_get_boolean(value) ? "on" : "off")); + } + if (NM_IN_STRSET(property_name, NM_MANAGER_GLOBAL_DNS_CONFIGURATION)) { + return NM_MANAGER_GLOBAL_DNS_CONFIGURATION; + } + + return nm_assert_unreachable_val("???"); +} + +/* this is a macro to catch the caller's line number. */ +#define _dbus_set_property_audit_log(obj, \ + audit_op, \ + auth_subject, \ + property_name, \ + value, \ + error_message) \ + G_STMT_START \ + { \ + NMDBusObject *const _obj = (obj); \ + const char *const _audit_op = (audit_op); \ + NMAuthSubject *const _auth_subject = (auth_subject); \ + const char *const _property_name = (property_name); \ + GVariant *const _value = (value); \ + const char *const _error_message = (error_message); \ + gs_free char * _args_to_free = NULL; \ + \ + if (NM_IS_DEVICE(_obj)) { \ + nm_audit_log_device_op(_audit_op, \ + NM_DEVICE(_obj), \ + !_error_message, \ + _dbus_set_property_audit_log_get_args(_obj, \ + _property_name, \ + _value, \ + &_args_to_free), \ + _auth_subject, \ + _error_message); \ + } else { \ + nm_audit_log_control_op(_audit_op, \ + _dbus_set_property_audit_log_get_args(_obj, \ + _property_name, \ + _value, \ + &_args_to_free), \ + !_error_message, \ + _auth_subject, \ + _error_message); \ + } \ + } \ + G_STMT_END + static void _dbus_set_property_auth_cb(NMAuthChain * chain, GDBusMethodInvocation *invocation, @@ -7159,11 +7275,13 @@ _dbus_set_property_auth_cb(NMAuthChain * chain, g_value_unset(&gvalue); out: - nm_audit_log_control_op(property_info->writable.audit_op, - property_info->property_name, - !error_message, - nm_auth_chain_get_subject(chain), - error_message); + _dbus_set_property_audit_log(obj, + property_info->writable.audit_op, + nm_auth_chain_get_subject(chain), + property_info->property_name, + value, + error_message); + if (error_message) g_dbus_method_invocation_return_dbus_error(invocation, error_name, error_message); else @@ -7187,10 +7305,27 @@ nm_manager_dbus_set_property_handle(NMDBusObject * obj, gs_unref_object NMAuthSubject *subject = NULL; DBusSetPropertyHandle * handle_data; + /* we only have writable properties on Device or Manager. In the future, + * we probably should not add new API with writable properties. Add + * methods instead. Systemd also avoids writable properties. */ + nm_assert(obj == (gpointer) self || NM_IS_DEVICE(obj)); + subject = nm_dbus_manager_new_auth_subject_from_context(invocation); if (!subject) { error_message = NM_UTILS_ERROR_MSG_REQ_UID_UKNOWN; - goto err; + + _dbus_set_property_audit_log(obj, + property_info->writable.audit_op, + NULL, + property_info->property_name, + value, + error_message); + + g_dbus_method_invocation_return_error_literal(invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_AUTH_FAILED, + error_message); + return; } handle_data = g_slice_new0(DBusSetPropertyHandle); @@ -7204,18 +7339,6 @@ nm_manager_dbus_set_property_handle(NMDBusObject * obj, chain = nm_auth_chain_new_subject(subject, invocation, _dbus_set_property_auth_cb, handle_data); c_list_link_tail(&priv->auth_lst_head, nm_auth_chain_parent_lst_list(chain)); nm_auth_chain_add_call_unsafe(chain, property_info->writable.permission, TRUE); - return; - -err: - nm_audit_log_control_op(property_info->writable.audit_op, - property_info->property_name, - FALSE, - invocation, - error_message); - g_dbus_method_invocation_return_error_literal(invocation, - G_DBUS_ERROR, - G_DBUS_ERROR_AUTH_FAILED, - error_message); } /*****************************************************************************/ @@ -7854,10 +7977,8 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) break; case PROP_CAPABILITIES: g_value_set_variant(value, - g_variant_new_fixed_array(G_VARIANT_TYPE("u"), - priv->capabilities->data, - priv->capabilities->len, - sizeof(guint32))); + nm_g_variant_new_au((const guint32 *) priv->capabilities->data, + priv->capabilities->len)); break; case PROP_STATE: g_value_set_uint(value, priv->state); @@ -8297,76 +8418,74 @@ static const NMDBusInterfaceInfoExtended interface_info_manager = { NM_DEFINE_GDBUS_ARG_INFO("checkpoint", "o"), NM_DEFINE_GDBUS_ARG_INFO("add_timeout", "u"), ), ), .handle = impl_manager_checkpoint_adjust_rollback_timeout, ), ), - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, - &signal_info_check_permissions, + .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&signal_info_check_permissions, &signal_info_state_changed, &signal_info_device_added, &signal_info_device_removed, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Devices", "ao", NM_MANAGER_DEVICES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("AllDevices", - "ao", - NM_MANAGER_ALL_DEVICES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Checkpoints", - "ao", - NM_MANAGER_CHECKPOINTS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("NetworkingEnabled", - "b", - NM_MANAGER_NETWORKING_ENABLED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L( + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Devices", "ao", NM_MANAGER_DEVICES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("AllDevices", + "ao", + NM_MANAGER_ALL_DEVICES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Checkpoints", + "ao", + NM_MANAGER_CHECKPOINTS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("NetworkingEnabled", + "b", + NM_MANAGER_NETWORKING_ENABLED), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE( "WirelessEnabled", "b", NM_MANAGER_WIRELESS_ENABLED, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI, NM_AUDIT_OP_RADIO_CONTROL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("WirelessHardwareEnabled", - "b", - NM_MANAGER_WIRELESS_HARDWARE_ENABLED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L( + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("WirelessHardwareEnabled", + "b", + NM_MANAGER_WIRELESS_HARDWARE_ENABLED), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE( "WwanEnabled", "b", NM_MANAGER_WWAN_ENABLED, NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN, NM_AUDIT_OP_RADIO_CONTROL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("WwanHardwareEnabled", - "b", - NM_MANAGER_WWAN_HARDWARE_ENABLED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L( + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("WwanHardwareEnabled", + "b", + NM_MANAGER_WWAN_HARDWARE_ENABLED), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE( "WimaxEnabled", "b", NM_MANAGER_WIMAX_ENABLED, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX, NM_AUDIT_OP_RADIO_CONTROL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("WimaxHardwareEnabled", - "b", - NM_MANAGER_WIMAX_HARDWARE_ENABLED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("ActiveConnections", - "ao", - NM_MANAGER_ACTIVE_CONNECTIONS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("PrimaryConnection", - "o", - NM_MANAGER_PRIMARY_CONNECTION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("PrimaryConnectionType", - "s", - NM_MANAGER_PRIMARY_CONNECTION_TYPE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Metered", "u", NM_MANAGER_METERED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("ActivatingConnection", - "o", - NM_MANAGER_ACTIVATING_CONNECTION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Startup", "b", NM_MANAGER_STARTUP), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Version", "s", NM_MANAGER_VERSION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Capabilities", - "au", - NM_MANAGER_CAPABILITIES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("State", "u", NM_MANAGER_STATE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Connectivity", - "u", - NM_MANAGER_CONNECTIVITY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L( - "ConnectivityCheckAvailable", - "b", - NM_MANAGER_CONNECTIVITY_CHECK_AVAILABLE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L( + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("WimaxHardwareEnabled", + "b", + NM_MANAGER_WIMAX_HARDWARE_ENABLED), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("ActiveConnections", + "ao", + NM_MANAGER_ACTIVE_CONNECTIONS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("PrimaryConnection", + "o", + NM_MANAGER_PRIMARY_CONNECTION), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("PrimaryConnectionType", + "s", + NM_MANAGER_PRIMARY_CONNECTION_TYPE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Metered", "u", NM_MANAGER_METERED), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("ActivatingConnection", + "o", + NM_MANAGER_ACTIVATING_CONNECTION), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Startup", "b", NM_MANAGER_STARTUP), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Version", "s", NM_MANAGER_VERSION), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Capabilities", + "au", + NM_MANAGER_CAPABILITIES), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("State", "u", NM_MANAGER_STATE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Connectivity", + "u", + NM_MANAGER_CONNECTIVITY), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("ConnectivityCheckAvailable", + "b", + NM_MANAGER_CONNECTIVITY_CHECK_AVAILABLE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE( "ConnectivityCheckEnabled", "b", NM_MANAGER_CONNECTIVITY_CHECK_ENABLED, @@ -8375,13 +8494,12 @@ static const NMDBusInterfaceInfoExtended interface_info_manager = { NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("ConnectivityCheckUri", "s", NM_MANAGER_CONNECTIVITY_CHECK_URI), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L( + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE( "GlobalDnsConfiguration", "a{sv}", NM_MANAGER_GLOBAL_DNS_CONFIGURATION, NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS, NM_AUDIT_OP_NET_CONTROL), ), ), - .legacy_property_changed = TRUE, }; static void diff --git a/src/core/nm-netns.c b/src/core/nm-netns.c index 88ea09b6..d5a0317d 100644 --- a/src/core/nm-netns.c +++ b/src/core/nm-netns.c @@ -7,15 +7,15 @@ #include "nm-netns.h" -#include "nm-glib-aux/nm-dedup-multi.h" -#include "nm-glib-aux/nm-c-list.h" +#include "libnm-glib-aux/nm-dedup-multi.h" +#include "libnm-glib-aux/nm-c-list.h" #include "NetworkManagerUtils.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-l3cfg.h" -#include "platform/nm-platform.h" -#include "nm-platform/nmp-netns.h" -#include "platform/nmp-rules-manager.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-platform/nmp-netns.h" +#include "libnm-platform/nmp-rules-manager.h" /*****************************************************************************/ @@ -263,7 +263,7 @@ nm_netns_shared_ip_reserve(NMNetns *self) if (!priv->shared_ips) { addr = addr_start; - priv->shared_ips = g_hash_table_new(nm_puint32_hash, nm_puint32_equals); + priv->shared_ips = g_hash_table_new(nm_puint32_hash, nm_puint32_equal); g_object_ref(self); } else { guint32 count; @@ -392,7 +392,7 @@ constructed(GObject *object) if (!priv->platform) g_return_if_reached(); - priv->l3cfgs = g_hash_table_new_full(nm_pint_hash, nm_pint_equals, _l3cfg_data_free, NULL); + priv->l3cfgs = g_hash_table_new_full(nm_pint_hash, nm_pint_equal, _l3cfg_data_free, NULL); priv->platform_netns = nm_platform_netns_get(priv->platform); diff --git a/src/core/nm-netns.h b/src/core/nm-netns.h index aab3b520..78a9121a 100644 --- a/src/core/nm-netns.h +++ b/src/core/nm-netns.h @@ -6,7 +6,7 @@ #ifndef __NM_NETNS_H__ #define __NM_NETNS_H__ -#include "nm-platform/nmp-base.h" +#include "libnm-platform/nmp-base.h" #define NM_TYPE_NETNS (nm_netns_get_type()) #define NM_NETNS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_NETNS, NMNetns)) @@ -19,13 +19,15 @@ typedef struct _NMNetnsClass NMNetnsClass; +struct _NMPlatform; + GType nm_netns_get_type(void); NMNetns *nm_netns_get(void); -NMNetns *nm_netns_new(NMPlatform *platform); +NMNetns *nm_netns_new(struct _NMPlatform *platform); -NMPlatform *nm_netns_get_platform(NMNetns *self); -NMPNetns * nm_netns_get_platform_netns(NMNetns *self); +struct _NMPlatform *nm_netns_get_platform(NMNetns *self); +NMPNetns * nm_netns_get_platform_netns(NMNetns *self); struct _NMPRulesManager *nm_netns_get_rules_manager(NMNetns *self); diff --git a/src/core/nm-pacrunner-manager.c b/src/core/nm-pacrunner-manager.c index b58aef06..67930dba 100644 --- a/src/core/nm-pacrunner-manager.c +++ b/src/core/nm-pacrunner-manager.c @@ -9,13 +9,13 @@ #include "nm-utils.h" #include "NetworkManagerUtils.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-dbus-manager.h" #include "nm-proxy-config.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" #include "c-list/src/c-list.h" -#include "nm-glib-aux/nm-dbus-aux.h" +#include "libnm-glib-aux/nm-dbus-aux.h" #define PACRUNNER_DBUS_SERVICE "org.pacrunner" #define PACRUNNER_DBUS_INTERFACE "org.pacrunner.Manager" @@ -198,6 +198,7 @@ _make_request_create_proxy_configuration(NMProxyConfig *proxy_config, g_variant_builder_add(&builder, "{sv}", "Script", g_variant_new_string(pac_script)); } break; + case NM_PROXY_CONFIG_METHOD_UNKNOWN: case NM_PROXY_CONFIG_METHOD_NONE: g_variant_builder_add(&builder, "{sv}", "Method", g_variant_new_string("direct")); break; diff --git a/src/core/nm-policy.c b/src/core/nm-policy.c index db4983f8..e4914acf 100644 --- a/src/core/nm-policy.c +++ b/src/core/nm-policy.c @@ -17,14 +17,14 @@ #include "devices/nm-device.h" #include "nm-setting-ip4-config.h" #include "nm-setting-connection.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "dns/nm-dns-manager.h" #include "vpn/nm-vpn-manager.h" #include "nm-auth-utils.h" -#include "nm-firewall-manager.h" +#include "nm-firewalld-manager.h" #include "nm-dispatcher.h" #include "nm-utils.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-manager.h" #include "settings/nm-settings.h" #include "settings/nm-settings-connection.h" @@ -45,10 +45,10 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMPolicy, PROP_ACTIVATING_IP6_AC, ); typedef struct { - NMManager * manager; - NMNetns * netns; - NMFirewallManager *firewall_manager; - CList pending_activation_checks; + NMManager * manager; + NMNetns * netns; + NMFirewalldManager *firewalld_manager; + CList pending_activation_checks; NMAgentManager *agent_mgr; @@ -652,6 +652,7 @@ device_hostname_info_compare(gconstpointer a, gconstpointer b) NM_CMP_FIELD(info1, info2, priority); NM_CMP_FIELD_UNSAFE(info2, info1, is_default); + NM_CMP_FIELD_UNSAFE(info2, info1, IS_IPv4); return 0; } @@ -2003,19 +2004,12 @@ device_state_changed(NMDevice * device, nm_settings_connection_get_id(sett_conn)); } } - - nm_settings_connection_clear_secrets(sett_conn, FALSE, FALSE); } break; case NM_DEVICE_STATE_ACTIVATED: if (sett_conn) { /* Reset auto retries back to default since connection was successful */ nm_settings_connection_autoconnect_retries_reset(sett_conn); - - /* And clear secrets so they will always be requested from the - * settings service when the next connection is made. - */ - nm_settings_connection_clear_secrets(sett_conn, FALSE, FALSE); } /* Add device's new IPv4 and IPv6 configs to DNS */ @@ -2525,7 +2519,7 @@ connection_added(NMSettings *settings, NMSettingsConnection *connection, gpointe } static void -firewall_state_changed(NMFirewallManager *manager, gboolean initialized_now, gpointer user_data) +firewall_state_changed(NMFirewalldManager *manager, gboolean initialized_now, gpointer user_data) { NMPolicy * self = (NMPolicy *) user_data; NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE(self); @@ -2539,7 +2533,7 @@ firewall_state_changed(NMFirewallManager *manager, gboolean initialized_now, gpo return; } - if (!nm_firewall_manager_get_running(manager)) + if (!nm_firewalld_manager_get_running(manager)) return; /* add interface of each device to correct zone */ @@ -2791,9 +2785,9 @@ constructed(GObject *object) priv->agent_mgr = g_object_ref(nm_agent_manager_get()); - priv->firewall_manager = g_object_ref(nm_firewall_manager_get()); - g_signal_connect(priv->firewall_manager, - NM_FIREWALL_MANAGER_STATE_CHANGED, + priv->firewalld_manager = g_object_ref(nm_firewalld_manager_get()); + g_signal_connect(priv->firewalld_manager, + NM_FIREWALLD_MANAGER_STATE_CHANGED, G_CALLBACK(firewall_state_changed), self); @@ -2896,9 +2890,9 @@ dispose(GObject *object) g_slist_free_full(priv->pending_secondaries, (GDestroyNotify) pending_secondary_data_free); priv->pending_secondaries = NULL; - if (priv->firewall_manager) { - g_signal_handlers_disconnect_by_func(priv->firewall_manager, firewall_state_changed, self); - g_clear_object(&priv->firewall_manager); + if (priv->firewalld_manager) { + g_signal_handlers_disconnect_by_func(priv->firewalld_manager, firewall_state_changed, self); + g_clear_object(&priv->firewalld_manager); } if (priv->agent_mgr) { diff --git a/src/core/nm-proxy-config.c b/src/core/nm-proxy-config.c index f41601c9..49156dfa 100644 --- a/src/core/nm-proxy-config.c +++ b/src/core/nm-proxy-config.c @@ -9,7 +9,7 @@ #include -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" /*****************************************************************************/ diff --git a/src/core/nm-proxy-config.h b/src/core/nm-proxy-config.h index 7aa587d0..7b6241f8 100644 --- a/src/core/nm-proxy-config.h +++ b/src/core/nm-proxy-config.h @@ -7,8 +7,7 @@ #define __NETWORKMANAGER_PROXY_CONFIG_H__ #include "nm-setting-proxy.h" - -typedef enum { NM_PROXY_CONFIG_METHOD_AUTO = 0, NM_PROXY_CONFIG_METHOD_NONE } NMProxyConfigMethod; +#include "nm-l3-config-data.h" #define NM_TYPE_PROXY_CONFIG (nm_proxy_config_get_type()) #define NM_PROXY_CONFIG(obj) \ diff --git a/src/core/nm-rfkill-manager.c b/src/core/nm-rfkill-manager.c index f032851e..7f0b7726 100644 --- a/src/core/nm-rfkill-manager.c +++ b/src/core/nm-rfkill-manager.c @@ -9,7 +9,7 @@ #include -#include "nm-udev-aux/nm-udev-utils.h" +#include "libnm-udev-aux/nm-udev-utils.h" /*****************************************************************************/ diff --git a/src/core/nm-sleep-monitor.c b/src/core/nm-sleep-monitor.c index ffb4db4e..306453e7 100644 --- a/src/core/nm-sleep-monitor.c +++ b/src/core/nm-sleep-monitor.c @@ -11,7 +11,7 @@ #include #include -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "NetworkManagerUtils.h" #if defined(SUSPEND_RESUME_UPOWER) @@ -108,7 +108,7 @@ upower_resuming_cb(GDBusProxy *proxy, gpointer user_data) sleep_signal(user_data, FALSE); } -#else /* USE_UPOWER */ +#else /* USE_UPOWER */ static void drop_inhibitor(NMSleepMonitor *self, gboolean force) diff --git a/src/core/nm-test-utils-core.h b/src/core/nm-test-utils-core.h index e655ce22..99d12ba9 100644 --- a/src/core/nm-test-utils-core.h +++ b/src/core/nm-test-utils-core.h @@ -7,41 +7,11 @@ #define __NM_TEST_UTILS_CORE_H__ #include "NetworkManagerUtils.h" -#include "nm-keyfile-internal.h" +#include "libnm-core-intern/nm-keyfile-internal.h" #define _NMTST_INSIDE_CORE 1 -#include "nm-utils/nm-test-utils.h" - -/*****************************************************************************/ - -#define NMTST_EXPECT_NM(level, msg) NMTST_EXPECT("NetworkManager", level, msg) - -#define NMTST_EXPECT_NM_ERROR(msg) NMTST_EXPECT_NM(G_LOG_LEVEL_MESSAGE, "* [*] " msg) -#define NMTST_EXPECT_NM_WARN(msg) NMTST_EXPECT_NM(G_LOG_LEVEL_MESSAGE, "* [*] " msg) -#define NMTST_EXPECT_NM_INFO(msg) NMTST_EXPECT_NM(G_LOG_LEVEL_INFO, "* [*] " msg) -#define NMTST_EXPECT_NM_DEBUG(msg) NMTST_EXPECT_NM(G_LOG_LEVEL_DEBUG, "* [*] " msg) -#define NMTST_EXPECT_NM_TRACE(msg) NMTST_EXPECT_NM(G_LOG_LEVEL_DEBUG, "* [*] " msg) - -static inline void -nmtst_init_with_logging(int *argc, char ***argv, const char *log_level, const char *log_domains) -{ - __nmtst_init(argc, argv, FALSE, log_level, log_domains, NULL); -} -static inline void -nmtst_init_assert_logging(int *argc, char ***argv, const char *log_level, const char *log_domains) -{ - gboolean set_logging; - - __nmtst_init(argc, argv, TRUE, NULL, NULL, &set_logging); - - if (!set_logging) { - gboolean success; - - success = nm_logging_setup(log_level, log_domains, NULL, NULL); - g_assert(success); - } -} +#include "libnm-glib-aux/nm-test-utils.h" /*****************************************************************************/ @@ -347,7 +317,7 @@ nmtst_platform_ip6_routes_equal_aptr(const NMPObject *const * a, #ifdef __NETWORKMANAGER_IP4_CONFIG_H__ - #include "nm-glib-aux/nm-dedup-multi.h" + #include "libnm-glib-aux/nm-dedup-multi.h" static inline NMIP4Config * nmtst_ip4_config_new(int ifindex) @@ -361,7 +331,7 @@ nmtst_ip4_config_new(int ifindex) #ifdef __NETWORKMANAGER_IP6_CONFIG_H__ - #include "nm-glib-aux/nm-dedup-multi.h" + #include "libnm-glib-aux/nm-dedup-multi.h" static inline NMIP6Config * nmtst_ip6_config_new(int ifindex) diff --git a/src/core/nm-types.h b/src/core/nm-types.h index ab231459..7ad5aee1 100644 --- a/src/core/nm-types.h +++ b/src/core/nm-types.h @@ -10,8 +10,6 @@ #error Cannot use this header. #endif -#define _NM_SD_MAX_CLIENT_ID_LEN (sizeof(guint32) + 128) - /* core */ typedef struct _NMDBusObject NMDBusObject; typedef struct _NMActiveConnection NMActiveConnection; @@ -77,147 +75,6 @@ typedef enum { NM_ACTIVATION_REASON_USER_REQUEST, } NMActivationReason; -/* platform */ -typedef struct _NMPlatform NMPlatform; -typedef struct _NMPlatformObject NMPlatformObject; -typedef struct _NMPlatformObjWithIfindex NMPlatformObjWithIfindex; -typedef struct _NMPlatformIP4Address NMPlatformIP4Address; -typedef struct _NMPlatformIP4Route NMPlatformIP4Route; -typedef struct _NMPlatformIP6Address NMPlatformIP6Address; -typedef struct _NMPlatformIP6Route NMPlatformIP6Route; -typedef struct _NMPlatformLink NMPlatformLink; -typedef struct _NMPObject NMPObject; - -typedef enum { - - /* No type, used as error value */ - NM_LINK_TYPE_NONE, - - NM_LINK_TYPE_UNKNOWN, - - NM_LINK_TYPE_ANY, - -#define _NM_LINK_TYPE_REAL_FIRST NM_LINK_TYPE_ETHERNET - -/* Hardware types */ -#define _NM_LINK_TYPE_HW_FIRST NM_LINK_TYPE_ETHERNET - NM_LINK_TYPE_ETHERNET, - NM_LINK_TYPE_INFINIBAND, - NM_LINK_TYPE_OLPC_MESH, - NM_LINK_TYPE_WIFI, - NM_LINK_TYPE_WWAN_NET, /* WWAN kernel netdevice */ - NM_LINK_TYPE_WIMAX, - NM_LINK_TYPE_WPAN, - NM_LINK_TYPE_6LOWPAN, - NM_LINK_TYPE_WIFI_P2P, -#define _NM_LINK_TYPE_HW_LAST NM_LINK_TYPE_WIFI_P2P - -/* Software types */ -#define _NM_LINK_TYPE_SW_FIRST NM_LINK_TYPE_BNEP - NM_LINK_TYPE_BNEP, /* Bluetooth Ethernet emulation */ - NM_LINK_TYPE_DUMMY, - NM_LINK_TYPE_GRE, - NM_LINK_TYPE_GRETAP, - NM_LINK_TYPE_IFB, - NM_LINK_TYPE_IP6TNL, - NM_LINK_TYPE_IP6GRE, - NM_LINK_TYPE_IP6GRETAP, - NM_LINK_TYPE_IPIP, - NM_LINK_TYPE_LOOPBACK, - NM_LINK_TYPE_MACSEC, - NM_LINK_TYPE_MACVLAN, - NM_LINK_TYPE_MACVTAP, - NM_LINK_TYPE_OPENVSWITCH, - NM_LINK_TYPE_PPP, - NM_LINK_TYPE_SIT, - NM_LINK_TYPE_TUN, - NM_LINK_TYPE_VETH, - NM_LINK_TYPE_VLAN, - NM_LINK_TYPE_VRF, - NM_LINK_TYPE_VXLAN, - NM_LINK_TYPE_WIREGUARD, -#define _NM_LINK_TYPE_SW_LAST NM_LINK_TYPE_WIREGUARD - -/* Software types with slaves */ -#define _NM_LINK_TYPE_SW_MASTER_FIRST NM_LINK_TYPE_BRIDGE - NM_LINK_TYPE_BRIDGE, - NM_LINK_TYPE_BOND, - NM_LINK_TYPE_TEAM, -#define _NM_LINK_TYPE_SW_MASTER_LAST NM_LINK_TYPE_TEAM - -#define _NM_LINK_TYPE_REAL_LAST NM_LINK_TYPE_TEAM - -#define _NM_LINK_TYPE_REAL_NUM ((int) (_NM_LINK_TYPE_REAL_LAST - _NM_LINK_TYPE_REAL_FIRST + 1)) - -} NMLinkType; - -static inline gboolean -nm_link_type_is_software(NMLinkType link_type) -{ - G_STATIC_ASSERT(_NM_LINK_TYPE_SW_LAST + 1 == _NM_LINK_TYPE_SW_MASTER_FIRST); - - return link_type >= _NM_LINK_TYPE_SW_FIRST && link_type <= _NM_LINK_TYPE_SW_MASTER_LAST; -} - -static inline gboolean -nm_link_type_supports_slaves(NMLinkType link_type) -{ - return link_type >= _NM_LINK_TYPE_SW_MASTER_FIRST && link_type <= _NM_LINK_TYPE_SW_MASTER_LAST; -} - -typedef enum { - NMP_OBJECT_TYPE_UNKNOWN, - NMP_OBJECT_TYPE_LINK, - -#define NMP_OBJECT_TYPE_IP_ADDRESS(is_ipv4) \ - ((is_ipv4) ? NMP_OBJECT_TYPE_IP4_ADDRESS : NMP_OBJECT_TYPE_IP6_ADDRESS) - NMP_OBJECT_TYPE_IP4_ADDRESS, - NMP_OBJECT_TYPE_IP6_ADDRESS, - -#define NMP_OBJECT_TYPE_IP_ROUTE(is_ipv4) \ - ((is_ipv4) ? NMP_OBJECT_TYPE_IP4_ROUTE : NMP_OBJECT_TYPE_IP6_ROUTE) - NMP_OBJECT_TYPE_IP4_ROUTE, - NMP_OBJECT_TYPE_IP6_ROUTE, - - NMP_OBJECT_TYPE_ROUTING_RULE, - - NMP_OBJECT_TYPE_QDISC, - - NMP_OBJECT_TYPE_TFILTER, - - NMP_OBJECT_TYPE_LNK_BRIDGE, - NMP_OBJECT_TYPE_LNK_GRE, - NMP_OBJECT_TYPE_LNK_GRETAP, - NMP_OBJECT_TYPE_LNK_INFINIBAND, - NMP_OBJECT_TYPE_LNK_IP6TNL, - NMP_OBJECT_TYPE_LNK_IP6GRE, - NMP_OBJECT_TYPE_LNK_IP6GRETAP, - NMP_OBJECT_TYPE_LNK_IPIP, - NMP_OBJECT_TYPE_LNK_MACSEC, - NMP_OBJECT_TYPE_LNK_MACVLAN, - NMP_OBJECT_TYPE_LNK_MACVTAP, - NMP_OBJECT_TYPE_LNK_SIT, - NMP_OBJECT_TYPE_LNK_TUN, - NMP_OBJECT_TYPE_LNK_VLAN, - NMP_OBJECT_TYPE_LNK_VRF, - NMP_OBJECT_TYPE_LNK_VXLAN, - NMP_OBJECT_TYPE_LNK_WIREGUARD, - - __NMP_OBJECT_TYPE_LAST, - NMP_OBJECT_TYPE_MAX = __NMP_OBJECT_TYPE_LAST - 1, -} NMPObjectType; - -static inline guint32 -nmp_object_type_to_flags(NMPObjectType obj_type) -{ - G_STATIC_ASSERT_EXPR(NMP_OBJECT_TYPE_MAX < 32); - - nm_assert(_NM_INT_NOT_NEGATIVE(obj_type)); - nm_assert(obj_type < NMP_OBJECT_TYPE_MAX); - - return ((guint32) 1u) << obj_type; -} - /** * NMIPConfigMergeFlags: * @NM_IP_CONFIG_MERGE_DEFAULT: no flags set @@ -236,32 +93,12 @@ typedef enum { NM_IP_CONFIG_MERGE_EXTERNAL = (1LL << 3), } NMIPConfigMergeFlags; -/** - * NMIPRouteTableSyncMode: - * @NM_IP_ROUTE_TABLE_SYNC_MODE_NONE: indicate an invalid setting. - * @NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN: only the main table is synced. For all - * other tables, NM won't delete any extra routes. - * @NM_IP_ROUTE_TABLE_SYNC_MODE_FULL: NM will sync all tables, except the - * local table (255). - * @NM_IP_ROUTE_TABLE_SYNC_MODE_ALL: NM will sync all tables, including the - * local table (255). - */ -typedef enum { - NM_IP_ROUTE_TABLE_SYNC_MODE_NONE = 0, - NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN = 1, - NM_IP_ROUTE_TABLE_SYNC_MODE_FULL = 2, - NM_IP_ROUTE_TABLE_SYNC_MODE_ALL = 3, -} NMIPRouteTableSyncMode; - /* settings */ typedef struct _NMAgentManager NMAgentManager; typedef struct _NMSecretAgent NMSecretAgent; typedef struct _NMSettings NMSettings; typedef struct _NMSettingsConnection NMSettingsConnection; -/* utils */ -typedef struct _NMUtilsIPv6IfaceId NMUtilsIPv6IfaceId; - #define NM_SETTING_CONNECTION_MDNS_UNKNOWN ((NMSettingConnectionMdns) -42) #endif /* NM_TYPES_H */ diff --git a/src/core/platform/linux/nl802154.h b/src/core/platform/linux/nl802154.h deleted file mode 100644 index c21bd079..00000000 --- a/src/core/platform/linux/nl802154.h +++ /dev/null @@ -1,450 +0,0 @@ -#ifndef __NL802154_H -#define __NL802154_H -/* - * 802.15.4 netlink interface public header - * - * Copyright (C) 2014 Alexander Aring - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#define NL802154_GENL_NAME "nl802154" - -enum nl802154_commands { - /* don't change the order or add anything between, this is ABI! */ - /* currently we don't shipping this file via uapi, ignore the above one */ - NL802154_CMD_UNSPEC, - - NL802154_CMD_GET_WPAN_PHY, /* can dump */ - NL802154_CMD_SET_WPAN_PHY, - NL802154_CMD_NEW_WPAN_PHY, - NL802154_CMD_DEL_WPAN_PHY, - - NL802154_CMD_GET_INTERFACE, /* can dump */ - NL802154_CMD_SET_INTERFACE, - NL802154_CMD_NEW_INTERFACE, - NL802154_CMD_DEL_INTERFACE, - - NL802154_CMD_SET_CHANNEL, - - NL802154_CMD_SET_PAN_ID, - NL802154_CMD_SET_SHORT_ADDR, - - NL802154_CMD_SET_TX_POWER, - NL802154_CMD_SET_CCA_MODE, - NL802154_CMD_SET_CCA_ED_LEVEL, - - NL802154_CMD_SET_MAX_FRAME_RETRIES, - - NL802154_CMD_SET_BACKOFF_EXPONENT, - NL802154_CMD_SET_MAX_CSMA_BACKOFFS, - - NL802154_CMD_SET_LBT_MODE, - - NL802154_CMD_SET_ACKREQ_DEFAULT, - - NL802154_CMD_SET_WPAN_PHY_NETNS, - -/* add new commands above here */ - -#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL - NL802154_CMD_SET_SEC_PARAMS, - NL802154_CMD_GET_SEC_KEY, /* can dump */ - NL802154_CMD_NEW_SEC_KEY, - NL802154_CMD_DEL_SEC_KEY, - NL802154_CMD_GET_SEC_DEV, /* can dump */ - NL802154_CMD_NEW_SEC_DEV, - NL802154_CMD_DEL_SEC_DEV, - NL802154_CMD_GET_SEC_DEVKEY, /* can dump */ - NL802154_CMD_NEW_SEC_DEVKEY, - NL802154_CMD_DEL_SEC_DEVKEY, - NL802154_CMD_GET_SEC_LEVEL, /* can dump */ - NL802154_CMD_NEW_SEC_LEVEL, - NL802154_CMD_DEL_SEC_LEVEL, -#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */ - - /* used to define NL802154_CMD_MAX below */ - __NL802154_CMD_AFTER_LAST, - NL802154_CMD_MAX = __NL802154_CMD_AFTER_LAST - 1 -}; - -enum nl802154_attrs { - /* don't change the order or add anything between, this is ABI! */ - /* currently we don't shipping this file via uapi, ignore the above one */ - NL802154_ATTR_UNSPEC, - - NL802154_ATTR_WPAN_PHY, - NL802154_ATTR_WPAN_PHY_NAME, - - NL802154_ATTR_IFINDEX, - NL802154_ATTR_IFNAME, - NL802154_ATTR_IFTYPE, - - NL802154_ATTR_WPAN_DEV, - - NL802154_ATTR_PAGE, - NL802154_ATTR_CHANNEL, - - NL802154_ATTR_PAN_ID, - NL802154_ATTR_SHORT_ADDR, - - NL802154_ATTR_TX_POWER, - - NL802154_ATTR_CCA_MODE, - NL802154_ATTR_CCA_OPT, - NL802154_ATTR_CCA_ED_LEVEL, - - NL802154_ATTR_MAX_FRAME_RETRIES, - - NL802154_ATTR_MAX_BE, - NL802154_ATTR_MIN_BE, - NL802154_ATTR_MAX_CSMA_BACKOFFS, - - NL802154_ATTR_LBT_MODE, - - NL802154_ATTR_GENERATION, - - NL802154_ATTR_CHANNELS_SUPPORTED, - NL802154_ATTR_SUPPORTED_CHANNEL, - - NL802154_ATTR_EXTENDED_ADDR, - - NL802154_ATTR_WPAN_PHY_CAPS, - - NL802154_ATTR_SUPPORTED_COMMANDS, - - NL802154_ATTR_ACKREQ_DEFAULT, - - NL802154_ATTR_PAD, - - NL802154_ATTR_PID, - NL802154_ATTR_NETNS_FD, - -/* add attributes here, update the policy in nl802154.c */ - -#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL - NL802154_ATTR_SEC_ENABLED, - NL802154_ATTR_SEC_OUT_LEVEL, - NL802154_ATTR_SEC_OUT_KEY_ID, - NL802154_ATTR_SEC_FRAME_COUNTER, - - NL802154_ATTR_SEC_LEVEL, - NL802154_ATTR_SEC_DEVICE, - NL802154_ATTR_SEC_DEVKEY, - NL802154_ATTR_SEC_KEY, -#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */ - - __NL802154_ATTR_AFTER_LAST, - NL802154_ATTR_MAX = __NL802154_ATTR_AFTER_LAST - 1 -}; - -enum nl802154_iftype { - /* for backwards compatibility TODO */ - NL802154_IFTYPE_UNSPEC = -1, - - NL802154_IFTYPE_NODE, - NL802154_IFTYPE_MONITOR, - NL802154_IFTYPE_COORD, - - /* keep last */ - NUM_NL802154_IFTYPES, - NL802154_IFTYPE_MAX = NUM_NL802154_IFTYPES - 1 -}; - -/** - * enum nl802154_wpan_phy_capability_attr - wpan phy capability attributes - * - * @__NL802154_CAP_ATTR_INVALID: attribute number 0 is reserved - * @NL802154_CAP_ATTR_CHANNELS: a nested attribute for nl802154_channel_attr - * @NL802154_CAP_ATTR_TX_POWERS: a nested attribute for nl802154_wpan_phy_tx_power - * @NL802154_CAP_ATTR_MIN_CCA_ED_LEVEL: minimum value for cca_ed_level - * @NL802154_CAP_ATTR_MAX_CCA_ED_LEVEL: maxmimum value for cca_ed_level - * @NL802154_CAP_ATTR_CCA_MODES: nl802154_cca_modes flags - * @NL802154_CAP_ATTR_CCA_OPTS: nl802154_cca_opts flags - * @NL802154_CAP_ATTR_MIN_MINBE: minimum of minbe value - * @NL802154_CAP_ATTR_MAX_MINBE: maximum of minbe value - * @NL802154_CAP_ATTR_MIN_MAXBE: minimum of maxbe value - * @NL802154_CAP_ATTR_MAX_MINBE: maximum of maxbe value - * @NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS: minimum of csma backoff value - * @NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS: maximum of csma backoffs value - * @NL802154_CAP_ATTR_MIN_FRAME_RETRIES: minimum of frame retries value - * @NL802154_CAP_ATTR_MAX_FRAME_RETRIES: maximum of frame retries value - * @NL802154_CAP_ATTR_IFTYPES: nl802154_iftype flags - * @NL802154_CAP_ATTR_LBT: nl802154_supported_bool_states flags - * @NL802154_CAP_ATTR_MAX: highest cap attribute currently defined - * @__NL802154_CAP_ATTR_AFTER_LAST: internal use - */ -enum nl802154_wpan_phy_capability_attr { - __NL802154_CAP_ATTR_INVALID, - - NL802154_CAP_ATTR_IFTYPES, - - NL802154_CAP_ATTR_CHANNELS, - NL802154_CAP_ATTR_TX_POWERS, - - NL802154_CAP_ATTR_CCA_ED_LEVELS, - NL802154_CAP_ATTR_CCA_MODES, - NL802154_CAP_ATTR_CCA_OPTS, - - NL802154_CAP_ATTR_MIN_MINBE, - NL802154_CAP_ATTR_MAX_MINBE, - - NL802154_CAP_ATTR_MIN_MAXBE, - NL802154_CAP_ATTR_MAX_MAXBE, - - NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS, - NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS, - - NL802154_CAP_ATTR_MIN_FRAME_RETRIES, - NL802154_CAP_ATTR_MAX_FRAME_RETRIES, - - NL802154_CAP_ATTR_LBT, - - /* keep last */ - __NL802154_CAP_ATTR_AFTER_LAST, - NL802154_CAP_ATTR_MAX = __NL802154_CAP_ATTR_AFTER_LAST - 1 -}; - -/** - * enum nl802154_cca_modes - cca modes - * - * @__NL802154_CCA_INVALID: cca mode number 0 is reserved - * @NL802154_CCA_ENERGY: Energy above threshold - * @NL802154_CCA_CARRIER: Carrier sense only - * @NL802154_CCA_ENERGY_CARRIER: Carrier sense with energy above threshold - * @NL802154_CCA_ALOHA: CCA shall always report an idle medium - * @NL802154_CCA_UWB_SHR: UWB preamble sense based on the SHR of a frame - * @NL802154_CCA_UWB_MULTIPLEXED: UWB preamble sense based on the packet with the multiplexed preamble - * @__NL802154_CCA_ATTR_AFTER_LAST: Internal - * @NL802154_CCA_ATTR_MAX: Maximum CCA attribute number - */ -enum nl802154_cca_modes { - __NL802154_CCA_INVALID, - NL802154_CCA_ENERGY, - NL802154_CCA_CARRIER, - NL802154_CCA_ENERGY_CARRIER, - NL802154_CCA_ALOHA, - NL802154_CCA_UWB_SHR, - NL802154_CCA_UWB_MULTIPLEXED, - - /* keep last */ - __NL802154_CCA_ATTR_AFTER_LAST, - NL802154_CCA_ATTR_MAX = __NL802154_CCA_ATTR_AFTER_LAST - 1 -}; - -/** - * enum nl802154_cca_opts - additional options for cca modes - * - * @NL802154_CCA_OPT_ENERGY_CARRIER_OR: NL802154_CCA_ENERGY_CARRIER with OR - * @NL802154_CCA_OPT_ENERGY_CARRIER_AND: NL802154_CCA_ENERGY_CARRIER with AND - */ -enum nl802154_cca_opts { - NL802154_CCA_OPT_ENERGY_CARRIER_AND, - NL802154_CCA_OPT_ENERGY_CARRIER_OR, - - /* keep last */ - __NL802154_CCA_OPT_ATTR_AFTER_LAST, - NL802154_CCA_OPT_ATTR_MAX = __NL802154_CCA_OPT_ATTR_AFTER_LAST - 1 -}; - -/** - * enum nl802154_supported_bool_states - bool states for bool capability entry - * - * @NL802154_SUPPORTED_BOOL_FALSE: indicates to set false - * @NL802154_SUPPORTED_BOOL_TRUE: indicates to set true - * @__NL802154_SUPPORTED_BOOL_INVALD: reserved - * @NL802154_SUPPORTED_BOOL_BOTH: indicates to set true and false - * @__NL802154_SUPPORTED_BOOL_AFTER_LAST: Internal - * @NL802154_SUPPORTED_BOOL_MAX: highest value for bool states - */ -enum nl802154_supported_bool_states { - NL802154_SUPPORTED_BOOL_FALSE, - NL802154_SUPPORTED_BOOL_TRUE, - /* to handle them in a mask */ - __NL802154_SUPPORTED_BOOL_INVALD, - NL802154_SUPPORTED_BOOL_BOTH, - - /* keep last */ - __NL802154_SUPPORTED_BOOL_AFTER_LAST, - NL802154_SUPPORTED_BOOL_MAX = __NL802154_SUPPORTED_BOOL_AFTER_LAST - 1 -}; - -#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL - -enum nl802154_dev_addr_modes { - NL802154_DEV_ADDR_NONE, - __NL802154_DEV_ADDR_INVALID, - NL802154_DEV_ADDR_SHORT, - NL802154_DEV_ADDR_EXTENDED, - - /* keep last */ - __NL802154_DEV_ADDR_AFTER_LAST, - NL802154_DEV_ADDR_MAX = __NL802154_DEV_ADDR_AFTER_LAST - 1 -}; - -enum nl802154_dev_addr_attrs { - NL802154_DEV_ADDR_ATTR_UNSPEC, - - NL802154_DEV_ADDR_ATTR_PAN_ID, - NL802154_DEV_ADDR_ATTR_MODE, - NL802154_DEV_ADDR_ATTR_SHORT, - NL802154_DEV_ADDR_ATTR_EXTENDED, - NL802154_DEV_ADDR_ATTR_PAD, - - /* keep last */ - __NL802154_DEV_ADDR_ATTR_AFTER_LAST, - NL802154_DEV_ADDR_ATTR_MAX = __NL802154_DEV_ADDR_ATTR_AFTER_LAST - 1 -}; - -enum nl802154_key_id_modes { - NL802154_KEY_ID_MODE_IMPLICIT, - NL802154_KEY_ID_MODE_INDEX, - NL802154_KEY_ID_MODE_INDEX_SHORT, - NL802154_KEY_ID_MODE_INDEX_EXTENDED, - - /* keep last */ - __NL802154_KEY_ID_MODE_AFTER_LAST, - NL802154_KEY_ID_MODE_MAX = __NL802154_KEY_ID_MODE_AFTER_LAST - 1 -}; - -enum nl802154_key_id_attrs { - NL802154_KEY_ID_ATTR_UNSPEC, - - NL802154_KEY_ID_ATTR_MODE, - NL802154_KEY_ID_ATTR_INDEX, - NL802154_KEY_ID_ATTR_IMPLICIT, - NL802154_KEY_ID_ATTR_SOURCE_SHORT, - NL802154_KEY_ID_ATTR_SOURCE_EXTENDED, - NL802154_KEY_ID_ATTR_PAD, - - /* keep last */ - __NL802154_KEY_ID_ATTR_AFTER_LAST, - NL802154_KEY_ID_ATTR_MAX = __NL802154_KEY_ID_ATTR_AFTER_LAST - 1 -}; - -enum nl802154_seclevels { - NL802154_SECLEVEL_NONE, - NL802154_SECLEVEL_MIC32, - NL802154_SECLEVEL_MIC64, - NL802154_SECLEVEL_MIC128, - NL802154_SECLEVEL_ENC, - NL802154_SECLEVEL_ENC_MIC32, - NL802154_SECLEVEL_ENC_MIC64, - NL802154_SECLEVEL_ENC_MIC128, - - /* keep last */ - __NL802154_SECLEVEL_AFTER_LAST, - NL802154_SECLEVEL_MAX = __NL802154_SECLEVEL_AFTER_LAST - 1 -}; - -enum nl802154_frames { - NL802154_FRAME_BEACON, - NL802154_FRAME_DATA, - NL802154_FRAME_ACK, - NL802154_FRAME_CMD, - - /* keep last */ - __NL802154_FRAME_AFTER_LAST, - NL802154_FRAME_MAX = __NL802154_FRAME_AFTER_LAST - 1 -}; - -enum nl802154_cmd_frames { - __NL802154_CMD_FRAME_INVALID, - NL802154_CMD_FRAME_ASSOC_REQUEST, - NL802154_CMD_FRAME_ASSOC_RESPONSE, - NL802154_CMD_FRAME_DISASSOC_NOTIFY, - NL802154_CMD_FRAME_DATA_REQUEST, - NL802154_CMD_FRAME_PAN_ID_CONFLICT_NOTIFY, - NL802154_CMD_FRAME_ORPHAN_NOTIFY, - NL802154_CMD_FRAME_BEACON_REQUEST, - NL802154_CMD_FRAME_COORD_REALIGNMENT, - NL802154_CMD_FRAME_GTS_REQUEST, - - /* keep last */ - __NL802154_CMD_FRAME_AFTER_LAST, - NL802154_CMD_FRAME_MAX = __NL802154_CMD_FRAME_AFTER_LAST - 1 -}; - -enum nl802154_seclevel_attrs { - NL802154_SECLEVEL_ATTR_UNSPEC, - - NL802154_SECLEVEL_ATTR_LEVELS, - NL802154_SECLEVEL_ATTR_FRAME, - NL802154_SECLEVEL_ATTR_CMD_FRAME, - NL802154_SECLEVEL_ATTR_DEV_OVERRIDE, - - /* keep last */ - __NL802154_SECLEVEL_ATTR_AFTER_LAST, - NL802154_SECLEVEL_ATTR_MAX = __NL802154_SECLEVEL_ATTR_AFTER_LAST - 1 -}; - -/* TODO what is this? couldn't find in mib */ -enum { - NL802154_DEVKEY_IGNORE, - NL802154_DEVKEY_RESTRICT, - NL802154_DEVKEY_RECORD, - - /* keep last */ - __NL802154_DEVKEY_AFTER_LAST, - NL802154_DEVKEY_MAX = __NL802154_DEVKEY_AFTER_LAST - 1 -}; - -enum nl802154_dev { - NL802154_DEV_ATTR_UNSPEC, - - NL802154_DEV_ATTR_FRAME_COUNTER, - NL802154_DEV_ATTR_PAN_ID, - NL802154_DEV_ATTR_SHORT_ADDR, - NL802154_DEV_ATTR_EXTENDED_ADDR, - NL802154_DEV_ATTR_SECLEVEL_EXEMPT, - NL802154_DEV_ATTR_KEY_MODE, - NL802154_DEV_ATTR_PAD, - - /* keep last */ - __NL802154_DEV_ATTR_AFTER_LAST, - NL802154_DEV_ATTR_MAX = __NL802154_DEV_ATTR_AFTER_LAST - 1 -}; - -enum nl802154_devkey { - NL802154_DEVKEY_ATTR_UNSPEC, - - NL802154_DEVKEY_ATTR_FRAME_COUNTER, - NL802154_DEVKEY_ATTR_EXTENDED_ADDR, - NL802154_DEVKEY_ATTR_ID, - NL802154_DEVKEY_ATTR_PAD, - - /* keep last */ - __NL802154_DEVKEY_ATTR_AFTER_LAST, - NL802154_DEVKEY_ATTR_MAX = __NL802154_DEVKEY_ATTR_AFTER_LAST - 1 -}; - -enum nl802154_key { - NL802154_KEY_ATTR_UNSPEC, - - NL802154_KEY_ATTR_ID, - NL802154_KEY_ATTR_USAGE_FRAMES, - NL802154_KEY_ATTR_USAGE_CMDS, - NL802154_KEY_ATTR_BYTES, - - /* keep last */ - __NL802154_KEY_ATTR_AFTER_LAST, - NL802154_KEY_ATTR_MAX = __NL802154_KEY_ATTR_AFTER_LAST - 1 -}; - - #define NL802154_KEY_SIZE 16 - #define NL802154_CMD_FRAME_NR_IDS 256 - -#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */ - -#endif /* __NL802154_H */ diff --git a/src/core/platform/nm-fake-platform.c b/src/core/platform/nm-fake-platform.c index 81c9f06c..0108b581 100644 --- a/src/core/platform/nm-fake-platform.c +++ b/src/core/platform/nm-fake-platform.c @@ -13,12 +13,9 @@ #include #include -#include "nm-utils.h" - -#include "nm-core-utils.h" -#include "nm-platform/nm-platform-utils.h" -#include "nm-platform-private.h" -#include "nmp-object.h" +#include "libnm-platform/nm-platform-utils.h" +#include "libnm-platform/nm-platform-private.h" +#include "libnm-platform/nmp-object.h" #include "nm-test-utils-core.h" @@ -506,6 +503,21 @@ link_set_flags(NMPlatform *platform, NMFakePlatformLink *device, guint n_ifi_fla link_set_obj(platform, device, obj_tmp); } +static int +link_change_flags(NMPlatform *platform, int ifindex, unsigned flags_mask, unsigned flags_set) +{ + NMFakePlatformLink *device = link_get(platform, ifindex); + + if (!device) + return -ENOENT; + + link_set_flags(platform, + device, + NM_FLAGS_ASSIGN_MASK(device->obj->link.n_ifi_flags, flags_mask, flags_set)); + + return 0; +} + static void link_changed(NMPlatform * platform, NMFakePlatformLink *device, @@ -543,72 +555,13 @@ link_changed(NMPlatform * platform, } } -static gboolean -link_set_up(NMPlatform *platform, int ifindex, gboolean *out_no_firmware) -{ - NMFakePlatformLink *device = link_get(platform, ifindex); - - if (out_no_firmware) - *out_no_firmware = FALSE; - - if (!device) { - _LOGE("failure changing link: netlink error (No such device)"); - return FALSE; - } - - link_set_flags(platform, device, NM_FLAGS_ASSIGN(device->obj->link.n_ifi_flags, IFF_UP, TRUE)); - return TRUE; -} - -static gboolean -link_set_down(NMPlatform *platform, int ifindex) -{ - NMFakePlatformLink *device = link_get(platform, ifindex); - - if (!device) { - _LOGE("failure changing link: netlink error (No such device)"); - return FALSE; - } - - link_set_flags(platform, device, NM_FLAGS_UNSET(device->obj->link.n_ifi_flags, IFF_UP)); - return TRUE; -} - -static gboolean -link_set_arp(NMPlatform *platform, int ifindex) -{ - NMFakePlatformLink *device = link_get(platform, ifindex); - - if (!device) { - _LOGE("failure changing link: netlink error (No such device)"); - return FALSE; - } - - link_set_flags(platform, device, NM_FLAGS_UNSET(device->obj->link.n_ifi_flags, IFF_NOARP)); - return TRUE; -} - -static gboolean -link_set_noarp(NMPlatform *platform, int ifindex) -{ - NMFakePlatformLink *device = link_get(platform, ifindex); - - if (!device) { - _LOGE("failure changing link: netlink error (No such device)"); - return FALSE; - } - - link_set_flags(platform, device, NM_FLAGS_SET(device->obj->link.n_ifi_flags, IFF_NOARP)); - return TRUE; -} - static int link_set_address(NMPlatform *platform, int ifindex, gconstpointer addr, size_t len) { NMFakePlatformLink *device = link_get(platform, ifindex); nm_auto_nmpobj NMPObject *obj_tmp = NULL; - if (len == 0 || len > NM_UTILS_HWADDR_LEN_MAX || !addr) + if (len == 0 || len > _NM_UTILS_HWADDR_LEN_MAX || !addr) g_return_val_if_reached(-NME_BUG); if (!device) @@ -749,8 +702,8 @@ link_release(NMPlatform *platform, int master_idx, int slave_idx) static gboolean link_vlan_change(NMPlatform * platform, int ifindex, - NMVlanFlags flags_mask, - NMVlanFlags flags_set, + _NMVlanFlags flags_mask, + _NMVlanFlags flags_set, gboolean ingress_reset_all, const NMVlanQosMapping *ingress_map, gsize n_ingress_map, @@ -799,7 +752,7 @@ infiniband_partition_add(NMPlatform * platform, parent_device = link_get(platform, parent); g_return_val_if_fail(parent_device != NULL, FALSE); - nm_utils_new_infiniband_name(name, parent_device->obj->link.name, p_key); + nmp_utils_new_infiniband_name(name, parent_device->obj->link.name, p_key); link_add_one(platform, name, NM_LINK_TYPE_INFINIBAND, _infiniband_add_prepare, &d, out_link); return TRUE; @@ -814,12 +767,12 @@ infiniband_partition_delete(NMPlatform *platform, int parent, int p_key) parent_device = link_get(platform, parent); g_return_val_if_fail(parent_device != NULL, FALSE); - nm_utils_new_infiniband_name(name, parent_device->obj->link.name, p_key); + nmp_utils_new_infiniband_name(name, parent_device->obj->link.name, p_key); return link_delete(platform, nm_platform_link_get_ifindex(platform, name)); } static gboolean -wifi_get_capabilities(NMPlatform *platform, int ifindex, NMDeviceWifiCapabilities *caps) +wifi_get_capabilities(NMPlatform *platform, int ifindex, _NMDeviceWifiCapabilities *caps) { NMFakePlatformLink *device = link_get(platform, ifindex); @@ -829,10 +782,10 @@ wifi_get_capabilities(NMPlatform *platform, int ifindex, NMDeviceWifiCapabilitie return FALSE; if (caps) { - *caps = (NM_WIFI_DEVICE_CAP_CIPHER_WEP40 | NM_WIFI_DEVICE_CAP_CIPHER_WEP104 - | NM_WIFI_DEVICE_CAP_CIPHER_TKIP | NM_WIFI_DEVICE_CAP_CIPHER_CCMP - | NM_WIFI_DEVICE_CAP_WPA | NM_WIFI_DEVICE_CAP_RSN | NM_WIFI_DEVICE_CAP_AP - | NM_WIFI_DEVICE_CAP_ADHOC); + *caps = (_NM_WIFI_DEVICE_CAP_CIPHER_WEP40 | _NM_WIFI_DEVICE_CAP_CIPHER_WEP104 + | _NM_WIFI_DEVICE_CAP_CIPHER_TKIP | _NM_WIFI_DEVICE_CAP_CIPHER_CCMP + | _NM_WIFI_DEVICE_CAP_WPA | _NM_WIFI_DEVICE_CAP_RSN | _NM_WIFI_DEVICE_CAP_AP + | _NM_WIFI_DEVICE_CAP_ADHOC); } return TRUE; } @@ -861,14 +814,14 @@ wifi_get_rate(NMPlatform *platform, int ifindex) return 0; } -static NM80211Mode +static _NM80211Mode wifi_get_mode(NMPlatform *platform, int ifindex) { - return NM_802_11_MODE_UNKNOWN; + return _NM_802_11_MODE_UNKNOWN; } static void -wifi_set_mode(NMPlatform *platform, int ifindex, NM80211Mode mode) +wifi_set_mode(NMPlatform *platform, int ifindex, _NM80211Mode mode) { ; } @@ -1357,14 +1310,11 @@ nm_fake_platform_class_init(NMFakePlatformClass *klass) platform_class->link_add = link_add; platform_class->link_delete = link_delete; - platform_class->link_set_up = link_set_up; - platform_class->link_set_down = link_set_down; - platform_class->link_set_arp = link_set_arp; - platform_class->link_set_noarp = link_set_noarp; - platform_class->link_set_address = link_set_address; platform_class->link_set_mtu = link_set_mtu; + platform_class->link_change_flags = link_change_flags; + platform_class->link_get_driver_info = link_get_driver_info; platform_class->link_supports_carrier_detect = link_supports_carrier_detect; diff --git a/src/core/platform/nm-fake-platform.h b/src/core/platform/nm-fake-platform.h index a1d44f8f..8f8571fa 100644 --- a/src/core/platform/nm-fake-platform.h +++ b/src/core/platform/nm-fake-platform.h @@ -6,7 +6,7 @@ #ifndef __NETWORKMANAGER_FAKE_PLATFORM_H__ #define __NETWORKMANAGER_FAKE_PLATFORM_H__ -#include "nm-platform.h" +#include "libnm-platform/nm-platform.h" #define NM_TYPE_FAKE_PLATFORM (nm_fake_platform_get_type()) #define NM_FAKE_PLATFORM(obj) \ diff --git a/src/core/platform/nm-linux-platform.c b/src/core/platform/nm-linux-platform.c deleted file mode 100644 index 7bd42bba..00000000 --- a/src/core/platform/nm-linux-platform.c +++ /dev/null @@ -1,9696 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2012 - 2018 Red Hat, Inc. - */ - -#include "src/core/nm-default-daemon.h" - -#include "nm-linux-platform.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 "nm-std-aux/unaligned.h" - -#include "nm-utils.h" -#include "nm-core-internal.h" -#include "nm-setting-vlan.h" - -#include "nm-glib-aux/nm-secret-utils.h" -#include "nm-glib-aux/nm-c-list.h" -#include "nm-platform/nm-netlink.h" -#include "nm-core-utils.h" -#include "nmp-object.h" -#include "nm-platform/nmp-netns.h" -#include "nm-platform/nm-platform-utils.h" -#include "nm-platform-private.h" -#include "wifi/nm-wifi-utils.h" -#include "wifi/nm-wifi-utils-wext.h" -#include "wpan/nm-wpan-utils.h" -#include "nm-glib-aux/nm-io-utils.h" -#include "nm-udev-aux/nm-udev-utils.h" - -/*****************************************************************************/ - -/* re-implement to build against kernel - * headers that lack this. */ - -#include - -struct tc_defact { - tc_gen; -}; - -enum { TCA_DEF_UNSPEC, TCA_DEF_TM, TCA_DEF_PARMS, TCA_DEF_DATA, TCA_DEF_PAD, __TCA_DEF_MAX }; -#define TCA_DEF_MAX (__TCA_DEF_MAX - 1) - -/*****************************************************************************/ - -/* Compat with older kernels. */ - -#define TCA_FQ_CODEL_CE_THRESHOLD 7 -#define TCA_FQ_CODEL_MEMORY_LIMIT 9 - -/*****************************************************************************/ - -#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 - -#define IFLA_TUN_UNSPEC 0 -#define IFLA_TUN_OWNER 1 -#define IFLA_TUN_GROUP 2 -#define IFLA_TUN_TYPE 3 -#define IFLA_TUN_PI 4 -#define IFLA_TUN_VNET_HDR 5 -#define IFLA_TUN_PERSIST 6 -#define IFLA_TUN_MULTI_QUEUE 7 -#define IFLA_TUN_NUM_QUEUES 8 -#define IFLA_TUN_NUM_DISABLED_QUEUES 9 -#define __IFLA_TUN_MAX 10 -#define IFLA_TUN_MAX (__IFLA_TUN_MAX - 1) - -G_STATIC_ASSERT(RTA_MAX == (__RTA_MAX - 1)); -#define RTA_PREF 20 -#undef RTA_MAX -#define RTA_MAX (MAX((__RTA_MAX - 1), RTA_PREF)) - -#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 IFLA_BR_VLAN_STATS_ENABLED 41 - -/*****************************************************************************/ - -/* Appeared in the kernel prior to 3.13 dated 19 January, 2014 */ -#ifndef ARPHRD_6LOWPAN - #define ARPHRD_6LOWPAN 825 -#endif - -/*****************************************************************************/ - -#define FRA_TUN_ID 12 -#define FRA_SUPPRESS_IFGROUP 13 -#define FRA_SUPPRESS_PREFIXLEN 14 -#define FRA_PAD 18 -#define FRA_L3MDEV 19 -#define FRA_UID_RANGE 20 -#define FRA_PROTOCOL 21 -#define FRA_IP_PROTO 22 -#define FRA_SPORT_RANGE 23 -#define FRA_DPORT_RANGE 24 - -/*****************************************************************************/ - -#define IFLA_MACSEC_UNSPEC 0 -#define IFLA_MACSEC_SCI 1 -#define IFLA_MACSEC_PORT 2 -#define IFLA_MACSEC_ICV_LEN 3 -#define IFLA_MACSEC_CIPHER_SUITE 4 -#define IFLA_MACSEC_WINDOW 5 -#define IFLA_MACSEC_ENCODING_SA 6 -#define IFLA_MACSEC_ENCRYPT 7 -#define IFLA_MACSEC_PROTECT 8 -#define IFLA_MACSEC_INC_SCI 9 -#define IFLA_MACSEC_ES 10 -#define IFLA_MACSEC_SCB 11 -#define IFLA_MACSEC_REPLAY_PROTECT 12 -#define IFLA_MACSEC_VALIDATION 13 -#define IFLA_MACSEC_PAD 14 -#define __IFLA_MACSEC_MAX 15 - -/*****************************************************************************/ - -#define WG_CMD_GET_DEVICE 0 -#define WG_CMD_SET_DEVICE 1 - -#define WGDEVICE_F_REPLACE_PEERS ((guint32)(1U << 0)) - -#define WGPEER_F_REMOVE_ME ((guint32)(1U << 0)) -#define WGPEER_F_REPLACE_ALLOWEDIPS ((guint32)(1U << 1)) - -#define WGDEVICE_A_UNSPEC 0 -#define WGDEVICE_A_IFINDEX 1 -#define WGDEVICE_A_IFNAME 2 -#define WGDEVICE_A_PRIVATE_KEY 3 -#define WGDEVICE_A_PUBLIC_KEY 4 -#define WGDEVICE_A_FLAGS 5 -#define WGDEVICE_A_LISTEN_PORT 6 -#define WGDEVICE_A_FWMARK 7 -#define WGDEVICE_A_PEERS 8 -#define WGDEVICE_A_MAX 8 - -#define WGPEER_A_UNSPEC 0 -#define WGPEER_A_PUBLIC_KEY 1 -#define WGPEER_A_PRESHARED_KEY 2 -#define WGPEER_A_FLAGS 3 -#define WGPEER_A_ENDPOINT 4 -#define WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL 5 -#define WGPEER_A_LAST_HANDSHAKE_TIME 6 -#define WGPEER_A_RX_BYTES 7 -#define WGPEER_A_TX_BYTES 8 -#define WGPEER_A_ALLOWEDIPS 9 -#define WGPEER_A_MAX 9 - -#define WGALLOWEDIP_A_UNSPEC 0 -#define WGALLOWEDIP_A_FAMILY 1 -#define WGALLOWEDIP_A_IPADDR 2 -#define WGALLOWEDIP_A_CIDR_MASK 3 -#define WGALLOWEDIP_A_MAX 3 - -/*****************************************************************************/ - -/* Redefine VF enums and structures that are not available on older kernels. */ - -#define IFLA_VF_UNSPEC 0 -#define IFLA_VF_MAC 1 -#define IFLA_VF_VLAN 2 -#define IFLA_VF_TX_RATE 3 -#define IFLA_VF_SPOOFCHK 4 -#define IFLA_VF_LINK_STATE 5 -#define IFLA_VF_RATE 6 -#define IFLA_VF_RSS_QUERY_EN 7 -#define IFLA_VF_STATS 8 -#define IFLA_VF_TRUST 9 -#define IFLA_VF_IB_NODE_GUID 10 -#define IFLA_VF_IB_PORT_GUID 11 -#define IFLA_VF_VLAN_LIST 12 - -#define IFLA_VF_VLAN_INFO_UNSPEC 0 -#define IFLA_VF_VLAN_INFO 1 - -/* valid for TRUST, SPOOFCHK, LINK_STATE, RSS_QUERY_EN */ -struct _ifla_vf_setting { - guint32 vf; - guint32 setting; -}; - -struct _ifla_vf_rate { - guint32 vf; - guint32 min_tx_rate; - guint32 max_tx_rate; -}; - -struct _ifla_vf_vlan_info { - guint32 vf; - guint32 vlan; /* 0 - 4095, 0 disables VLAN filter */ - guint32 qos; - guint16 vlan_proto; /* VLAN protocol, either 802.1Q or 802.1ad */ -}; - -/*****************************************************************************/ - -/* Appeared in the kernel 4.0 dated April 12, 2015 */ -#ifndef BRIDGE_VLAN_INFO_RANGE_BEGIN - #define BRIDGE_VLAN_INFO_RANGE_BEGIN (1 << 3) /* VLAN is start of vlan range */ - #define BRIDGE_VLAN_INFO_RANGE_END (1 << 4) /* VLAN is end of vlan range */ -#endif - -/*****************************************************************************/ - -#define PSCHED_TIME_UNITS_PER_SEC 1000000 - -/*****************************************************************************/ - -typedef enum { - INFINIBAND_ACTION_CREATE_CHILD, - INFINIBAND_ACTION_DELETE_CHILD, -} InfinibandAction; - -typedef enum { - CHANGE_LINK_TYPE_UNSPEC, - CHANGE_LINK_TYPE_SET_MTU, - CHANGE_LINK_TYPE_SET_ADDRESS, -} ChangeLinkType; - -typedef struct { - union { - struct { - gconstpointer address; - gsize length; - } set_address; - }; -} ChangeLinkData; - -typedef enum { - _REFRESH_ALL_TYPE_FIRST = 0, - - REFRESH_ALL_TYPE_LINKS = 0, - REFRESH_ALL_TYPE_IP4_ADDRESSES = 1, - REFRESH_ALL_TYPE_IP6_ADDRESSES = 2, - REFRESH_ALL_TYPE_IP4_ROUTES = 3, - REFRESH_ALL_TYPE_IP6_ROUTES = 4, - REFRESH_ALL_TYPE_ROUTING_RULES_IP4 = 5, - REFRESH_ALL_TYPE_ROUTING_RULES_IP6 = 6, - REFRESH_ALL_TYPE_QDISCS = 7, - REFRESH_ALL_TYPE_TFILTERS = 8, - - _REFRESH_ALL_TYPE_NUM, -} RefreshAllType; - -typedef struct { - NMPObjectType obj_type; - - /* for NLM_F_DUMP, which address family to request. */ - int addr_family; -} RefreshAllInfo; - -typedef enum { - DELAYED_ACTION_TYPE_NONE = 0, - -#define F(val, name) ((sizeof(char[(((val)) == (name)) ? 1 : -1]) * 0) + (val)) - DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS = 1 << F(0, REFRESH_ALL_TYPE_LINKS), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES = 1 << F(1, REFRESH_ALL_TYPE_IP4_ADDRESSES), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES = 1 << F(2, REFRESH_ALL_TYPE_IP6_ADDRESSES), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES = 1 << F(3, REFRESH_ALL_TYPE_IP4_ROUTES), - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES = 1 << F(4, REFRESH_ALL_TYPE_IP6_ROUTES), - DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4 = 1 - << F(5, REFRESH_ALL_TYPE_ROUTING_RULES_IP4), - DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6 = 1 - << F(6, REFRESH_ALL_TYPE_ROUTING_RULES_IP6), - DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS = 1 << F(7, REFRESH_ALL_TYPE_QDISCS), - DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS = 1 << F(8, REFRESH_ALL_TYPE_TFILTERS), -#undef F - - DELAYED_ACTION_TYPE_REFRESH_LINK = 1 << 9, - DELAYED_ACTION_TYPE_MASTER_CONNECTED = 1 << 10, - DELAYED_ACTION_TYPE_READ_NETLINK = 1 << 11, - DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE = 1 << 12, - - __DELAYED_ACTION_TYPE_MAX, - - DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL = - DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4 - | DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6, - - DELAYED_ACTION_TYPE_REFRESH_ALL = - 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 - | DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL | DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS - | DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, - - DELAYED_ACTION_TYPE_MAX = __DELAYED_ACTION_TYPE_MAX - 1, -} DelayedActionType; - -#define FOR_EACH_DELAYED_ACTION(iflags, flags_all) \ - for ((iflags) = (DelayedActionType) 0x1LL; ({ \ - gboolean _good = FALSE; \ - \ - nm_assert(nm_utils_is_power_of_two(iflags)); \ - \ - while ((iflags) <= DELAYED_ACTION_TYPE_MAX) { \ - if (NM_FLAGS_ANY((flags_all), (iflags))) { \ - _good = TRUE; \ - break; \ - } \ - (iflags) <<= 1; \ - } \ - _good; \ - }); \ - (iflags) <<= 1) - -typedef enum { - /* Negative values are errors from kernel. Add dummy member to - * make enum signed. */ - _WAIT_FOR_NL_RESPONSE_RESULT_SYSTEM_ERROR = G_MININT, - - 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, - WAIT_FOR_NL_RESPONSE_RESULT_FAILED_SETNS, -} WaitForNlResponseResult; - -typedef enum { - DELAYED_ACTION_RESPONSE_TYPE_VOID = 0, - DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS = 1, - DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET = 2, -} DelayedActionWaitForNlResponseType; - -typedef struct { - guint32 seq_number; - WaitForNlResponseResult seq_result; - DelayedActionWaitForNlResponseType response_type; - gint64 timeout_abs_ns; - WaitForNlResponseResult * out_seq_result; - char ** out_errmsg; - union { - int * out_refresh_all_in_progress; - NMPObject **out_route_get; - gpointer out_data; - } response; -} DelayedActionWaitForNlResponseData; - -/*****************************************************************************/ - -typedef struct { - struct nl_sock *genl; - - struct nl_sock *nlh; - - GSource *event_source; - - guint32 nlh_seq_next; -#if NM_MORE_LOGGING - guint32 nlh_seq_last_handled; -#endif - guint32 nlh_seq_last_seen; - - guint32 pruning[_REFRESH_ALL_TYPE_NUM]; - - GHashTable *sysctl_get_prev_values; - CList sysctl_list; - - NMUdevClient *udev_client; - - struct { - /* which delayed actions are scheduled, as marked in @flags. - * Some types have additional arguments in the fields below. */ - DelayedActionType flags; - - /* counter that a refresh all action is in progress, separated - * by type. */ - int refresh_all_in_progress[_REFRESH_ALL_TYPE_NUM]; - - GPtrArray *list_master_connected; - GPtrArray *list_refresh_link; - GArray * list_wait_for_nl_response; - - int is_handling; - } delayed_action; -} NMLinuxPlatformPrivate; - -struct _NMLinuxPlatform { - NMPlatform parent; - NMLinuxPlatformPrivate _priv; -}; - -struct _NMLinuxPlatformClass { - NMPlatformClass parent; -}; - -G_DEFINE_TYPE(NMLinuxPlatform, nm_linux_platform, NM_TYPE_PLATFORM) - -#define NM_LINUX_PLATFORM_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMLinuxPlatform, NM_IS_LINUX_PLATFORM, NMPlatform) - -/*****************************************************************************/ - -#define _NMLOG_PREFIX_NAME "platform-linux" -#define _NMLOG_DOMAIN LOGD_PLATFORM -#define _NMLOG2_DOMAIN LOGD_PLATFORM -#define _NMLOG(level, ...) _LOG(level, _NMLOG_DOMAIN, platform, __VA_ARGS__) -#define _NMLOG_err(errsv, level, ...) _LOG_err(errsv, level, _NMLOG_DOMAIN, platform, __VA_ARGS__) -#define _NMLOG2(level, ...) _LOG(level, _NMLOG2_DOMAIN, NULL, __VA_ARGS__) -#define _NMLOG2_err(errsv, level, ...) _LOG_err(errsv, level, _NMLOG2_DOMAIN, NULL, __VA_ARGS__) - -#define _LOG_print(__level, __domain, __errsv, self, ...) \ - G_STMT_START \ - { \ - char __prefix[32]; \ - const char * __p_prefix = _NMLOG_PREFIX_NAME; \ - NMPlatform *const __self = (self); \ - \ - if (__self && nm_platform_get_log_with_ptr(__self)) { \ - g_snprintf(__prefix, sizeof(__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \ - __p_prefix = __prefix; \ - } \ - _nm_log(__level, \ - __domain, \ - __errsv, \ - NULL, \ - NULL, \ - "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - __p_prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - G_STMT_END - -#define _LOG(level, domain, self, ...) \ - G_STMT_START \ - { \ - const NMLogLevel __level = (level); \ - const NMLogDomain __domain = (domain); \ - \ - if (nm_logging_enabled(__level, __domain)) { \ - _LOG_print(__level, __domain, 0, self, __VA_ARGS__); \ - } \ - } \ - G_STMT_END - -#define _LOG_err(errsv, level, domain, self, ...) \ - G_STMT_START \ - { \ - const NMLogLevel __level = (level); \ - const NMLogDomain __domain = (domain); \ - \ - if (nm_logging_enabled(__level, __domain)) { \ - int __errsv = (errsv); \ - \ - /* The %m format specifier (GNU extension) would already allow you to specify the error - * message conveniently (and nm_log would get that right too). But we don't want to depend - * on that, so instead append the message at the end. - * Currently, users are expected not to use %m in the format string. */ \ - _LOG_print( \ - __level, \ - __domain, \ - __errsv, \ - self, \ - _NM_UTILS_MACRO_FIRST(__VA_ARGS__) ": %s (%d)" _NM_UTILS_MACRO_REST(__VA_ARGS__), \ - nm_strerror_native(__errsv), \ - __errsv); \ - } \ - } \ - G_STMT_END - -/*****************************************************************************/ - -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_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_on_change(NMPlatform * platform, - NMPCacheOpsType cache_op, - const NMPObject *obj_old, - const NMPObject *obj_new); -static void cache_prune_all(NMPlatform *platform); -static gboolean event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks); -static struct nl_sock *_genl_sock(NMLinuxPlatform *platform); - -/*****************************************************************************/ - -static int -wait_for_nl_response_to_nmerr(WaitForNlResponseResult seq_result) -{ - if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) - return 0; - if (seq_result < 0) - return (int) seq_result; - return -NME_PL_NETLINK; -} - -static const char * -wait_for_nl_response_to_string(WaitForNlResponseResult seq_result, - const char * errmsg, - char * buf, - gsize buf_size) -{ - char *buf0 = buf; - - 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%s%s)", - -((int) seq_result), - nm_strerror_native(-((int) seq_result)), - errmsg ? " - " : "", - errmsg ?: ""); - } else - nm_utils_strbuf_append(&buf, &buf_size, "internal failure %d", (int) seq_result); - break; - } - return buf0; -} - -/****************************************************************** - * Various utilities - ******************************************************************/ - -static int -_vlan_qos_mapping_cmp_from(gconstpointer a, gconstpointer b, gpointer user_data) -{ - const NMVlanQosMapping *map_a = a; - const NMVlanQosMapping *map_b = b; - - if (map_a->from != map_b->from) - return map_a->from < map_b->from ? -1 : 1; - return 0; -} - -static int -_vlan_qos_mapping_cmp_from_ptr(gconstpointer a, gconstpointer b, gpointer user_data) -{ - return _vlan_qos_mapping_cmp_from(*((const NMVlanQosMapping **) a), - *((const NMVlanQosMapping **) b), - NULL); -} - -/****************************************************************** - * NMLinkType functions - ******************************************************************/ - -typedef struct { - const char *type_string; - - /* 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; - - /* 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 const LinkDesc link_descs[] = { - [NM_LINK_TYPE_NONE] = {"none", NULL, NULL}, - [NM_LINK_TYPE_UNKNOWN] = {"unknown", NULL, NULL}, - [NM_LINK_TYPE_ANY] = {"any", NULL, NULL}, - - [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_NET] = {"wwan", NULL, "wwan"}, - [NM_LINK_TYPE_WIMAX] = {"wimax", "wimax", "wimax"}, - [NM_LINK_TYPE_WPAN] = {"wpan", NULL, NULL}, - [NM_LINK_TYPE_6LOWPAN] = {"6lowpan", NULL, NULL}, - - [NM_LINK_TYPE_BNEP] = {"bluetooth", NULL, "bluetooth"}, - [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_IP6GRE] = {"ip6gre", "ip6gre", NULL}, - [NM_LINK_TYPE_IP6GRETAP] = {"ip6gretap", "ip6gretap", NULL}, - [NM_LINK_TYPE_IPIP] = {"ipip", "ipip", NULL}, - [NM_LINK_TYPE_LOOPBACK] = {"loopback", NULL, NULL}, - [NM_LINK_TYPE_MACSEC] = {"macsec", "macsec", 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_PPP] = {"ppp", NULL, "ppp"}, - [NM_LINK_TYPE_SIT] = {"sit", "sit", NULL}, - [NM_LINK_TYPE_TUN] = {"tun", "tun", NULL}, - [NM_LINK_TYPE_VETH] = {"veth", "veth", NULL}, - [NM_LINK_TYPE_VLAN] = {"vlan", "vlan", "vlan"}, - [NM_LINK_TYPE_VRF] = {"vrf", "vrf", "vrf"}, - [NM_LINK_TYPE_VXLAN] = {"vxlan", "vxlan", "vxlan"}, - [NM_LINK_TYPE_WIREGUARD] = {"wireguard", "wireguard", "wireguard"}, - - [NM_LINK_TYPE_BRIDGE] = {"bridge", "bridge", "bridge"}, - [NM_LINK_TYPE_BOND] = {"bond", "bond", "bond"}, - [NM_LINK_TYPE_TEAM] = {"team", "team", NULL}, -}; - -static const LinkDesc * -_link_desc_from_link_type(NMLinkType link_type) -{ - nm_assert(_NM_INT_NOT_NEGATIVE(link_type)); - nm_assert(link_type < G_N_ELEMENTS(link_descs)); - nm_assert(link_descs[link_type].type_string); - - return &link_descs[link_type]; -} - -static NMLinkType -_link_type_from_rtnl_type(const char *name) -{ - static const NMLinkType LIST[] = { - NM_LINK_TYPE_BOND, /* "bond" */ - NM_LINK_TYPE_BRIDGE, /* "bridge" */ - NM_LINK_TYPE_DUMMY, /* "dummy" */ - NM_LINK_TYPE_GRE, /* "gre" */ - NM_LINK_TYPE_GRETAP, /* "gretap" */ - NM_LINK_TYPE_IFB, /* "ifb" */ - NM_LINK_TYPE_IP6GRE, /* "ip6gre" */ - NM_LINK_TYPE_IP6GRETAP, /* "ip6gretap" */ - NM_LINK_TYPE_IP6TNL, /* "ip6tnl" */ - NM_LINK_TYPE_IPIP, /* "ipip" */ - NM_LINK_TYPE_MACSEC, /* "macsec" */ - NM_LINK_TYPE_MACVLAN, /* "macvlan" */ - NM_LINK_TYPE_MACVTAP, /* "macvtap" */ - NM_LINK_TYPE_OPENVSWITCH, /* "openvswitch" */ - NM_LINK_TYPE_SIT, /* "sit" */ - NM_LINK_TYPE_TEAM, /* "team" */ - NM_LINK_TYPE_TUN, /* "tun" */ - NM_LINK_TYPE_VETH, /* "veth" */ - NM_LINK_TYPE_VLAN, /* "vlan" */ - NM_LINK_TYPE_VRF, /* "vrf" */ - NM_LINK_TYPE_VXLAN, /* "vxlan" */ - NM_LINK_TYPE_WIMAX, /* "wimax" */ - NM_LINK_TYPE_WIREGUARD, /* "wireguard" */ - }; - - nm_assert(name); - - if (NM_MORE_ASSERT_ONCE(5)) { - int i, j, k; - - for (i = 0; i < G_N_ELEMENTS(LIST); i++) { - nm_assert(_link_desc_from_link_type(LIST[i]) == &link_descs[LIST[i]]); - nm_assert(link_descs[LIST[i]].rtnl_type); - if (i > 0) - nm_assert(strcmp(link_descs[LIST[i - 1]].rtnl_type, link_descs[LIST[i]].rtnl_type) - < 0); - } - for (i = 0; i < G_N_ELEMENTS(link_descs); i++) { - if (!link_descs[i].rtnl_type) - continue; - for (j = 0, k = 0; j < G_N_ELEMENTS(LIST); j++) - k += (LIST[j] == i); - nm_assert(k == 1); - } - } - - { - int imin = 0; - int imax = (G_N_ELEMENTS(LIST) - 1); - int imid = (G_N_ELEMENTS(LIST) - 1) / 2; - - for (;;) { - const int cmp = strcmp(link_descs[LIST[imid]].rtnl_type, name); - - if (G_UNLIKELY(cmp == 0)) - return LIST[imid]; - - if (cmp < 0) - imin = imid + 1; - else - imax = imid - 1; - - if (G_UNLIKELY(imin > imax)) - return NM_LINK_TYPE_NONE; - - imid = (imin + imax) / 2; - } - } -} - -static NMLinkType -_link_type_from_devtype(const char *name) -{ - static const NMLinkType LIST[] = { - NM_LINK_TYPE_BNEP, /* "bluetooth" */ - NM_LINK_TYPE_BOND, /* "bond" */ - NM_LINK_TYPE_BRIDGE, /* "bridge" */ - NM_LINK_TYPE_PPP, /* "ppp" */ - NM_LINK_TYPE_VLAN, /* "vlan" */ - NM_LINK_TYPE_VRF, /* "vrf" */ - NM_LINK_TYPE_VXLAN, /* "vxlan" */ - NM_LINK_TYPE_WIMAX, /* "wimax" */ - NM_LINK_TYPE_WIREGUARD, /* "wireguard" */ - NM_LINK_TYPE_WIFI, /* "wlan" */ - NM_LINK_TYPE_WWAN_NET, /* "wwan" */ - }; - - nm_assert(name); - - if (NM_MORE_ASSERT_ONCE(5)) { - int i, j, k; - - for (i = 0; i < G_N_ELEMENTS(LIST); i++) { - nm_assert(_link_desc_from_link_type(LIST[i]) == &link_descs[LIST[i]]); - nm_assert(link_descs[LIST[i]].devtype); - if (i > 0) - nm_assert(strcmp(link_descs[LIST[i - 1]].devtype, link_descs[LIST[i]].devtype) < 0); - } - for (i = 0; i < G_N_ELEMENTS(link_descs); i++) { - if (!link_descs[i].devtype) - continue; - for (j = 0, k = 0; j < G_N_ELEMENTS(LIST); j++) - k += (LIST[j] == i); - nm_assert(k == 1); - } - } - - { - int imin = 0; - int imax = (G_N_ELEMENTS(LIST) - 1); - int imid = (G_N_ELEMENTS(LIST) - 1) / 2; - - for (;;) { - const int cmp = strcmp(link_descs[LIST[imid]].devtype, name); - - if (G_UNLIKELY(cmp == 0)) - return LIST[imid]; - - if (cmp < 0) - imin = imid + 1; - else - imax = imid - 1; - - if (G_UNLIKELY(imin > imax)) - return NM_LINK_TYPE_NONE; - - imid = (imin + imax) / 2; - } - } -} - -static const char * -nm_link_type_to_rtnl_type_string(NMLinkType link_type) -{ - return _link_desc_from_link_type(link_type)->rtnl_type; -} - -const char * -nm_link_type_to_string(NMLinkType link_type) -{ - return _link_desc_from_link_type(link_type)->type_string; -} - -/****************************************************************** - * Utilities - ******************************************************************/ - -/* _timestamp_nl_to_ms: - * @timestamp_nl: a timestamp from ifa_cacheinfo. - * @monotonic_ms: *now* in CLOCK_MONOTONIC. Needed to estimate the current - * uptime and how often timestamp_nl wrapped. - * - * Convert the timestamp from ifa_cacheinfo to CLOCK_MONOTONIC milliseconds. - * The ifa_cacheinfo fields tstamp and cstamp contains timestamps that counts - * with in 1/100th of a second of clock_gettime(CLOCK_MONOTONIC). However, - * the uint32 counter wraps every 497 days of uptime, so we have to compensate - * for that. */ -static gint64 -_timestamp_nl_to_ms(guint32 timestamp_nl, gint64 monotonic_ms) -{ - const gint64 WRAP_INTERVAL = (((gint64) G_MAXUINT32) + 1) * (1000 / 100); - gint64 timestamp_nl_ms; - - /* convert timestamp from 1/100th of a second to msec. */ - timestamp_nl_ms = ((gint64) timestamp_nl) * (1000 / 100); - - /* timestamp wraps every 497 days. Try to compensate for that.*/ - if (timestamp_nl_ms > monotonic_ms) { - /* timestamp_nl_ms is in the future. Truncate it to *now* */ - timestamp_nl_ms = monotonic_ms; - } else if (monotonic_ms >= WRAP_INTERVAL) { - timestamp_nl_ms += (monotonic_ms / WRAP_INTERVAL) * WRAP_INTERVAL; - if (timestamp_nl_ms > monotonic_ms) - timestamp_nl_ms -= WRAP_INTERVAL; - } - - return timestamp_nl_ms; -} - -static guint32 -_addrtime_timestamp_to_nm(guint32 timestamp, gint32 *out_now_nm) -{ - gint64 now_nl; - gint64 now_nm; - gint64 result; - - /* timestamp is unset. Default to 1. */ - if (!timestamp) { - NM_SET_OUT(out_now_nm, 0); - return 1; - } - - /* do all the calculations in milliseconds scale */ - - now_nm = nm_utils_get_monotonic_timestamp_msec(); - now_nl = nm_utils_clock_gettime_msec(CLOCK_MONOTONIC); - - nm_assert(now_nm >= 1000); - nm_assert(now_nl >= 0); - - result = now_nm - (now_nl - _timestamp_nl_to_ms(timestamp, now_nl)); - - NM_SET_OUT(out_now_nm, now_nm / 1000); - - /* converting the timestamp into nm_utils_get_monotonic_timestamp_msec() 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_msec() 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_sec(); - } - 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; - - *link_cached = obj; - *completed_from_cache = TRUE; - } - return *link_cached; -} - -/*****************************************************************************/ - -#define DEVTYPE_PREFIX "DEVTYPE=" - -static char * -_linktype_read_devtype(int dirfd) -{ - gs_free char *contents = NULL; - char * cont, *end; - - nm_assert(dirfd >= 0); - - if (!nm_utils_file_get_contents(dirfd, - "uevent", - 1 * 1024 * 1024, - NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE, - &contents, - NULL, - NULL, - NULL)) - return NULL; - for (cont = contents; cont; cont = end) { - end = strpbrk(cont, "\r\n"); - if (end) - *end++ = '\0'; - if (strncmp(cont, DEVTYPE_PREFIX, NM_STRLEN(DEVTYPE_PREFIX)) == 0) { - cont += NM_STRLEN(DEVTYPE_PREFIX); - memmove(contents, cont, strlen(cont) + 1); - return g_steal_pointer(&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) -{ - NMLinkType link_type; - - NMTST_ASSERT_PLATFORM_NETNS_CURRENT(platform); - nm_assert(ifname); - nm_assert(_link_type_from_devtype("wlan") == NM_LINK_TYPE_WIFI); - nm_assert(_link_type_from_rtnl_type("bond") == NM_LINK_TYPE_BOND); - - 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" or "name" changed. If "name" changed, - * it means that their type may not have been determined correctly - * due to race conditions while accessing sysfs. - * - * This way, we save additional 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 interface to other netns). Thus here there is a tiny potential - * of messing stuff up. */ - if (obj && obj->_link.netlink.is_in_netlink - && !NM_IN_SET(obj->link.type, NM_LINK_TYPE_UNKNOWN, NM_LINK_TYPE_NONE) - && nm_streq(ifname, obj->link.name) && (!kind || nm_streq0(kind, obj->link.kind))) { - nm_assert(obj->link.kind == g_intern_string(obj->link.kind)); - *out_kind = obj->link.kind; - return obj->link.type; - } - } - - /* we intern kind to not require us to keep the pointer alive. Essentially - * leaking it in a global cache. That should be safe enough, because the - * kind comes only from kernel messages, which depend on the number of - * available drivers. So, there is not the danger that we leak uncontrolled - * many kinds. */ - *out_kind = g_intern_string(kind); - - if (kind) { - link_type = _link_type_from_rtnl_type(kind); - if (link_type != NM_LINK_TYPE_NONE) - return link_type; - } - - 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; - else if (arptype == ARPHRD_PPP) - return NM_LINK_TYPE_PPP; - else if (arptype == ARPHRD_IEEE802154) - return NM_LINK_TYPE_WPAN; - else if (arptype == ARPHRD_6LOWPAN) - return NM_LINK_TYPE_6LOWPAN; - - { - NMPUtilsEthtoolDriverInfo driver_info; - - /* Fallback OVS detection for kernel <= 3.16 */ - if (nmp_utils_ethtool_get_driver_info(ifindex, &driver_info)) { - if (nm_streq(driver_info.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 (nm_streq(driver_info.driver, "ctcm")) - return NM_LINK_TYPE_ETHERNET; - } - } - } - - { - nm_auto_close int dirfd = -1; - gs_free char * devtype = NULL; - char ifname_verified[IFNAMSIZ]; - - dirfd = nmp_utils_sysctl_open_netdir(ifindex, ifname, ifname_verified); - if (dirfd >= 0) { - if (faccessat(dirfd, "anycast_mask", F_OK, 0) == 0) - return NM_LINK_TYPE_OLPC_MESH; - - devtype = _linktype_read_devtype(dirfd); - if (devtype) { - link_type = _link_type_from_devtype(devtype); - if (link_type != NM_LINK_TYPE_NONE) { - if (link_type == NM_LINK_TYPE_BNEP && arptype != ARPHRD_ETHER) { - /* Both BNEP and 6lowpan use DEVTYPE=bluetooth, so we must - * use arptype to distinguish between them. - */ - } else - return link_type; - } - } - - /* Fallback for drivers that don't call SET_NETDEV_DEVTYPE() */ - if (nm_wifi_utils_is_wifi(dirfd, ifname_verified)) - return NM_LINK_TYPE_WIFI; - } - - if (arptype == ARPHRD_ETHER) { - /* Misc non-upstream WWAN drivers. rmnet is Qualcomm's proprietary - * modem interface, ccmni is MediaTek's. FIXME: these drivers should - * really set devtype=WWAN. - */ - if (g_str_has_prefix(ifname, "rmnet") || g_str_has_prefix(ifname, "rev_rmnet") - || g_str_has_prefix(ifname, "ccmni")) - return NM_LINK_TYPE_WWAN_NET; - - /* 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 (!kind && !devtype) - return NM_LINK_TYPE_ETHERNET; - - /* The USB gadget interfaces behave and look like ordinary ethernet devices - * aside from the DEVTYPE. */ - if (nm_streq0(devtype, "gadget")) - return NM_LINK_TYPE_ETHERNET; - - /* Distributed Switch Architecture switch chips */ - if (nm_streq0(devtype, "dsa")) - return NM_LINK_TYPE_ETHERNET; - } - } - - return NM_LINK_TYPE_UNKNOWN; -} - -/****************************************************************** - * libnl unility functions and wrappers - ******************************************************************/ - -#define NLMSG_TAIL(nmsg) ((struct rtattr *) (((char *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) - -/* copied from iproute2's addattr_l(). */ -static gboolean -_nl_addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, int alen) -{ - int len = RTA_LENGTH(alen); - struct rtattr *rta; - - if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) - return FALSE; - - rta = NLMSG_TAIL(n); - rta->rta_type = type; - rta->rta_len = len; - memcpy(RTA_DATA(rta), data, alen); - n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); - return TRUE; -} - -/****************************************************************** - * NMPObject/netlink functions - ******************************************************************/ - -#define _check_addr_or_return_val(tb, attr, addr_len, ret_val) \ - ({ \ - const struct nlattr *__t = (tb)[(attr)]; \ - \ - if (__t) { \ - if (nla_len(__t) != (addr_len)) { \ - return ret_val; \ - } \ - } \ - !!__t; \ - }) - -#define _check_addr_or_return_null(tb, attr, addr_len) \ - _check_addr_or_return_val(tb, attr, addr_len, NULL) - -/*****************************************************************************/ - -/* Copied and heavily modified from libnl3's inet6_parse_protinfo(). */ -static gboolean -_parse_af_inet6(NMPlatform * platform, - struct nlattr * attr, - NMUtilsIPv6IfaceId *out_token, - gboolean * out_token_valid, - guint8 * out_addr_gen_mode_inv, - gboolean * out_addr_gen_mode_valid) -{ - static const struct nla_policy policy[] = { - [IFLA_INET6_FLAGS] = {.type = NLA_U32}, - [IFLA_INET6_CACHEINFO] = {.minlen = nm_offsetofend(struct ifla_cacheinfo, retrans_time)}, - [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[G_N_ELEMENTS(policy)]; - struct in6_addr i6_token; - gboolean token_valid = FALSE; - gboolean addr_gen_mode_valid = FALSE; - guint8 i6_addr_gen_mode_inv = 0; - - if (nla_parse_nested_arr(tb, attr, policy) < 0) - return FALSE; - - if (tb[IFLA_INET6_CONF] && nla_len(tb[IFLA_INET6_CONF]) % 4) - return FALSE; - if (tb[IFLA_INET6_STATS] && nla_len(tb[IFLA_INET6_STATS]) % 8) - return FALSE; - if (tb[IFLA_INET6_ICMP6STATS] && nla_len(tb[IFLA_INET6_ICMP6STATS]) % 8) - return FALSE; - - if (_check_addr_or_return_val(tb, IFLA_INET6_TOKEN, sizeof(struct in6_addr), FALSE)) { - nla_memcpy(&i6_token, tb[IFLA_INET6_TOKEN], sizeof(struct in6_addr)); - token_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. */ - if (!_nm_platform_kernel_support_detected(NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL)) { - /* IFLA_INET6_ADDR_GEN_MODE was added in kernel 3.17, dated 5 October, 2014. */ - _nm_platform_kernel_support_init(NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL, - tb[IFLA_INET6_ADDR_GEN_MODE] ? 1 : -1); - } - - 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". */ - return FALSE; - } - addr_gen_mode_valid = TRUE; - } - - if (token_valid) { - *out_token_valid = token_valid; - nm_utils_ipv6_interface_identifier_get_from_addr(out_token, &i6_token); - } - if (addr_gen_mode_valid) { - *out_addr_gen_mode_valid = addr_gen_mode_valid; - *out_addr_gen_mode_inv = i6_addr_gen_mode_inv; - } - return TRUE; -} - -/*****************************************************************************/ - -static NMPObject * -_parse_lnk_bridge(const char *kind, struct nlattr *info_data) -{ - static const struct nla_policy policy[] = { - [IFLA_BR_FORWARD_DELAY] = {.type = NLA_U32}, - [IFLA_BR_HELLO_TIME] = {.type = NLA_U32}, - [IFLA_BR_MAX_AGE] = {.type = NLA_U32}, - [IFLA_BR_AGEING_TIME] = {.type = NLA_U32}, - [IFLA_BR_STP_STATE] = {.type = NLA_U32}, - [IFLA_BR_PRIORITY] = {.type = NLA_U16}, - [IFLA_BR_VLAN_PROTOCOL] = {.type = NLA_U16}, - [IFLA_BR_VLAN_STATS_ENABLED] = {.type = NLA_U8}, - [IFLA_BR_GROUP_FWD_MASK] = {.type = NLA_U16}, - [IFLA_BR_GROUP_ADDR] = {.minlen = sizeof(NMEtherAddr)}, - [IFLA_BR_MCAST_SNOOPING] = {.type = NLA_U8}, - [IFLA_BR_MCAST_ROUTER] = {.type = NLA_U8}, - [IFLA_BR_MCAST_QUERY_USE_IFADDR] = {.type = NLA_U8}, - [IFLA_BR_MCAST_QUERIER] = {.type = NLA_U8}, - [IFLA_BR_MCAST_HASH_MAX] = {.type = NLA_U32}, - [IFLA_BR_MCAST_LAST_MEMBER_CNT] = {.type = NLA_U32}, - [IFLA_BR_MCAST_STARTUP_QUERY_CNT] = {.type = NLA_U32}, - [IFLA_BR_MCAST_LAST_MEMBER_INTVL] = {.type = NLA_U64}, - [IFLA_BR_MCAST_MEMBERSHIP_INTVL] = {.type = NLA_U64}, - [IFLA_BR_MCAST_QUERIER_INTVL] = {.type = NLA_U64}, - [IFLA_BR_MCAST_QUERY_INTVL] = {.type = NLA_U64}, - [IFLA_BR_MCAST_QUERY_RESPONSE_INTVL] = {.type = NLA_U64}, - [IFLA_BR_MCAST_STARTUP_QUERY_INTVL] = {.type = NLA_U64}, - }; - NMPlatformLnkBridge *props; - struct nlattr * tb[G_N_ELEMENTS(policy)]; - NMPObject * obj; - - if (!info_data || !nm_streq0(kind, "bridge")) - return NULL; - - if (nla_parse_nested_arr(tb, info_data, policy) < 0) - return NULL; - - obj = nmp_object_new(NMP_OBJECT_TYPE_LNK_BRIDGE, NULL); - - props = &obj->lnk_bridge; - *props = nm_platform_lnk_bridge_default; - - if (!_nm_platform_kernel_support_detected( - NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_BR_VLAN_STATS_ENABLED)) { - /* IFLA_BR_VLAN_STATS_ENABLED was added in kernel 4.10 on April 30, 2016. - * See commit 6dada9b10a0818ba72c249526a742c8c41274a73. */ - _nm_platform_kernel_support_init(NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_BR_VLAN_STATS_ENABLED, - tb[IFLA_BR_VLAN_STATS_ENABLED] ? 1 : -1); - } - - if (tb[IFLA_BR_FORWARD_DELAY]) - props->forward_delay = nla_get_u32(tb[IFLA_BR_FORWARD_DELAY]); - if (tb[IFLA_BR_HELLO_TIME]) - props->hello_time = nla_get_u32(tb[IFLA_BR_HELLO_TIME]); - if (tb[IFLA_BR_MAX_AGE]) - props->max_age = nla_get_u32(tb[IFLA_BR_MAX_AGE]); - if (tb[IFLA_BR_AGEING_TIME]) - props->ageing_time = nla_get_u32(tb[IFLA_BR_AGEING_TIME]); - if (tb[IFLA_BR_STP_STATE]) - props->stp_state = !!nla_get_u32(tb[IFLA_BR_STP_STATE]); - if (tb[IFLA_BR_PRIORITY]) - props->priority = nla_get_u16(tb[IFLA_BR_PRIORITY]); - if (tb[IFLA_BR_VLAN_PROTOCOL]) - props->vlan_protocol = ntohs(nla_get_u16(tb[IFLA_BR_VLAN_PROTOCOL])); - if (tb[IFLA_BR_VLAN_STATS_ENABLED]) - props->vlan_stats_enabled = nla_get_u8(tb[IFLA_BR_VLAN_STATS_ENABLED]); - if (tb[IFLA_BR_GROUP_FWD_MASK]) - props->group_fwd_mask = nla_get_u16(tb[IFLA_BR_GROUP_FWD_MASK]); - if (tb[IFLA_BR_GROUP_ADDR]) - props->group_addr = *nla_data_as(NMEtherAddr, tb[IFLA_BR_GROUP_ADDR]); - if (tb[IFLA_BR_MCAST_SNOOPING]) - props->mcast_snooping = !!nla_get_u8(tb[IFLA_BR_MCAST_SNOOPING]); - if (tb[IFLA_BR_MCAST_ROUTER]) - props->mcast_router = nla_get_u8(tb[IFLA_BR_MCAST_ROUTER]); - if (tb[IFLA_BR_MCAST_QUERY_USE_IFADDR]) - props->mcast_query_use_ifaddr = !!nla_get_u8(tb[IFLA_BR_MCAST_QUERY_USE_IFADDR]); - if (tb[IFLA_BR_MCAST_QUERIER]) - props->mcast_querier = nla_get_u8(tb[IFLA_BR_MCAST_QUERIER]); - if (tb[IFLA_BR_MCAST_HASH_MAX]) - props->mcast_hash_max = nla_get_u32(tb[IFLA_BR_MCAST_HASH_MAX]); - if (tb[IFLA_BR_MCAST_LAST_MEMBER_CNT]) - props->mcast_last_member_count = nla_get_u32(tb[IFLA_BR_MCAST_LAST_MEMBER_CNT]); - if (tb[IFLA_BR_MCAST_STARTUP_QUERY_CNT]) - props->mcast_startup_query_count = nla_get_u32(tb[IFLA_BR_MCAST_STARTUP_QUERY_CNT]); - if (tb[IFLA_BR_MCAST_LAST_MEMBER_INTVL]) - props->mcast_last_member_interval = nla_get_u64(tb[IFLA_BR_MCAST_LAST_MEMBER_INTVL]); - if (tb[IFLA_BR_MCAST_MEMBERSHIP_INTVL]) - props->mcast_membership_interval = nla_get_u64(tb[IFLA_BR_MCAST_MEMBERSHIP_INTVL]); - if (tb[IFLA_BR_MCAST_QUERIER_INTVL]) - props->mcast_querier_interval = nla_get_u64(tb[IFLA_BR_MCAST_QUERIER_INTVL]); - if (tb[IFLA_BR_MCAST_QUERY_INTVL]) - props->mcast_query_interval = nla_get_u64(tb[IFLA_BR_MCAST_QUERY_INTVL]); - if (tb[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL]) - props->mcast_query_response_interval = nla_get_u64(tb[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL]); - if (tb[IFLA_BR_MCAST_STARTUP_QUERY_INTVL]) - props->mcast_startup_query_interval = nla_get_u64(tb[IFLA_BR_MCAST_STARTUP_QUERY_INTVL]); - - return obj; -} - -/***********************************************************************************/ - -static NMPObject * -_parse_lnk_gre(const char *kind, struct nlattr *info_data) -{ - static const struct nla_policy policy[] = { - [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[G_N_ELEMENTS(policy)]; - NMPObject * obj; - NMPlatformLnkGre *props; - gboolean is_tap; - - if (!info_data || !kind) - return NULL; - - if (nm_streq(kind, "gretap")) - is_tap = TRUE; - else if (nm_streq(kind, "gre")) - is_tap = FALSE; - else - return NULL; - - if (nla_parse_nested_arr(tb, info_data, policy) < 0) - return NULL; - - obj = nmp_object_new(is_tap ? NMP_OBJECT_TYPE_LNK_GRETAP : 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]); - props->is_tap = is_tap; - - 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 const struct nla_policy policy[] = { - [IFLA_IPOIB_PKEY] = {.type = NLA_U16}, - [IFLA_IPOIB_MODE] = {.type = NLA_U16}, - [IFLA_IPOIB_UMCAST] = {.type = NLA_U16}, - }; - struct nlattr * tb[G_N_ELEMENTS(policy)]; - NMPlatformLnkInfiniband *info; - NMPObject * obj; - const char * mode; - - if (!info_data || !nm_streq0(kind, "ipoib")) - return NULL; - - if (nla_parse_nested_arr(tb, info_data, policy) < 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 obj; -} - -/*****************************************************************************/ - -static NMPObject * -_parse_lnk_ip6tnl(const char *kind, struct nlattr *info_data) -{ - static const struct nla_policy policy[] = { - [IFLA_IPTUN_LINK] = {.type = NLA_U32}, - [IFLA_IPTUN_LOCAL] = {.minlen = sizeof(struct in6_addr)}, - [IFLA_IPTUN_REMOTE] = {.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}, - [IFLA_IPTUN_FLAGS] = {.type = NLA_U32}, - }; - struct nlattr * tb[G_N_ELEMENTS(policy)]; - NMPObject * obj; - NMPlatformLnkIp6Tnl *props; - guint32 flowinfo; - - if (!info_data || !nm_streq0(kind, "ip6tnl")) - return NULL; - - if (nla_parse_nested_arr(tb, info_data, policy) < 0) - return NULL; - - 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]) - props->local = *nla_data_as(struct in6_addr, tb[IFLA_IPTUN_LOCAL]); - if (tb[IFLA_IPTUN_REMOTE]) - props->remote = *nla_data_as(struct in6_addr, tb[IFLA_IPTUN_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]); - if (tb[IFLA_IPTUN_FLAGS]) - props->flags = nla_get_u32(tb[IFLA_IPTUN_FLAGS]); - - return obj; -} - -static NMPObject * -_parse_lnk_ip6gre(const char *kind, struct nlattr *info_data) -{ - static const struct nla_policy policy[] = { - [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_UNSPEC, .minlen = sizeof(struct in6_addr)}, - [IFLA_GRE_REMOTE] = {.type = NLA_UNSPEC, .minlen = sizeof(struct in6_addr)}, - [IFLA_GRE_TTL] = {.type = NLA_U8}, - [IFLA_GRE_ENCAP_LIMIT] = {.type = NLA_U8}, - [IFLA_GRE_FLOWINFO] = {.type = NLA_U32}, - [IFLA_GRE_FLAGS] = {.type = NLA_U32}, - }; - struct nlattr * tb[G_N_ELEMENTS(policy)]; - NMPObject * obj; - NMPlatformLnkIp6Tnl *props; - guint32 flowinfo; - gboolean is_tap; - - if (!info_data || !kind) - return NULL; - - if (nm_streq(kind, "ip6gre")) - is_tap = FALSE; - else if (nm_streq(kind, "ip6gretap")) - is_tap = TRUE; - else - return NULL; - - if (nla_parse_nested_arr(tb, info_data, policy) < 0) - return NULL; - - obj = nmp_object_new(is_tap ? NMP_OBJECT_TYPE_LNK_IP6GRETAP : NMP_OBJECT_TYPE_LNK_IP6GRE, NULL); - props = &obj->lnk_ip6tnl; - props->is_gre = TRUE; - props->is_tap = is_tap; - - if (tb[IFLA_GRE_LINK]) - props->parent_ifindex = nla_get_u32(tb[IFLA_GRE_LINK]); - if (tb[IFLA_GRE_IFLAGS]) - props->input_flags = ntohs(nla_get_u16(tb[IFLA_GRE_IFLAGS])); - if (tb[IFLA_GRE_OFLAGS]) - props->output_flags = ntohs(nla_get_u16(tb[IFLA_GRE_OFLAGS])); - if (tb[IFLA_GRE_IKEY]) - props->input_key = ntohl(nla_get_u32(tb[IFLA_GRE_IKEY])); - if (tb[IFLA_GRE_OKEY]) - props->output_key = ntohl(nla_get_u32(tb[IFLA_GRE_OKEY])); - if (tb[IFLA_GRE_LOCAL]) - props->local = *nla_data_as(struct in6_addr, tb[IFLA_GRE_LOCAL]); - if (tb[IFLA_GRE_REMOTE]) - props->remote = *nla_data_as(struct in6_addr, tb[IFLA_GRE_REMOTE]); - if (tb[IFLA_GRE_TTL]) - props->ttl = nla_get_u8(tb[IFLA_GRE_TTL]); - if (tb[IFLA_GRE_ENCAP_LIMIT]) - props->encap_limit = nla_get_u8(tb[IFLA_GRE_ENCAP_LIMIT]); - if (tb[IFLA_GRE_FLOWINFO]) { - flowinfo = ntohl(nla_get_u32(tb[IFLA_GRE_FLOWINFO])); - props->flow_label = flowinfo & IP6_FLOWINFO_FLOWLABEL_MASK; - props->tclass = (flowinfo & IP6_FLOWINFO_TCLASS_MASK) >> IP6_FLOWINFO_TCLASS_SHIFT; - } - if (tb[IFLA_GRE_FLAGS]) - props->flags = nla_get_u32(tb[IFLA_GRE_FLAGS]); - - return obj; -} - -/*****************************************************************************/ - -static NMPObject * -_parse_lnk_ipip(const char *kind, struct nlattr *info_data) -{ - static const struct nla_policy policy[] = { - [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[G_N_ELEMENTS(policy)]; - NMPObject * obj; - NMPlatformLnkIpIp *props; - - if (!info_data || !nm_streq0(kind, "ipip")) - return NULL; - - if (nla_parse_nested_arr(tb, info_data, policy) < 0) - 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 const struct nla_policy policy[] = { - [IFLA_MACVLAN_MODE] = {.type = NLA_U32}, - [IFLA_MACVLAN_FLAGS] = {.type = NLA_U16}, - }; - NMPlatformLnkMacvlan *props; - struct nlattr * tb[G_N_ELEMENTS(policy)]; - NMPObject * obj; - gboolean tap; - - if (!info_data || !kind) - return NULL; - - if (nm_streq(kind, "macvlan")) - tap = FALSE; - else if (nm_streq(kind, "macvtap")) - tap = TRUE; - else - return NULL; - - if (nla_parse_nested_arr(tb, info_data, policy) < 0) - return NULL; - - 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 NMPObject * -_parse_lnk_macsec(const char *kind, struct nlattr *info_data) -{ - static const struct nla_policy policy[] = { - [IFLA_MACSEC_SCI] = {.type = NLA_U64}, - [IFLA_MACSEC_ICV_LEN] = {.type = NLA_U8}, - [IFLA_MACSEC_CIPHER_SUITE] = {.type = NLA_U64}, - [IFLA_MACSEC_WINDOW] = {.type = NLA_U32}, - [IFLA_MACSEC_ENCODING_SA] = {.type = NLA_U8}, - [IFLA_MACSEC_ENCRYPT] = {.type = NLA_U8}, - [IFLA_MACSEC_PROTECT] = {.type = NLA_U8}, - [IFLA_MACSEC_INC_SCI] = {.type = NLA_U8}, - [IFLA_MACSEC_ES] = {.type = NLA_U8}, - [IFLA_MACSEC_SCB] = {.type = NLA_U8}, - [IFLA_MACSEC_REPLAY_PROTECT] = {.type = NLA_U8}, - [IFLA_MACSEC_VALIDATION] = {.type = NLA_U8}, - }; - struct nlattr * tb[G_N_ELEMENTS(policy)]; - NMPObject * obj; - NMPlatformLnkMacsec *props; - - if (!info_data || !nm_streq0(kind, "macsec")) - return NULL; - - if (nla_parse_nested_arr(tb, info_data, policy) < 0) - return NULL; - - obj = nmp_object_new(NMP_OBJECT_TYPE_LNK_MACSEC, NULL); - props = &obj->lnk_macsec; - - if (tb[IFLA_MACSEC_SCI]) { - props->sci = nla_get_be64(tb[IFLA_MACSEC_SCI]); - } - if (tb[IFLA_MACSEC_ICV_LEN]) { - props->icv_length = nla_get_u8(tb[IFLA_MACSEC_ICV_LEN]); - } - if (tb[IFLA_MACSEC_CIPHER_SUITE]) { - props->cipher_suite = nla_get_u64(tb[IFLA_MACSEC_CIPHER_SUITE]); - } - if (tb[IFLA_MACSEC_WINDOW]) { - props->window = nla_get_u32(tb[IFLA_MACSEC_WINDOW]); - } - if (tb[IFLA_MACSEC_ENCODING_SA]) { - props->encoding_sa = !!nla_get_u8(tb[IFLA_MACSEC_ENCODING_SA]); - } - if (tb[IFLA_MACSEC_ENCRYPT]) { - props->encrypt = !!nla_get_u8(tb[IFLA_MACSEC_ENCRYPT]); - } - if (tb[IFLA_MACSEC_PROTECT]) { - props->protect = !!nla_get_u8(tb[IFLA_MACSEC_PROTECT]); - } - if (tb[IFLA_MACSEC_INC_SCI]) { - props->include_sci = !!nla_get_u8(tb[IFLA_MACSEC_INC_SCI]); - } - if (tb[IFLA_MACSEC_ES]) { - props->es = !!nla_get_u8(tb[IFLA_MACSEC_ES]); - } - if (tb[IFLA_MACSEC_SCB]) { - props->scb = !!nla_get_u8(tb[IFLA_MACSEC_SCB]); - } - if (tb[IFLA_MACSEC_REPLAY_PROTECT]) { - props->replay_protect = !!nla_get_u8(tb[IFLA_MACSEC_REPLAY_PROTECT]); - } - if (tb[IFLA_MACSEC_VALIDATION]) { - props->validation = nla_get_u8(tb[IFLA_MACSEC_VALIDATION]); - } - - return obj; -} - -/*****************************************************************************/ - -static NMPObject * -_parse_lnk_sit(const char *kind, struct nlattr *info_data) -{ - static const struct nla_policy policy[] = { - [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[G_N_ELEMENTS(policy)]; - NMPObject * obj; - NMPlatformLnkSit *props; - - if (!info_data || !nm_streq0(kind, "sit")) - return NULL; - - if (nla_parse_nested_arr(tb, info_data, policy) < 0) - return NULL; - - obj = nmp_object_new(NMP_OBJECT_TYPE_LNK_SIT, NULL); - props = &obj->lnk_sit; - - 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; - - return obj; -} - -/*****************************************************************************/ - -static NMPObject * -_parse_lnk_tun(const char *kind, struct nlattr *info_data) -{ - static const struct nla_policy policy[] = { - [IFLA_TUN_OWNER] = {.type = NLA_U32}, - [IFLA_TUN_GROUP] = {.type = NLA_U32}, - [IFLA_TUN_TYPE] = {.type = NLA_U8}, - [IFLA_TUN_PI] = {.type = NLA_U8}, - [IFLA_TUN_VNET_HDR] = {.type = NLA_U8}, - [IFLA_TUN_PERSIST] = {.type = NLA_U8}, - [IFLA_TUN_MULTI_QUEUE] = {.type = NLA_U8}, - [IFLA_TUN_NUM_QUEUES] = {.type = NLA_U32}, - [IFLA_TUN_NUM_DISABLED_QUEUES] = {.type = NLA_U32}, - }; - struct nlattr * tb[G_N_ELEMENTS(policy)]; - NMPObject * obj; - NMPlatformLnkTun *props; - - if (!info_data || !nm_streq0(kind, "tun")) - return NULL; - - if (nla_parse_nested_arr(tb, info_data, policy) < 0) - return NULL; - - if (!tb[IFLA_TUN_TYPE]) - return NULL; - - obj = nmp_object_new(NMP_OBJECT_TYPE_LNK_TUN, NULL); - props = &obj->lnk_tun; - - props->type = nla_get_u8(tb[IFLA_TUN_TYPE]); - - props->pi = !!nla_get_u8_cond(tb, IFLA_TUN_PI, FALSE); - props->vnet_hdr = !!nla_get_u8_cond(tb, IFLA_TUN_VNET_HDR, FALSE); - props->multi_queue = !!nla_get_u8_cond(tb, IFLA_TUN_MULTI_QUEUE, FALSE); - props->persist = !!nla_get_u8_cond(tb, IFLA_TUN_PERSIST, FALSE); - - if (tb[IFLA_TUN_OWNER]) { - props->owner_valid = TRUE; - props->owner = nla_get_u32(tb[IFLA_TUN_OWNER]); - } - if (tb[IFLA_TUN_GROUP]) { - props->group_valid = TRUE; - props->group = nla_get_u32(tb[IFLA_TUN_GROUP]); - } - return obj; -} - -/*****************************************************************************/ - -static gboolean -_vlan_qos_mapping_from_nla(struct nlattr * nlattr, - const NMVlanQosMapping **out_map, - guint * out_n_map) -{ - 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; - - map = array->pdata[i]; - - /* 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; -} - -/* Copied and heavily modified from libnl3's vlan_parse() */ -static NMPObject * -_parse_lnk_vlan(const char *kind, struct nlattr *info_data) -{ - static const struct nla_policy policy[] = { - [IFLA_VLAN_ID] = {.type = NLA_U16}, - [IFLA_VLAN_FLAGS] = {.minlen = nm_offsetofend(struct ifla_vlan_flags, flags)}, - [IFLA_VLAN_INGRESS_QOS] = {.type = NLA_NESTED}, - [IFLA_VLAN_EGRESS_QOS] = {.type = NLA_NESTED}, - [IFLA_VLAN_PROTOCOL] = {.type = NLA_U16}, - }; - struct nlattr *tb[G_N_ELEMENTS(policy)]; - nm_auto_nmpobj NMPObject *obj = NULL; - NMPObject * obj_result; - - if (!info_data || !nm_streq0(kind, "vlan")) - return NULL; - - if (nla_parse_nested_arr(tb, info_data, policy) < 0) - return NULL; - - if (!tb[IFLA_VLAN_ID]) - return NULL; - - obj = nmp_object_new(NMP_OBJECT_TYPE_LNK_VLAN, NULL); - obj->lnk_vlan.id = nla_get_u16(tb[IFLA_VLAN_ID]); - - if (tb[IFLA_VLAN_FLAGS]) { - struct ifla_vlan_flags flags; - - nla_memcpy(&flags, tb[IFLA_VLAN_FLAGS], sizeof(flags)); - - 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; -} - -/*****************************************************************************/ - -/* 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 - -#define IFLA_VRF_TABLE 1 - -/* 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 const struct nla_policy policy[] = { - [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[G_N_ELEMENTS(policy)]; - NMPObject * obj; - - if (!info_data || !nm_streq0(kind, "vxlan")) - return NULL; - - if (nla_parse_nested_arr(tb, info_data, policy) < 0) - return NULL; - - 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_LOCAL6]) - props->local6 = *nla_data_as(struct in6_addr, tb[IFLA_VXLAN_LOCAL6]); - if (tb[IFLA_VXLAN_GROUP6]) - props->group6 = *nla_data_as(struct in6_addr, tb[IFLA_VXLAN_GROUP6]); - - 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]) { - struct nm_ifla_vxlan_port_range *range; - - range = nla_data_as(struct nm_ifla_vxlan_port_range, 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; -} - -static NMPObject * -_parse_lnk_vrf(const char *kind, struct nlattr *info_data) -{ - static const struct nla_policy policy[] = { - [IFLA_VRF_TABLE] = {.type = NLA_U32}, - }; - NMPlatformLnkVrf *props; - struct nlattr * tb[G_N_ELEMENTS(policy)]; - NMPObject * obj; - - if (!info_data || !nm_streq0(kind, "vrf")) - return NULL; - - if (nla_parse_nested_arr(tb, info_data, policy) < 0) - return NULL; - - obj = nmp_object_new(NMP_OBJECT_TYPE_LNK_VRF, NULL); - - props = &obj->lnk_vrf; - - if (tb[IFLA_VRF_TABLE]) - props->table = nla_get_u32(tb[IFLA_VRF_TABLE]); - - return obj; -} - -/*****************************************************************************/ - -static gboolean -_wireguard_update_from_allowed_ips_nla(NMPWireGuardAllowedIP *allowed_ip, struct nlattr *nlattr) -{ - static const struct nla_policy policy[] = { - [WGALLOWEDIP_A_FAMILY] = {.type = NLA_U16}, - [WGALLOWEDIP_A_IPADDR] = {.minlen = sizeof(struct in_addr)}, - [WGALLOWEDIP_A_CIDR_MASK] = {.type = NLA_U8}, - }; - struct nlattr *tb[G_N_ELEMENTS(policy)]; - int family; - int addr_len; - - if (nla_parse_nested_arr(tb, nlattr, policy) < 0) - return FALSE; - - if (!tb[WGALLOWEDIP_A_FAMILY]) - return FALSE; - - family = nla_get_u16(tb[WGALLOWEDIP_A_FAMILY]); - if (family == AF_INET) - addr_len = sizeof(in_addr_t); - else if (family == AF_INET6) - addr_len = sizeof(struct in6_addr); - else - return FALSE; - - _check_addr_or_return_val(tb, WGALLOWEDIP_A_IPADDR, addr_len, FALSE); - - *allowed_ip = (NMPWireGuardAllowedIP){ - .family = family, - }; - - nm_assert((int) allowed_ip->family == family); - - if (tb[WGALLOWEDIP_A_IPADDR]) - nla_memcpy(&allowed_ip->addr, tb[WGALLOWEDIP_A_IPADDR], addr_len); - if (tb[WGALLOWEDIP_A_CIDR_MASK]) - allowed_ip->mask = nla_get_u8(tb[WGALLOWEDIP_A_CIDR_MASK]); - - return TRUE; -} - -typedef struct { - CList lst; - NMPWireGuardPeer data; -} WireGuardPeerConstruct; - -static gboolean -_wireguard_update_from_peers_nla(CList *peers, GArray **p_allowed_ips, struct nlattr *peer_attr) -{ - static const struct nla_policy policy[] = { - [WGPEER_A_PUBLIC_KEY] = {.minlen = NMP_WIREGUARD_PUBLIC_KEY_LEN}, - [WGPEER_A_PRESHARED_KEY] = {}, - [WGPEER_A_FLAGS] = {.type = NLA_U32}, - [WGPEER_A_ENDPOINT] = {}, - [WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL] = {.type = NLA_U16}, - [WGPEER_A_LAST_HANDSHAKE_TIME] = {}, - [WGPEER_A_RX_BYTES] = {.type = NLA_U64}, - [WGPEER_A_TX_BYTES] = {.type = NLA_U64}, - [WGPEER_A_ALLOWEDIPS] = {.type = NLA_NESTED}, - }; - struct nlattr * tb[G_N_ELEMENTS(policy)]; - WireGuardPeerConstruct *peer_c; - - if (nla_parse_nested_arr(tb, peer_attr, policy) < 0) - return FALSE; - - if (!tb[WGPEER_A_PUBLIC_KEY]) - return FALSE; - - /* a peer with the same public key as last peer is just a continuation for extra AllowedIPs */ - peer_c = c_list_last_entry(peers, WireGuardPeerConstruct, lst); - if (peer_c - && !memcmp(nla_data(tb[WGPEER_A_PUBLIC_KEY]), - peer_c->data.public_key, - NMP_WIREGUARD_PUBLIC_KEY_LEN)) { - G_STATIC_ASSERT_EXPR(NMP_WIREGUARD_PUBLIC_KEY_LEN == sizeof(peer_c->data.public_key)); - /* this message is a continuation of the previous peer. - * Only parse WGPEER_A_ALLOWEDIPS below. */ - } else { - /* otherwise, start a new peer */ - peer_c = g_slice_new0(WireGuardPeerConstruct); - c_list_link_tail(peers, &peer_c->lst); - - nla_memcpy(&peer_c->data.public_key, - tb[WGPEER_A_PUBLIC_KEY], - sizeof(peer_c->data.public_key)); - - if (tb[WGPEER_A_PRESHARED_KEY]) { - nla_memcpy(&peer_c->data.preshared_key, - tb[WGPEER_A_PRESHARED_KEY], - sizeof(peer_c->data.preshared_key)); - /* FIXME(netlink-bzero-secret) */ - nm_explicit_bzero(nla_data(tb[WGPEER_A_PRESHARED_KEY]), - nla_len(tb[WGPEER_A_PRESHARED_KEY])); - } - - nm_sock_addr_union_cpy_untrusted( - &peer_c->data.endpoint, - tb[WGPEER_A_ENDPOINT] ? nla_data(tb[WGPEER_A_ENDPOINT]) : NULL, - tb[WGPEER_A_ENDPOINT] ? nla_len(tb[WGPEER_A_ENDPOINT]) : 0); - - if (tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]) - peer_c->data.persistent_keepalive_interval = - nla_get_u16(tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]); - if (tb[WGPEER_A_LAST_HANDSHAKE_TIME]) { - if (nla_len(tb[WGPEER_A_LAST_HANDSHAKE_TIME]) - >= sizeof(peer_c->data.last_handshake_time)) - nla_memcpy(&peer_c->data.last_handshake_time, - tb[WGPEER_A_LAST_HANDSHAKE_TIME], - sizeof(peer_c->data.last_handshake_time)); - } - if (tb[WGPEER_A_RX_BYTES]) - peer_c->data.rx_bytes = nla_get_u64(tb[WGPEER_A_RX_BYTES]); - if (tb[WGPEER_A_TX_BYTES]) - peer_c->data.tx_bytes = nla_get_u64(tb[WGPEER_A_TX_BYTES]); - } - - if (tb[WGPEER_A_ALLOWEDIPS]) { - struct nlattr *attr; - int rem; - GArray * allowed_ips = *p_allowed_ips; - - nla_for_each_nested (attr, tb[WGPEER_A_ALLOWEDIPS], rem) { - if (!allowed_ips) { - allowed_ips = g_array_new(FALSE, FALSE, sizeof(NMPWireGuardAllowedIP)); - *p_allowed_ips = allowed_ips; - g_array_set_size(allowed_ips, 1); - } else - g_array_set_size(allowed_ips, allowed_ips->len + 1); - - if (!_wireguard_update_from_allowed_ips_nla( - &g_array_index(allowed_ips, NMPWireGuardAllowedIP, allowed_ips->len - 1), - attr)) { - /* we ignore the error of parsing one allowed-ip. */ - g_array_set_size(allowed_ips, allowed_ips->len - 1); - continue; - } - - if (!peer_c->data._construct_idx_end) - peer_c->data._construct_idx_start = allowed_ips->len - 1; - peer_c->data._construct_idx_end = allowed_ips->len; - } - } - - return TRUE; -} - -typedef struct { - const int ifindex; - NMPObject *obj; - CList peers; - GArray * allowed_ips; -} WireGuardParseData; - -static int -_wireguard_get_device_cb(struct nl_msg *msg, void *arg) -{ - static const struct nla_policy policy[] = { - [WGDEVICE_A_IFINDEX] = {.type = NLA_U32}, - [WGDEVICE_A_IFNAME] = {.type = NLA_NUL_STRING, .maxlen = IFNAMSIZ}, - [WGDEVICE_A_PRIVATE_KEY] = {}, - [WGDEVICE_A_PUBLIC_KEY] = {}, - [WGDEVICE_A_FLAGS] = {.type = NLA_U32}, - [WGDEVICE_A_LISTEN_PORT] = {.type = NLA_U16}, - [WGDEVICE_A_FWMARK] = {.type = NLA_U32}, - [WGDEVICE_A_PEERS] = {.type = NLA_NESTED}, - }; - struct nlattr * tb[G_N_ELEMENTS(policy)]; - WireGuardParseData *parse_data = arg; - - if (genlmsg_parse_arr(nlmsg_hdr(msg), 0, tb, policy) < 0) - return NL_SKIP; - - if (tb[WGDEVICE_A_IFINDEX]) { - int ifindex; - - ifindex = (int) nla_get_u32(tb[WGDEVICE_A_IFINDEX]); - if (ifindex <= 0 || parse_data->ifindex != ifindex) - return NL_SKIP; - } else { - if (!parse_data->obj) - return NL_SKIP; - } - - if (parse_data->obj) { - /* we already have an object instance. This means the netlink message - * is a continuation, only providing more WGDEVICE_A_PEERS data below. */ - } else { - NMPObject * obj; - NMPlatformLnkWireGuard *props; - - obj = nmp_object_new(NMP_OBJECT_TYPE_LNK_WIREGUARD, NULL); - props = &obj->lnk_wireguard; - - if (tb[WGDEVICE_A_PRIVATE_KEY]) { - nla_memcpy(props->private_key, tb[WGDEVICE_A_PRIVATE_KEY], sizeof(props->private_key)); - /* FIXME(netlink-bzero-secret): extend netlink library to wipe memory. For now, - * just hack it here (yes, this does not cover all places where the - * private key was copied). */ - nm_explicit_bzero(nla_data(tb[WGDEVICE_A_PRIVATE_KEY]), - nla_len(tb[WGDEVICE_A_PRIVATE_KEY])); - } - if (tb[WGDEVICE_A_PUBLIC_KEY]) - nla_memcpy(props->public_key, tb[WGDEVICE_A_PUBLIC_KEY], sizeof(props->public_key)); - if (tb[WGDEVICE_A_LISTEN_PORT]) - props->listen_port = nla_get_u16(tb[WGDEVICE_A_LISTEN_PORT]); - if (tb[WGDEVICE_A_FWMARK]) - props->fwmark = nla_get_u32(tb[WGDEVICE_A_FWMARK]); - - parse_data->obj = obj; - } - - if (tb[WGDEVICE_A_PEERS]) { - struct nlattr *attr; - int rem; - - nla_for_each_nested (attr, tb[WGDEVICE_A_PEERS], rem) { - if (!_wireguard_update_from_peers_nla(&parse_data->peers, - &parse_data->allowed_ips, - attr)) { - /* we ignore the error of parsing one peer. - * _wireguard_update_from_peers_nla() leaves the @peers array in the - * desired state. */ - } - } - } - - return NL_OK; -} - -static const NMPObject * -_wireguard_read_info(NMPlatform * platform /* used only as logging context */, - struct nl_sock *genl, - int wireguard_family_id, - int ifindex) -{ - nm_auto_nlmsg struct nl_msg *msg = NULL; - NMPObject * obj = NULL; - WireGuardPeerConstruct * peer_c; - WireGuardPeerConstruct * peer_c_safe; - gs_unref_array GArray *allowed_ips = NULL; - WireGuardParseData parse_data = { - .ifindex = ifindex, - }; - guint i; - - nm_assert(genl); - nm_assert(wireguard_family_id >= 0); - nm_assert(ifindex > 0); - - _LOGT("wireguard: fetching information for ifindex %d (genl-id %d)...", - ifindex, - wireguard_family_id); - - msg = nlmsg_alloc(); - - if (!genlmsg_put(msg, - NL_AUTO_PORT, - NL_AUTO_SEQ, - wireguard_family_id, - 0, - NLM_F_DUMP, - WG_CMD_GET_DEVICE, - 1)) - return NULL; - - NLA_PUT_U32(msg, WGDEVICE_A_IFINDEX, (guint32) ifindex); - - if (nl_send_auto(genl, msg) < 0) - return NULL; - - c_list_init(&parse_data.peers); - - /* we ignore errors, and return whatever we could successfully - * parse. */ - nl_recvmsgs(genl, - &((const struct nl_cb){ - .valid_cb = _wireguard_get_device_cb, - .valid_arg = (gpointer) &parse_data, - })); - - /* unpack: transfer ownership */ - obj = parse_data.obj; - allowed_ips = parse_data.allowed_ips; - - if (!obj) { - while ((peer_c = c_list_first_entry(&parse_data.peers, WireGuardPeerConstruct, lst))) { - c_list_unlink_stale(&peer_c->lst); - nm_explicit_bzero(&peer_c->data.preshared_key, sizeof(peer_c->data.preshared_key)); - g_slice_free(WireGuardPeerConstruct, peer_c); - } - return NULL; - } - - /* we receive peers/allowed-ips possibly in separate netlink messages. Hence, while - * parsing the dump, we don't know upfront how many peers/allowed-ips we will receive. - * - * We solve that, by collecting all peers with a CList. It's done this way, - * because a GArray would require growing the array, but we want to bzero() - * the preshared-key of each peer while reallocating. The CList apprach avoids - * that. - * - * For allowed-ips, we instead track one GArray, which are all appended - * there. The realloc/resize of the GArray is fine there. However, - * while we build the GArray, we don't yet have the final pointers. - * Hence, while constructing, we track the indexes with peer->_construct_idx_* - * fields. These indexes must be converted to actual pointers blow. - * - * This is all done during parsing. In the final NMPObjectLnkWireGuard we - * don't want the CList anymore and repackage the NMPObject tightly. The - * reason is, that NMPObject instances are immutable and long-living. Spend - * a bit effort below during construction to obtain a most suitable representation - * in this regard. */ - obj->_lnk_wireguard.peers_len = c_list_length(&parse_data.peers); - obj->_lnk_wireguard.peers = obj->_lnk_wireguard.peers_len > 0 - ? g_new(NMPWireGuardPeer, obj->_lnk_wireguard.peers_len) - : NULL; - - /* duplicate allowed_ips instead of using the pointer. The GArray possibly has more - * space allocated then we need, and we want to get rid of this excess buffer. - * Note that NMPObject instance is possibly put into the cache and long-living. */ - obj->_lnk_wireguard._allowed_ips_buf_len = allowed_ips ? allowed_ips->len : 0u; - obj->_lnk_wireguard._allowed_ips_buf = - obj->_lnk_wireguard._allowed_ips_buf_len > 0 - ? (NMPWireGuardAllowedIP *) nm_memdup(allowed_ips->data, - sizeof(NMPWireGuardAllowedIP) * allowed_ips->len) - : NULL; - - i = 0; - c_list_for_each_entry_safe (peer_c, peer_c_safe, &parse_data.peers, lst) { - NMPWireGuardPeer *peer = (NMPWireGuardPeer *) &obj->_lnk_wireguard.peers[i++]; - - *peer = peer_c->data; - - c_list_unlink_stale(&peer_c->lst); - nm_explicit_bzero(&peer_c->data.preshared_key, sizeof(peer_c->data.preshared_key)); - g_slice_free(WireGuardPeerConstruct, peer_c); - - if (peer->_construct_idx_end != 0) { - guint len; - - nm_assert(obj->_lnk_wireguard._allowed_ips_buf); - nm_assert(peer->_construct_idx_end > peer->_construct_idx_start); - nm_assert(peer->_construct_idx_start < obj->_lnk_wireguard._allowed_ips_buf_len); - nm_assert(peer->_construct_idx_end <= obj->_lnk_wireguard._allowed_ips_buf_len); - - len = peer->_construct_idx_end - peer->_construct_idx_start; - peer->allowed_ips = &obj->_lnk_wireguard._allowed_ips_buf[peer->_construct_idx_start]; - peer->allowed_ips_len = len; - } else { - nm_assert(!peer->_construct_idx_start); - nm_assert(!peer->_construct_idx_end); - peer->allowed_ips = NULL; - peer->allowed_ips_len = 0; - } - } - - return obj; - -nla_put_failure: - g_return_val_if_reached(NULL); -} - -static int -_wireguard_get_family_id(NMPlatform *platform, int ifindex_try) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - int wireguard_family_id = -1; - - if (ifindex_try > 0) { - const NMPlatformLink *plink; - - if (nm_platform_link_get_lnk_wireguard(platform, ifindex_try, &plink)) - wireguard_family_id = NMP_OBJECT_UP_CAST(plink)->_link.wireguard_family_id; - } - if (wireguard_family_id < 0) - wireguard_family_id = genl_ctrl_resolve(priv->genl, "wireguard"); - return wireguard_family_id; -} - -static const NMPObject * -_wireguard_refresh_link(NMPlatform *platform, int wireguard_family_id, int ifindex) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - nm_auto_nmpobj const NMPObject *obj_old = NULL; - nm_auto_nmpobj const NMPObject *obj_new = NULL; - nm_auto_nmpobj const NMPObject *lnk_new = NULL; - NMPCacheOpsType cache_op; - const NMPObject * plink = NULL; - nm_auto_nmpobj NMPObject *obj = NULL; - - nm_assert(wireguard_family_id >= 0); - nm_assert(ifindex > 0); - - nm_platform_process_events(platform); - - plink = nm_platform_link_get_obj(platform, ifindex, TRUE); - - if (!plink || plink->link.type != NM_LINK_TYPE_WIREGUARD) { - nm_platform_link_refresh(platform, ifindex); - plink = nm_platform_link_get_obj(platform, ifindex, TRUE); - if (!plink || plink->link.type != NM_LINK_TYPE_WIREGUARD) - return NULL; - if (NMP_OBJECT_GET_TYPE(plink->_link.netlink.lnk) == NMP_OBJECT_TYPE_LNK_WIREGUARD) - lnk_new = nmp_object_ref(plink->_link.netlink.lnk); - } else { - lnk_new = _wireguard_read_info(platform, priv->genl, wireguard_family_id, ifindex); - if (!lnk_new) { - if (NMP_OBJECT_GET_TYPE(plink->_link.netlink.lnk) == NMP_OBJECT_TYPE_LNK_WIREGUARD) - lnk_new = nmp_object_ref(plink->_link.netlink.lnk); - } else if (nmp_object_equal(plink->_link.netlink.lnk, lnk_new)) { - nmp_object_unref(lnk_new); - lnk_new = nmp_object_ref(plink->_link.netlink.lnk); - } - } - - if (plink->_link.wireguard_family_id == wireguard_family_id - && plink->_link.netlink.lnk == lnk_new) - return plink; - - /* we use nmp_cache_update_netlink() to re-inject the new object into the cache. - * For that, we need to clone it, and tweak it so that it's suitable. It's a bit - * of a hack, in particular that we need to clear driver and udev-device. */ - obj = nmp_object_clone(plink, FALSE); - obj->_link.wireguard_family_id = wireguard_family_id; - nmp_object_unref(obj->_link.netlink.lnk); - obj->_link.netlink.lnk = g_steal_pointer(&lnk_new); - obj->link.driver = NULL; - nm_clear_pointer(&obj->_link.udev.device, udev_device_unref); - - cache_op = - nmp_cache_update_netlink(nm_platform_get_cache(platform), obj, FALSE, &obj_old, &obj_new); - nm_assert(NM_IN_SET(cache_op, NMP_CACHE_OPS_UPDATED)); - if (cache_op != NMP_CACHE_OPS_UNCHANGED) { - cache_on_change(platform, cache_op, obj_old, obj_new); - nm_platform_cache_update_emit_signal(platform, cache_op, obj_old, obj_new); - } - - nm_assert(!obj_new - || (NMP_OBJECT_GET_TYPE(obj_new) == NMP_OBJECT_TYPE_LINK - && obj_new->link.type == NM_LINK_TYPE_WIREGUARD - && (!obj_new->_link.netlink.lnk - || NMP_OBJECT_GET_TYPE(obj_new->_link.netlink.lnk) - == NMP_OBJECT_TYPE_LNK_WIREGUARD))); - return obj_new; -} - -static int -_wireguard_create_change_nlmsgs(NMPlatform * platform, - int ifindex, - int wireguard_family_id, - const NMPlatformLnkWireGuard * lnk_wireguard, - const NMPWireGuardPeer * peers, - const NMPlatformWireGuardChangePeerFlags *peer_flags, - guint peers_len, - NMPlatformWireGuardChangeFlags change_flags, - GPtrArray ** out_msgs) -{ - gs_unref_ptrarray GPtrArray * msgs = NULL; - nm_auto_nlmsg struct nl_msg * msg = NULL; - const guint IDX_NIL = G_MAXUINT; - guint idx_peer_curr; - guint idx_allowed_ips_curr; - struct nlattr * nest_peers; - struct nlattr * nest_curr_peer; - struct nlattr * nest_allowed_ips; - struct nlattr * nest_curr_allowed_ip; - NMPlatformWireGuardChangePeerFlags p_flags = NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_DEFAULT; - -#define _nla_nest_end(msg, nest_start) \ - G_STMT_START \ - { \ - if (nla_nest_end((msg), (nest_start)) < 0) \ - g_return_val_if_reached(-NME_BUG); \ - } \ - G_STMT_END - - /* Adapted from LGPL-2.1+ code [1]. - * - * [1] https://git.zx2c4.com/WireGuard/tree/contrib/examples/embeddable-wg-library/wireguard.c?id=5e99a6d43fe2351adf36c786f5ea2086a8fe7ab8#n1073 */ - - idx_peer_curr = IDX_NIL; - idx_allowed_ips_curr = IDX_NIL; - - /* TODO: for the moment, we always reset all peers and allowed-ips (WGDEVICE_F_REPLACE_PEERS, WGPEER_F_REPLACE_ALLOWEDIPS). - * The platform API should be extended to also support partial updates. In particular, configuring the same configuration - * multiple times, should not clear and re-add all settings, but rather sync the existing settings with the desired configuration. */ - -again: - - msg = nlmsg_alloc(); - if (!genlmsg_put(msg, - NL_AUTO_PORT, - NL_AUTO_SEQ, - wireguard_family_id, - 0, - NLM_F_REQUEST, - WG_CMD_SET_DEVICE, - 1)) - g_return_val_if_reached(-NME_BUG); - - NLA_PUT_U32(msg, WGDEVICE_A_IFINDEX, (guint32) ifindex); - - if (idx_peer_curr == IDX_NIL) { - guint32 flags; - - if (NM_FLAGS_HAS(change_flags, NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_PRIVATE_KEY)) - NLA_PUT(msg, - WGDEVICE_A_PRIVATE_KEY, - sizeof(lnk_wireguard->private_key), - lnk_wireguard->private_key); - if (NM_FLAGS_HAS(change_flags, NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_LISTEN_PORT)) - NLA_PUT_U16(msg, WGDEVICE_A_LISTEN_PORT, lnk_wireguard->listen_port); - if (NM_FLAGS_HAS(change_flags, NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_FWMARK)) - NLA_PUT_U32(msg, WGDEVICE_A_FWMARK, lnk_wireguard->fwmark); - - flags = 0; - if (NM_FLAGS_HAS(change_flags, NM_PLATFORM_WIREGUARD_CHANGE_FLAG_REPLACE_PEERS)) - flags |= WGDEVICE_F_REPLACE_PEERS; - NLA_PUT_U32(msg, WGDEVICE_A_FLAGS, flags); - } - - if (peers_len == 0) - goto send; - - nest_curr_peer = NULL; - nest_allowed_ips = NULL; - nest_curr_allowed_ip = NULL; - - nest_peers = nla_nest_start(msg, WGDEVICE_A_PEERS); - if (!nest_peers) - g_return_val_if_reached(-NME_BUG); - - if (idx_peer_curr == IDX_NIL) - idx_peer_curr = 0; - for (; idx_peer_curr < peers_len; idx_peer_curr++) { - const NMPWireGuardPeer *p = &peers[idx_peer_curr]; - - if (peer_flags) { - p_flags = peer_flags[idx_peer_curr]; - if (!NM_FLAGS_ANY(p_flags, - NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REMOVE_ME - | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY - | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_KEEPALIVE_INTERVAL - | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ENDPOINT - | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ALLOWEDIPS - | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REPLACE_ALLOWEDIPS)) { - /* no flags set. We take that as indication to skip configuring the peer - * entirely. */ - nm_assert(p_flags == NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_NONE); - continue; - } - } - - nest_curr_peer = nla_nest_start(msg, 0); - if (!nest_curr_peer) - goto toobig_peers; - - if (nla_put(msg, WGPEER_A_PUBLIC_KEY, NMP_WIREGUARD_PUBLIC_KEY_LEN, p->public_key) < 0) - goto toobig_peers; - - if (NM_FLAGS_HAS(p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REMOVE_ME)) { - /* all other p_flags are silently ignored. */ - if (nla_put_uint32(msg, WGPEER_A_FLAGS, WGPEER_F_REMOVE_ME) < 0) - goto toobig_peers; - } else { - if (idx_allowed_ips_curr == IDX_NIL) { - if (NM_FLAGS_HAS(p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY) - && nla_put(msg, - WGPEER_A_PRESHARED_KEY, - sizeof(p->preshared_key), - p->preshared_key) - < 0) - goto toobig_peers; - - if (NM_FLAGS_HAS(p_flags, - NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_KEEPALIVE_INTERVAL) - && nla_put_uint16(msg, - WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, - p->persistent_keepalive_interval) - < 0) - goto toobig_peers; - - if (NM_FLAGS_HAS(p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REPLACE_ALLOWEDIPS) - && nla_put_uint32(msg, WGPEER_A_FLAGS, WGPEER_F_REPLACE_ALLOWEDIPS) < 0) - goto toobig_peers; - - if (NM_FLAGS_HAS(p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ENDPOINT)) { - if (NM_IN_SET(p->endpoint.sa.sa_family, AF_INET, AF_INET6)) { - if (nla_put(msg, - WGPEER_A_ENDPOINT, - p->endpoint.sa.sa_family == AF_INET ? sizeof(p->endpoint.in) - : sizeof(p->endpoint.in6), - &p->endpoint) - < 0) - goto toobig_peers; - } else { - /* I think there is no way to clear an endpoint, though there should be. */ - nm_assert(p->endpoint.sa.sa_family == AF_UNSPEC); - } - } - } - - if (NM_FLAGS_HAS(p_flags, NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ALLOWEDIPS) - && p->allowed_ips_len > 0) { - if (idx_allowed_ips_curr == IDX_NIL) - idx_allowed_ips_curr = 0; - - nest_allowed_ips = nla_nest_start(msg, WGPEER_A_ALLOWEDIPS); - if (!nest_allowed_ips) - goto toobig_allowedips; - - for (; idx_allowed_ips_curr < p->allowed_ips_len; idx_allowed_ips_curr++) { - const NMPWireGuardAllowedIP *aip = &p->allowed_ips[idx_allowed_ips_curr]; - - nest_curr_allowed_ip = nla_nest_start(msg, 0); - if (!nest_curr_allowed_ip) - goto toobig_allowedips; - - g_return_val_if_fail(NM_IN_SET(aip->family, AF_INET, AF_INET6), -NME_BUG); - - if (nla_put_uint16(msg, WGALLOWEDIP_A_FAMILY, aip->family) < 0) - goto toobig_allowedips; - if (nla_put(msg, - WGALLOWEDIP_A_IPADDR, - nm_utils_addr_family_to_size(aip->family), - &aip->addr) - < 0) - goto toobig_allowedips; - if (nla_put_uint8(msg, WGALLOWEDIP_A_CIDR_MASK, aip->mask) < 0) - goto toobig_allowedips; - - _nla_nest_end(msg, nest_curr_allowed_ip); - nest_curr_allowed_ip = NULL; - } - idx_allowed_ips_curr = IDX_NIL; - - _nla_nest_end(msg, nest_allowed_ips); - nest_allowed_ips = NULL; - } - } - - _nla_nest_end(msg, nest_curr_peer); - nest_curr_peer = NULL; - } - - _nla_nest_end(msg, nest_peers); - goto send; - -toobig_allowedips: - if (nest_curr_allowed_ip) - nla_nest_cancel(msg, nest_curr_allowed_ip); - if (nest_allowed_ips) - _nla_nest_end(msg, nest_allowed_ips); - _nla_nest_end(msg, nest_curr_peer); - _nla_nest_end(msg, nest_peers); - goto send; - -toobig_peers: - if (nest_curr_peer) - nla_nest_cancel(msg, nest_curr_peer); - _nla_nest_end(msg, nest_peers); - goto send; - -send: - if (!msgs) - msgs = g_ptr_array_new_with_free_func((GDestroyNotify) nlmsg_free); - g_ptr_array_add(msgs, g_steal_pointer(&msg)); - - if (idx_peer_curr != IDX_NIL && idx_peer_curr < peers_len) - goto again; - - NM_SET_OUT(out_msgs, g_steal_pointer(&msgs)); - return 0; - -nla_put_failure: - g_return_val_if_reached(-NME_BUG); - -#undef _nla_nest_end -} - -static int -link_wireguard_change(NMPlatform * platform, - int ifindex, - const NMPlatformLnkWireGuard * lnk_wireguard, - const NMPWireGuardPeer * peers, - const NMPlatformWireGuardChangePeerFlags *peer_flags, - guint peers_len, - NMPlatformWireGuardChangeFlags change_flags) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - gs_unref_ptrarray GPtrArray *msgs = NULL; - int wireguard_family_id; - guint i; - int r; - - wireguard_family_id = _wireguard_get_family_id(platform, ifindex); - if (wireguard_family_id < 0) - return -NME_PL_NO_FIRMWARE; - - r = _wireguard_create_change_nlmsgs(platform, - ifindex, - wireguard_family_id, - lnk_wireguard, - peers, - peer_flags, - peers_len, - change_flags, - &msgs); - if (r < 0) { - _LOGW("wireguard: set-device, cannot construct netlink message: %s", nm_strerror(r)); - return r; - } - - for (i = 0; i < msgs->len; i++) { - r = nl_send_auto(priv->genl, msgs->pdata[i]); - if (r < 0) { - _LOGW("wireguard: set-device, send netlink message #%u failed: %s", i, nm_strerror(r)); - return r; - } - - do { - r = nl_recvmsgs(priv->genl, NULL); - } while (r == -EAGAIN); - if (r < 0) { - _LOGW("wireguard: set-device, message #%u was rejected: %s", i, nm_strerror(r)); - return r; - } - - _LOGT("wireguard: set-device, message #%u sent and confirmed", i); - } - - _wireguard_refresh_link(platform, wireguard_family_id, ifindex); - - return 0; -} - -/*****************************************************************************/ - -static void -_nmp_link_address_set(NMPLinkAddress *dst, const struct nlattr *nla) -{ - *dst = (NMPLinkAddress){ - .len = 0, - }; - if (nla) { - int l = nla_len(nla); - - if (l > 0 && l <= NM_UTILS_HWADDR_LEN_MAX) { - G_STATIC_ASSERT_EXPR(sizeof(dst->data) == NM_UTILS_HWADDR_LEN_MAX); - memcpy(dst->data, nla_data(nla), l); - dst->len = l; - } - } -} - -/* 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 const struct nla_policy policy[] = { - [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 = nm_offsetofend(struct rtnl_link_stats, tx_compressed)}, - [IFLA_STATS64] = {.minlen = nm_offsetofend(struct rtnl_link_stats64, tx_compressed)}, - [IFLA_MAP] = {.minlen = nm_offsetofend(struct rtnl_link_ifmap, port)}, - [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}, - [IFLA_LINK_NETNSID] = {}, - }; - const struct ifinfomsg *ifi; - struct nlattr * tb[G_N_ELEMENTS(policy)]; - struct nlattr * nl_info_data = NULL; - const char * nl_info_kind = NULL; - nm_auto_nmpobj NMPObject *obj = NULL; - gboolean completed_from_cache_val = FALSE; - gboolean * completed_from_cache = cache ? &completed_from_cache_val : NULL; - const NMPObject * link_cached = NULL; - const NMPObject * lnk_data = NULL; - gboolean address_complete_from_cache = TRUE; - gboolean broadcast_complete_from_cache = TRUE; - gboolean lnk_data_complete_from_cache = TRUE; - gboolean need_ext_data = FALSE; - gboolean af_inet6_token_valid = FALSE; - gboolean af_inet6_addr_gen_mode_valid = FALSE; - - if (!nlmsg_valid_hdr(nlh, sizeof(*ifi))) - return NULL; - - ifi = nlmsg_data(nlh); - - if (ifi->ifi_family != AF_UNSPEC) - return NULL; - if (ifi->ifi_index <= 0) - return NULL; - - obj = nmp_object_new_link(ifi->ifi_index); - - if (id_only) - return g_steal_pointer(&obj); - - if (nlmsg_parse_arr(nlh, sizeof(*ifi), tb, policy) < 0) - return NULL; - - if (!tb[IFLA_IFNAME]) - return NULL; - nla_strlcpy(obj->link.name, tb[IFLA_IFNAME], IFNAMSIZ); - if (!obj->link.name[0]) - return NULL; - - if (!tb[IFLA_MTU]) { - /* Kernel has two places that send RTM_GETLINK messages: - * net/core/rtnetlink.c and net/wireless/ext-core.c. - * Unfortunately ext-core.c sets only IFLA_WIRELESS and - * IFLA_IFNAME. This confuses code in this function, because - * it cannot get complete set of data for the interface and - * later incomplete object this function creates is used to - * overwrite existing data in NM's cache. - * Since ext-core.c doesn't set IFLA_MTU we can use it as a - * signal to ignore incoming message. - * To some extent this is a hack and correct approach is to - * merge objects per-field. - */ - return NULL; - } - obj->link.mtu = nla_get_u32(tb[IFLA_MTU]); - - if (tb[IFLA_LINKINFO]) { - static const struct nla_policy policy_link_info[] = { - [IFLA_INFO_KIND] = {.type = NLA_STRING}, - [IFLA_INFO_DATA] = {.type = NLA_NESTED}, - [IFLA_INFO_XSTATS] = {.type = NLA_NESTED}, - }; - struct nlattr *li[G_N_ELEMENTS(policy_link_info)]; - - if (nla_parse_nested_arr(li, tb[IFLA_LINKINFO], policy_link_info) < 0) - return NULL; - - if (li[IFLA_INFO_KIND]) - nl_info_kind = nla_get_string(li[IFLA_INFO_KIND]); - - nl_info_data = li[IFLA_INFO_DATA]; - } - - if (tb[IFLA_STATS64]) { - const char *stats = nla_data(tb[IFLA_STATS64]); - - obj->link.rx_packets = - unaligned_read_ne64(&stats[G_STRUCT_OFFSET(struct rtnl_link_stats64, rx_packets)]); - obj->link.rx_bytes = - unaligned_read_ne64(&stats[G_STRUCT_OFFSET(struct rtnl_link_stats64, rx_bytes)]); - obj->link.tx_packets = - unaligned_read_ne64(&stats[G_STRUCT_OFFSET(struct rtnl_link_stats64, tx_packets)]); - obj->link.tx_bytes = - unaligned_read_ne64(&stats[G_STRUCT_OFFSET(struct rtnl_link_stats64, tx_bytes)]); - } - - obj->link.n_ifi_flags = ifi->ifi_flags; - obj->link.connected = NM_FLAGS_HAS(obj->link.n_ifi_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.n_ifi_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; - } - - if (tb[IFLA_ADDRESS]) { - _nmp_link_address_set(&obj->link.l_address, tb[IFLA_ADDRESS]); - address_complete_from_cache = FALSE; - } - - if (tb[IFLA_BROADCAST]) { - _nmp_link_address_set(&obj->link.l_broadcast, tb[IFLA_BROADCAST]); - broadcast_complete_from_cache = FALSE; - } - - 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, - &af_inet6_token_valid, - &obj->link.inet6_addr_gen_mode_inv, - &af_inet6_addr_gen_mode_valid); - break; - } - } - } - - switch (obj->link.type) { - case NM_LINK_TYPE_BRIDGE: - lnk_data = _parse_lnk_bridge(nl_info_kind, nl_info_data); - break; - case NM_LINK_TYPE_GRE: - case NM_LINK_TYPE_GRETAP: - 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_IP6GRE: - case NM_LINK_TYPE_IP6GRETAP: - lnk_data = _parse_lnk_ip6gre(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_MACSEC: - lnk_data = _parse_lnk_macsec(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_TUN: - lnk_data = _parse_lnk_tun(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_VRF: - lnk_data = _parse_lnk_vrf(nl_info_kind, nl_info_data); - break; - case NM_LINK_TYPE_VXLAN: - lnk_data = _parse_lnk_vxlan(nl_info_kind, nl_info_data); - break; - case NM_LINK_TYPE_WIFI: - case NM_LINK_TYPE_OLPC_MESH: - case NM_LINK_TYPE_WPAN: - need_ext_data = TRUE; - lnk_data_complete_from_cache = FALSE; - break; - case NM_LINK_TYPE_WIREGUARD: - lnk_data_complete_from_cache = TRUE; - break; - default: - lnk_data_complete_from_cache = FALSE; - break; - } - - if (completed_from_cache - && (lnk_data_complete_from_cache || need_ext_data || address_complete_from_cache - || broadcast_complete_from_cache || !af_inet6_token_valid - || !af_inet6_addr_gen_mode_valid || !tb[IFLA_STATS64])) { - _lookup_cached_link(cache, obj->link.ifindex, completed_from_cache, &link_cached); - if (link_cached && link_cached->_link.netlink.is_in_netlink) { - if (lnk_data_complete_from_cache && link_cached->link.type == obj->link.type - && link_cached->_link.netlink.lnk - && (!lnk_data || nmp_object_equal(lnk_data, link_cached->_link.netlink.lnk))) { - /* 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. */ - nmp_object_unref(lnk_data); - lnk_data = nmp_object_ref(link_cached->_link.netlink.lnk); - } - - if (need_ext_data && link_cached->link.type == obj->link.type - && link_cached->_link.ext_data) { - /* Prefer reuse of existing ext_data object */ - obj->_link.ext_data = g_object_ref(link_cached->_link.ext_data); - } - - if (address_complete_from_cache) - obj->link.l_address = link_cached->link.l_address; - if (broadcast_complete_from_cache) - obj->link.l_broadcast = link_cached->link.l_broadcast; - if (!af_inet6_token_valid) - obj->link.inet6_token = link_cached->link.inet6_token; - if (!af_inet6_addr_gen_mode_valid) - obj->link.inet6_addr_gen_mode_inv = link_cached->link.inet6_addr_gen_mode_inv; - if (!tb[IFLA_STATS64]) { - obj->link.rx_packets = link_cached->link.rx_packets; - obj->link.rx_bytes = link_cached->link.rx_bytes; - obj->link.tx_packets = link_cached->link.tx_packets; - obj->link.tx_bytes = link_cached->link.tx_bytes; - } - } - } - - obj->_link.netlink.lnk = lnk_data; - - if (need_ext_data && obj->_link.ext_data == NULL) { - switch (obj->link.type) { - case NM_LINK_TYPE_WIFI: - case NM_LINK_TYPE_OLPC_MESH: - obj->_link.ext_data = - (GObject *) nm_wifi_utils_new(ifi->ifi_index, - _genl_sock(NM_LINUX_PLATFORM(platform)), - TRUE); - break; - case NM_LINK_TYPE_WPAN: - obj->_link.ext_data = - (GObject *) nm_wpan_utils_new(ifi->ifi_index, - _genl_sock(NM_LINUX_PLATFORM(platform)), - TRUE); - break; - default: - g_assert_not_reached(); - } - } - - if (obj->link.type == NM_LINK_TYPE_WIREGUARD) { - const NMPObject *lnk_data_new = NULL; - struct nl_sock * genl = NM_LINUX_PLATFORM_GET_PRIVATE(platform)->genl; - - /* The WireGuard kernel module does not yet send link update - * notifications, so we don't actually update the cache. For - * now, always refetch link data here. */ - - _lookup_cached_link(cache, obj->link.ifindex, completed_from_cache, &link_cached); - if (link_cached && link_cached->_link.netlink.is_in_netlink - && link_cached->link.type == NM_LINK_TYPE_WIREGUARD) - obj->_link.wireguard_family_id = link_cached->_link.wireguard_family_id; - else - obj->_link.wireguard_family_id = -1; - - if (obj->_link.wireguard_family_id < 0) - obj->_link.wireguard_family_id = genl_ctrl_resolve(genl, "wireguard"); - - if (obj->_link.wireguard_family_id >= 0) { - lnk_data_new = _wireguard_read_info(platform, - genl, - obj->_link.wireguard_family_id, - obj->link.ifindex); - } - - if (lnk_data_new && obj->_link.netlink.lnk - && nmp_object_equal(obj->_link.netlink.lnk, lnk_data_new)) - nmp_object_unref(lnk_data_new); - else { - nmp_object_unref(obj->_link.netlink.lnk); - obj->_link.netlink.lnk = lnk_data_new; - } - } - - obj->_link.netlink.is_in_netlink = TRUE; - return g_steal_pointer(&obj); -} - -/* Copied and heavily modified from libnl3's addr_msg_parser(). */ -static NMPObject * -_new_from_nl_addr(struct nlmsghdr *nlh, gboolean id_only) -{ - static const struct nla_policy policy[] = { - [IFA_LABEL] = {.type = NLA_STRING, .maxlen = IFNAMSIZ}, - [IFA_CACHEINFO] = {.minlen = nm_offsetofend(struct ifa_cacheinfo, tstamp)}, - [IFA_FLAGS] = {}, - }; - struct nlattr * tb[G_N_ELEMENTS(policy)]; - const struct ifaddrmsg *ifa; - gboolean is_v4; - nm_auto_nmpobj NMPObject *obj = 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)) - return NULL; - - is_v4 = ifa->ifa_family == AF_INET; - - if (nlmsg_parse_arr(nlh, sizeof(*ifa), tb, policy) < 0) - return NULL; - - addr_len = is_v4 ? sizeof(in_addr_t) : sizeof(struct in6_addr); - - if (ifa->ifa_prefixlen > (is_v4 ? 32 : 128)) - return NULL; - - /*****************************************************************/ - - 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_return_null(tb, IFA_ADDRESS, addr_len); - _check_addr_or_return_null(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); - - _check_addr_or_return_null(tb, IFA_BROADCAST, addr_len); - obj->ip4_address.broadcast_address = - tb[IFA_BROADCAST] ? nla_get_u32(tb[IFA_BROADCAST]) : 0u; - obj->ip4_address.use_ip4_broadcast_address = TRUE; - } else { - /* For IPv6, IFA_ADDRESS is always present. - * - * If IFA_LOCAL is missing, IFA_ADDRESS is @address and @peer_address - * is :: (all-zero). - * - * If unexpectedly 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); - } - } - - obj->ip_address.addr_source = NM_IP_CONFIG_SOURCE_KERNEL; - - obj->ip_address.n_ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : ifa->ifa_flags; - - if (is_v4) { - if (tb[IFA_LABEL]) { - char label[IFNAMSIZ]; - - nla_strlcpy(label, tb[IFA_LABEL], IFNAMSIZ); - - /* 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)); - } - } - - lifetime = NM_PLATFORM_LIFETIME_PERMANENT; - preferred = NM_PLATFORM_LIFETIME_PERMANENT; - timestamp = 0; - /* IPv6 only */ - if (tb[IFA_CACHEINFO]) { - const struct ifa_cacheinfo *ca; - - ca = nla_data_as(struct ifa_cacheinfo, tb[IFA_CACHEINFO]); - 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); - - return g_steal_pointer(&obj); -} - -/* 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) -{ - static const struct nla_policy policy[] = { - [RTA_TABLE] = {.type = NLA_U32}, - [RTA_IIF] = {.type = NLA_U32}, - [RTA_OIF] = {.type = NLA_U32}, - [RTA_PRIORITY] = {.type = NLA_U32}, - [RTA_PREF] = {.type = NLA_U8}, - [RTA_FLOW] = {.type = NLA_U32}, - [RTA_CACHEINFO] = {.minlen = nm_offsetofend(struct rta_cacheinfo, rta_tsage)}, - [RTA_METRICS] = {.type = NLA_NESTED}, - [RTA_MULTIPATH] = {.type = NLA_NESTED}, - }; - const struct rtmsg *rtm; - struct nlattr * tb[G_N_ELEMENTS(policy)]; - gboolean is_v4; - nm_auto_nmpobj NMPObject *obj = NULL; - int addr_len; - struct { - gboolean is_present; - int ifindex; - NMIPAddr gateway; - } nh = { - .is_present = FALSE, - }; - guint32 mss; - guint32 window = 0; - guint32 cwnd = 0; - guint32 initcwnd = 0; - guint32 initrwnd = 0; - guint32 mtu = 0; - guint32 lock = 0; - - if (!nlmsg_valid_hdr(nlh, sizeof(*rtm))) - return NULL; - - rtm = nlmsg_data(nlh); - - /***************************************************************** - * only handle ~supported~ routes. - *****************************************************************/ - - if (!NM_IN_SET(rtm->rtm_family, AF_INET, AF_INET6)) - return NULL; - - if (!NM_IN_SET(rtm->rtm_type, RTN_UNICAST, RTN_LOCAL)) - return NULL; - - if (nlmsg_parse_arr(nlh, sizeof(struct rtmsg), tb, policy) < 0) - return NULL; - - /*****************************************************************/ - - is_v4 = rtm->rtm_family == AF_INET; - addr_len = is_v4 ? sizeof(in_addr_t) : sizeof(struct in6_addr); - - if (rtm->rtm_dst_len > (is_v4 ? 32 : 128)) - return NULL; - - /***************************************************************** - * parse nexthops. Only handle routes with one nh. - *****************************************************************/ - - if (tb[RTA_MULTIPATH]) { - size_t tlen = nla_len(tb[RTA_MULTIPATH]); - struct rtnexthop *rtnh; - - if (tlen < sizeof(*rtnh)) - goto rta_multipath_done; - - rtnh = nla_data_as(struct rtnexthop, tb[RTA_MULTIPATH]); - - if (tlen < rtnh->rtnh_len) - goto rta_multipath_done; - - while (TRUE) { - if (nh.is_present) { - /* we don't support multipath routes. */ - return NULL; - } - - nh.is_present = TRUE; - nh.ifindex = rtnh->rtnh_ifindex; - - if (rtnh->rtnh_len > sizeof(*rtnh)) { - struct nlattr *ntb[G_N_ELEMENTS(policy)]; - - if (nla_parse_arr(ntb, - (struct nlattr *) RTNH_DATA(rtnh), - rtnh->rtnh_len - sizeof(*rtnh), - policy) - < 0) - return NULL; - - if (_check_addr_or_return_null(ntb, RTA_GATEWAY, addr_len)) - memcpy(&nh.gateway, nla_data(ntb[RTA_GATEWAY]), addr_len); - } - - if (tlen < RTNH_ALIGN(rtnh->rtnh_len) + sizeof(*rtnh)) - goto rta_multipath_done; - - tlen -= RTNH_ALIGN(rtnh->rtnh_len); - rtnh = RTNH_NEXT(rtnh); - } -rta_multipath_done:; - } - - if (tb[RTA_OIF] || tb[RTA_GATEWAY] || tb[RTA_FLOW]) { - int ifindex = 0; - NMIPAddr gateway = {}; - - if (tb[RTA_OIF]) - ifindex = nla_get_u32(tb[RTA_OIF]); - if (_check_addr_or_return_null(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) - return NULL; - } - } else if (!nh.is_present) - return NULL; - - /*****************************************************************/ - - mss = 0; - if (tb[RTA_METRICS]) { - static const struct nla_policy rtax_policy[] = { - [RTAX_LOCK] = {.type = NLA_U32}, - [RTAX_ADVMSS] = {.type = NLA_U32}, - [RTAX_WINDOW] = {.type = NLA_U32}, - [RTAX_CWND] = {.type = NLA_U32}, - [RTAX_INITCWND] = {.type = NLA_U32}, - [RTAX_INITRWND] = {.type = NLA_U32}, - [RTAX_MTU] = {.type = NLA_U32}, - }; - struct nlattr *mtb[G_N_ELEMENTS(rtax_policy)]; - - if (nla_parse_nested_arr(mtb, tb[RTA_METRICS], rtax_policy) < 0) - return NULL; - - if (mtb[RTAX_LOCK]) - lock = nla_get_u32(mtb[RTAX_LOCK]); - if (mtb[RTAX_ADVMSS]) - mss = nla_get_u32(mtb[RTAX_ADVMSS]); - if (mtb[RTAX_WINDOW]) - window = nla_get_u32(mtb[RTAX_WINDOW]); - if (mtb[RTAX_CWND]) - cwnd = nla_get_u32(mtb[RTAX_CWND]); - if (mtb[RTAX_INITCWND]) - initcwnd = nla_get_u32(mtb[RTAX_INITCWND]); - if (mtb[RTAX_INITRWND]) - initrwnd = nla_get_u32(mtb[RTAX_INITRWND]); - if (mtb[RTAX_MTU]) - mtu = nla_get_u32(mtb[RTAX_MTU]); - } - - /*****************************************************************/ - - obj = nmp_object_new(is_v4 ? NMP_OBJECT_TYPE_IP4_ROUTE : NMP_OBJECT_TYPE_IP6_ROUTE, NULL); - - obj->ip_route.type_coerced = nm_platform_route_type_coerce(rtm->rtm_type); - obj->ip_route.table_coerced = nm_platform_route_table_coerce( - tb[RTA_TABLE] ? nla_get_u32(tb[RTA_TABLE]) : (guint32) rtm->rtm_table); - - obj->ip_route.ifindex = nh.ifindex; - - if (_check_addr_or_return_null(tb, RTA_DST, addr_len)) - memcpy(obj->ip_route.network_ptr, nla_data(tb[RTA_DST]), addr_len); - - obj->ip_route.plen = rtm->rtm_dst_len; - - 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; - - if (is_v4) - obj->ip4_route.scope_inv = nm_platform_route_scope_inv(rtm->rtm_scope); - - if (_check_addr_or_return_null(tb, RTA_PREFSRC, addr_len)) { - if (is_v4) - memcpy(&obj->ip4_route.pref_src, nla_data(tb[RTA_PREFSRC]), addr_len); - else - memcpy(&obj->ip6_route.pref_src, nla_data(tb[RTA_PREFSRC]), addr_len); - } - - if (is_v4) - obj->ip4_route.tos = rtm->rtm_tos; - else { - if (tb[RTA_SRC]) { - _check_addr_or_return_null(tb, RTA_SRC, addr_len); - memcpy(&obj->ip6_route.src, nla_data(tb[RTA_SRC]), addr_len); - } - obj->ip6_route.src_plen = rtm->rtm_src_len; - } - - obj->ip_route.mss = mss; - obj->ip_route.window = window; - obj->ip_route.cwnd = cwnd; - obj->ip_route.initcwnd = initcwnd; - obj->ip_route.initrwnd = initrwnd; - obj->ip_route.mtu = mtu; - obj->ip_route.lock_window = NM_FLAGS_HAS(lock, 1 << RTAX_WINDOW); - obj->ip_route.lock_cwnd = NM_FLAGS_HAS(lock, 1 << RTAX_CWND); - obj->ip_route.lock_initcwnd = NM_FLAGS_HAS(lock, 1 << RTAX_INITCWND); - obj->ip_route.lock_initrwnd = NM_FLAGS_HAS(lock, 1 << RTAX_INITRWND); - obj->ip_route.lock_mtu = NM_FLAGS_HAS(lock, 1 << RTAX_MTU); - - if (!is_v4) { - if (!_nm_platform_kernel_support_detected(NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF)) { - /* Detect support for RTA_PREF by inspecting the netlink message. - * RTA_PREF was added in kernel 4.1, dated 21 June, 2015. */ - _nm_platform_kernel_support_init(NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF, - tb[RTA_PREF] ? 1 : -1); - } - - if (tb[RTA_PREF]) - obj->ip6_route.rt_pref = nla_get_u8(tb[RTA_PREF]); - } - - obj->ip_route.r_rtm_flags = rtm->rtm_flags; - obj->ip_route.rt_source = nmp_utils_ip_config_source_from_rtprot(rtm->rtm_protocol); - - return g_steal_pointer(&obj); -} - -static NMPObject * -_new_from_nl_routing_rule(struct nlmsghdr *nlh, gboolean id_only) -{ - static const struct nla_policy policy[] = { - [FRA_UNSPEC] = {}, - [FRA_DST] = {/* struct in_addr, struct in6_addr */}, - [FRA_SRC] = {/* struct in_addr, struct in6_addr */}, - [FRA_IIFNAME] = - { - .type = NLA_STRING, - .maxlen = IFNAMSIZ, - }, - [FRA_GOTO] = - { - .type = NLA_U32, - }, - [FRA_UNUSED2] = {}, - [FRA_PRIORITY] = - { - .type = NLA_U32, - }, - [FRA_UNUSED3] = {}, - [FRA_UNUSED4] = {}, - [FRA_UNUSED5] = {}, - [FRA_FWMARK] = - { - .type = NLA_U32, - }, - [FRA_FLOW] = - { - .type = NLA_U32, - }, - [FRA_TUN_ID] = - { - .type = NLA_U64, - }, - [FRA_SUPPRESS_IFGROUP] = - { - .type = NLA_U32, - }, - [FRA_SUPPRESS_PREFIXLEN] = - { - .type = NLA_U32, - }, - [FRA_TABLE] = - { - .type = NLA_U32, - }, - [FRA_FWMASK] = - { - .type = NLA_U32, - }, - [FRA_OIFNAME] = - { - .type = NLA_STRING, - .maxlen = IFNAMSIZ, - }, - [FRA_PAD] = - { - .type = NLA_U32, - }, - [FRA_L3MDEV] = - { - .type = NLA_U8, - }, - [FRA_UID_RANGE] = - { - .minlen = sizeof(NMFibRuleUidRange), - .maxlen = sizeof(NMFibRuleUidRange), - }, - [FRA_PROTOCOL] = - { - .type = NLA_U8, - }, - [FRA_IP_PROTO] = - { - .type = NLA_U8, - }, - [FRA_SPORT_RANGE] = - { - .minlen = sizeof(NMFibRulePortRange), - .maxlen = sizeof(NMFibRulePortRange), - }, - [FRA_DPORT_RANGE] = - { - .minlen = sizeof(NMFibRulePortRange), - .maxlen = sizeof(NMFibRulePortRange), - }, - }; - struct nlattr * tb[G_N_ELEMENTS(policy)]; - const struct fib_rule_hdr *frh; - NMPlatformRoutingRule * props; - nm_auto_nmpobj NMPObject *obj = NULL; - int addr_family; - guint8 addr_size; - - if (nlmsg_parse_arr(nlh, sizeof(*frh), tb, policy) < 0) - return NULL; - - frh = nlmsg_data(nlh); - - addr_family = frh->family; - - if (!NM_IN_SET(addr_family, AF_INET, AF_INET6)) { - /* we don't care about other address families. */ - return NULL; - } - - addr_size = nm_utils_addr_family_to_size(addr_family); - - obj = nmp_object_new(NMP_OBJECT_TYPE_ROUTING_RULE, NULL); - props = &obj->routing_rule; - - props->addr_family = addr_family; - props->action = frh->action; - props->flags = frh->flags; - props->tos = frh->tos; - - props->table = tb[FRA_TABLE] ? nla_get_u32(tb[FRA_TABLE]) : frh->table; - - if (tb[FRA_SUPPRESS_PREFIXLEN]) - props->suppress_prefixlen_inverse = ~nla_get_u32(tb[FRA_SUPPRESS_PREFIXLEN]); - - if (tb[FRA_SUPPRESS_IFGROUP]) - props->suppress_ifgroup_inverse = ~nla_get_u32(tb[FRA_SUPPRESS_IFGROUP]); - - if (tb[FRA_IIFNAME]) - nla_strlcpy(props->iifname, tb[FRA_IIFNAME], sizeof(props->iifname)); - - if (tb[FRA_OIFNAME]) - nla_strlcpy(props->oifname, tb[FRA_OIFNAME], sizeof(props->oifname)); - - if (tb[FRA_PRIORITY]) - props->priority = nla_get_u32(tb[FRA_PRIORITY]); - - if (tb[FRA_FWMARK]) - props->fwmark = nla_get_u32(tb[FRA_FWMARK]); - - if (tb[FRA_FWMASK]) - props->fwmask = nla_get_u32(tb[FRA_FWMASK]); - - if (tb[FRA_GOTO]) - props->goto_target = nla_get_u32(tb[FRA_GOTO]); - - props->src_len = frh->src_len; - if (props->src_len > addr_size * 8) - return NULL; - if (!tb[FRA_SRC]) { - if (props->src_len > 0) - return NULL; - } else if (!nm_ip_addr_set_from_untrusted(addr_family, - &props->src, - nla_data(tb[FRA_SRC]), - nla_len(tb[FRA_SRC]), - NULL)) - return NULL; - - props->dst_len = frh->dst_len; - if (props->dst_len > addr_size * 8) - return NULL; - if (!tb[FRA_DST]) { - if (props->dst_len > 0) - return NULL; - } else if (!nm_ip_addr_set_from_untrusted(addr_family, - &props->dst, - nla_data(tb[FRA_DST]), - nla_len(tb[FRA_DST]), - NULL)) - return NULL; - - if (tb[FRA_FLOW]) - props->flow = nla_get_u32(tb[FRA_FLOW]); - - if (tb[FRA_TUN_ID]) - props->tun_id = nla_get_be64(tb[FRA_TUN_ID]); - - if (tb[FRA_L3MDEV]) { - if (!_nm_platform_kernel_support_detected(NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_L3MDEV)) { - /* support for FRA_L3MDEV was added in 96c63fa7393d0a346acfe5a91e0c7d4c7782641b, - * kernel 4.8, 3 October 2017. - * - * We can only detect support if the attribute is present. A missing attribute - * is not conclusive. */ - _nm_platform_kernel_support_init(NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_L3MDEV, 1); - } - - /* actually, kernel only allows this attribute to be missing or - * "1". Still, encode it as full uint8. - * - * Note that FRA_L3MDEV and FRA_TABLE are mutally exclusive. */ - props->l3mdev = nla_get_u8(tb[FRA_L3MDEV]); - } - - if (tb[FRA_PROTOCOL]) - props->protocol = nla_get_u8(tb[FRA_PROTOCOL]); - else - nm_assert(props->protocol == RTPROT_UNSPEC); - - if (!_nm_platform_kernel_support_detected(NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_PROTOCOL)) { - /* FRA_PROTOCOL was added in kernel 4.17, dated 3 June, 2018. - * See commit 1b71af6053af1bd2f849e9fda4f71c1e3f145dcf. */ - _nm_platform_kernel_support_init(NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_PROTOCOL, - tb[FRA_PROTOCOL] ? 1 : -1); - } - - if (tb[FRA_IP_PROTO]) - props->ip_proto = nla_get_u8(tb[FRA_IP_PROTO]); - - G_STATIC_ASSERT_EXPR(sizeof(NMFibRulePortRange) == 4); - G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(NMFibRulePortRange, start) == 0); - G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(NMFibRulePortRange, end) == 2); - - nla_memcpy_checked_size(&props->sport_range, tb[FRA_SPORT_RANGE], sizeof(props->sport_range)); - nla_memcpy_checked_size(&props->dport_range, tb[FRA_DPORT_RANGE], sizeof(props->dport_range)); - - if (!_nm_platform_kernel_support_detected(NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_IP_PROTO)) { - /* support for FRA_IP_PROTO, FRA_SPORT_RANGE, and FRA_DPORT_RANGE was added together - * by bfff4862653bb96001ab57c1edd6d03f48e5f035, kernel 4.17, 4 June 2018. - * - * Unfortunately, a missing attribute does not tell us anything about support. - * We can only tell for sure when we have support, but not when we don't have. */ - if (tb[FRA_IP_PROTO] || tb[FRA_SPORT_RANGE] || tb[FRA_DPORT_RANGE]) - _nm_platform_kernel_support_init(NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_IP_PROTO, 1); - } - - G_STATIC_ASSERT_EXPR(sizeof(NMFibRuleUidRange) == 8); - G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(NMFibRuleUidRange, start) == 0); - G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(NMFibRuleUidRange, end) == 4); - - if (tb[FRA_UID_RANGE]) { - if (!_nm_platform_kernel_support_detected(NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_UID_RANGE)) { - /* support for FRA_UID_RANGE was added in 622ec2c9d52405973c9f1ca5116eb1c393adfc7d, - * kernel 4.10, 19 February 2017. - * - * We can only detect support if the attribute is present. A missing attribute - * is not conclusive. */ - _nm_platform_kernel_support_init(NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_UID_RANGE, 1); - } - - nla_memcpy_checked_size(&props->uid_range, tb[FRA_UID_RANGE], sizeof(props->uid_range)); - props->uid_range_has = TRUE; - } - - return g_steal_pointer(&obj); -} - -static guint32 -psched_tick_to_time(NMPlatform *platform, guint32 tick) -{ - static gboolean initialized; - static double tick_in_usec = 1; - - if (!initialized) { - gs_free char *params = NULL; - double clock_factor = 1; - guint32 clock_res; - guint32 t2us; - guint32 us2t; - - initialized = TRUE; - params = nm_platform_sysctl_get(platform, NMP_SYSCTL_PATHID_ABSOLUTE("/proc/net/psched")); - if (!params || sscanf(params, "%08x%08x%08x", &t2us, &us2t, &clock_res) != 3) { - _LOGW("packet scheduler parameters not available"); - } else { - /* See tc_core_init() in iproute2 */ - if (clock_res == 1000000000) - t2us = us2t; - - clock_factor = (double) clock_res / PSCHED_TIME_UNITS_PER_SEC; - tick_in_usec = (double) t2us / us2t * clock_factor; - } - } - - return tick / tick_in_usec; -} - -static NMPObject * -_new_from_nl_qdisc(NMPlatform *platform, struct nlmsghdr *nlh, gboolean id_only) -{ - static const struct nla_policy policy[] = { - [TCA_KIND] = {.type = NLA_STRING}, - [TCA_OPTIONS] = {.type = NLA_NESTED}, - }; - struct nlattr * tb[G_N_ELEMENTS(policy)]; - const struct tcmsg *tcm; - nm_auto_nmpobj NMPObject *obj = NULL; - - if (nlmsg_parse_arr(nlh, sizeof(*tcm), tb, policy) < 0) - return NULL; - - if (!tb[TCA_KIND]) - return NULL; - - tcm = nlmsg_data(nlh); - - obj = nmp_object_new(NMP_OBJECT_TYPE_QDISC, NULL); - - obj->qdisc.kind = g_intern_string(nla_get_string(tb[TCA_KIND])); - obj->qdisc.ifindex = tcm->tcm_ifindex; - obj->qdisc.addr_family = tcm->tcm_family; - obj->qdisc.handle = tcm->tcm_handle; - obj->qdisc.parent = tcm->tcm_parent; - obj->qdisc.info = tcm->tcm_info; - - if (nm_streq0(obj->qdisc.kind, "fq_codel")) { - obj->qdisc.fq_codel.memory_limit = NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET; - obj->qdisc.fq_codel.ce_threshold = NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED; - } - - if (tb[TCA_OPTIONS]) { - struct nlattr *options_attr; - int remaining; - - if (nm_streq0(obj->qdisc.kind, "sfq")) { - struct tc_sfq_qopt_v1 opt; - - if (tb[TCA_OPTIONS]->nla_len >= nla_attr_size(sizeof(opt))) { - memcpy(&opt, nla_data(tb[TCA_OPTIONS]), sizeof(opt)); - obj->qdisc.sfq.quantum = opt.v0.quantum; - obj->qdisc.sfq.perturb_period = opt.v0.perturb_period; - obj->qdisc.sfq.limit = opt.v0.limit; - obj->qdisc.sfq.divisor = opt.v0.divisor; - obj->qdisc.sfq.flows = opt.v0.flows; - obj->qdisc.sfq.depth = opt.depth; - } - } else if (nm_streq0(obj->qdisc.kind, "tbf")) { - static const struct nla_policy tbf_policy[] = { - [TCA_TBF_PARMS] = {.minlen = sizeof(struct tc_tbf_qopt)}, - [TCA_TBF_RATE64] = {.type = NLA_U64}, - }; - struct nlattr * tbf_tb[G_N_ELEMENTS(tbf_policy)]; - struct tc_tbf_qopt opt; - - if (nla_parse_nested_arr(tbf_tb, tb[TCA_OPTIONS], tbf_policy) < 0) - return NULL; - if (!tbf_tb[TCA_TBF_PARMS]) - return NULL; - - nla_memcpy_checked_size(&opt, tbf_tb[TCA_TBF_PARMS], sizeof(opt)); - obj->qdisc.tbf.rate = opt.rate.rate; - if (tbf_tb[TCA_TBF_RATE64]) - obj->qdisc.tbf.rate = nla_get_u64(tbf_tb[TCA_TBF_RATE64]); - obj->qdisc.tbf.burst = - ((double) obj->qdisc.tbf.rate * psched_tick_to_time(platform, opt.buffer)) - / PSCHED_TIME_UNITS_PER_SEC; - obj->qdisc.tbf.limit = opt.limit; - } else { - nla_for_each_nested (options_attr, tb[TCA_OPTIONS], remaining) { - if (nla_len(options_attr) < sizeof(uint32_t)) - continue; - - if (nm_streq0(obj->qdisc.kind, "fq_codel")) { - switch (nla_type(options_attr)) { - case TCA_FQ_CODEL_LIMIT: - obj->qdisc.fq_codel.limit = nla_get_u32(options_attr); - break; - case TCA_FQ_CODEL_FLOWS: - obj->qdisc.fq_codel.flows = nla_get_u32(options_attr); - break; - case TCA_FQ_CODEL_TARGET: - obj->qdisc.fq_codel.target = nla_get_u32(options_attr); - break; - case TCA_FQ_CODEL_INTERVAL: - obj->qdisc.fq_codel.interval = nla_get_u32(options_attr); - break; - case TCA_FQ_CODEL_QUANTUM: - obj->qdisc.fq_codel.quantum = nla_get_u32(options_attr); - break; - case TCA_FQ_CODEL_CE_THRESHOLD: - obj->qdisc.fq_codel.ce_threshold = nla_get_u32(options_attr); - break; - case TCA_FQ_CODEL_MEMORY_LIMIT: - obj->qdisc.fq_codel.memory_limit = nla_get_u32(options_attr); - break; - case TCA_FQ_CODEL_ECN: - obj->qdisc.fq_codel.ecn = !!nla_get_u32(options_attr); - break; - } - } - } - } - } - - return g_steal_pointer(&obj); -} - -static NMPObject * -_new_from_nl_tfilter(struct nlmsghdr *nlh, gboolean id_only) -{ - static const struct nla_policy policy[] = { - [TCA_KIND] = {.type = NLA_STRING}, - }; - struct nlattr * tb[G_N_ELEMENTS(policy)]; - NMPObject * obj = NULL; - const struct tcmsg *tcm; - - if (nlmsg_parse_arr(nlh, sizeof(*tcm), tb, policy) < 0) - return NULL; - - if (!tb[TCA_KIND]) - return NULL; - - tcm = nlmsg_data(nlh); - - obj = nmp_object_new(NMP_OBJECT_TYPE_TFILTER, NULL); - - obj->tfilter.kind = g_intern_string(nla_get_string(tb[TCA_KIND])); - obj->tfilter.ifindex = tcm->tcm_ifindex; - obj->tfilter.addr_family = tcm->tcm_family; - obj->tfilter.handle = tcm->tcm_handle; - obj->tfilter.parent = tcm->tcm_parent; - obj->tfilter.info = tcm->tcm_info; - - return obj; -} - -/** - * 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) -{ - struct nlmsghdr *msghdr; - - if (nlmsg_get_proto(msg) != NETLINK_ROUTE) - return NULL; - - msghdr = nlmsg_hdr(msg); - - 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); - case RTM_NEWRULE: - case RTM_DELRULE: - case RTM_GETRULE: - return _new_from_nl_routing_rule(msghdr, id_only); - case RTM_NEWQDISC: - case RTM_DELQDISC: - case RTM_GETQDISC: - return _new_from_nl_qdisc(platform, msghdr, id_only); - case RTM_NEWTFILTER: - case RTM_DELTFILTER: - case RTM_GETTFILTER: - return _new_from_nl_tfilter(msghdr, id_only); - default: - return NULL; - } -} - -/*****************************************************************************/ - -static gboolean -_nl_msg_new_link_set_afspec(struct nl_msg *msg, int addr_gen_mode, NMUtilsIPv6IfaceId *iid) -{ - 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; - - if (addr_gen_mode >= 0 || iid) { - if (!(af_attr = nla_nest_start(msg, AF_INET6))) - goto nla_put_failure; - - if (addr_gen_mode >= 0) - NLA_PUT_U8(msg, IFLA_INET6_ADDR_GEN_MODE, addr_gen_mode); - - if (iid) { - struct in6_addr i6_token = {.s6_addr = { - 0, - }}; - - nm_utils_ipv6_addr_set_interface_identifier(&i6_token, *iid); - NLA_PUT(msg, IFLA_INET6_TOKEN, sizeof(struct in6_addr), &i6_token); - } - - nla_nest_end(msg, af_attr); - } - - nla_nest_end(msg, af_spec); - - return TRUE; -nla_put_failure: - g_return_val_if_reached(FALSE); -} - -static gboolean -_nl_msg_new_link_set_linkinfo(struct nl_msg *msg, NMLinkType link_type, gconstpointer extra_data) -{ - struct nlattr *info; - struct nlattr *data = NULL; - const char * kind; - - nm_assert(msg); - - kind = nm_link_type_to_rtnl_type_string(link_type); - if (!kind) - goto nla_put_failure; - - if (!(info = nla_nest_start(msg, IFLA_LINKINFO))) - goto nla_put_failure; - - NLA_PUT_STRING(msg, IFLA_INFO_KIND, kind); - - switch (link_type) { - case NM_LINK_TYPE_BRIDGE: - { - const NMPlatformLnkBridge *props = extra_data; - - nm_assert(extra_data); - - if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) - goto nla_put_failure; - - NLA_PUT_U32(msg, IFLA_BR_FORWARD_DELAY, props->forward_delay); - NLA_PUT_U32(msg, IFLA_BR_HELLO_TIME, props->hello_time); - NLA_PUT_U32(msg, IFLA_BR_MAX_AGE, props->max_age); - NLA_PUT_U32(msg, IFLA_BR_AGEING_TIME, props->ageing_time); - NLA_PUT_U32(msg, IFLA_BR_STP_STATE, !!props->stp_state); - NLA_PUT_U16(msg, IFLA_BR_PRIORITY, props->priority); - NLA_PUT_U16(msg, IFLA_BR_VLAN_PROTOCOL, htons(props->vlan_protocol)); - if (props->vlan_stats_enabled) - NLA_PUT_U8(msg, IFLA_BR_VLAN_STATS_ENABLED, !!props->vlan_stats_enabled); - NLA_PUT_U16(msg, IFLA_BR_GROUP_FWD_MASK, props->group_fwd_mask); - NLA_PUT(msg, IFLA_BR_GROUP_ADDR, sizeof(props->group_addr), &props->group_addr); - NLA_PUT_U8(msg, IFLA_BR_MCAST_SNOOPING, !!props->mcast_snooping); - NLA_PUT_U8(msg, IFLA_BR_MCAST_ROUTER, props->mcast_router); - NLA_PUT_U8(msg, IFLA_BR_MCAST_QUERY_USE_IFADDR, !!props->mcast_query_use_ifaddr); - NLA_PUT_U8(msg, IFLA_BR_MCAST_QUERIER, !!props->mcast_querier); - NLA_PUT_U32(msg, IFLA_BR_MCAST_HASH_MAX, props->mcast_hash_max); - NLA_PUT_U32(msg, IFLA_BR_MCAST_LAST_MEMBER_CNT, props->mcast_last_member_count); - NLA_PUT_U32(msg, IFLA_BR_MCAST_STARTUP_QUERY_CNT, props->mcast_startup_query_count); - NLA_PUT_U64(msg, IFLA_BR_MCAST_LAST_MEMBER_INTVL, props->mcast_last_member_interval); - NLA_PUT_U64(msg, IFLA_BR_MCAST_MEMBERSHIP_INTVL, props->mcast_membership_interval); - NLA_PUT_U64(msg, IFLA_BR_MCAST_QUERIER_INTVL, props->mcast_querier_interval); - NLA_PUT_U64(msg, IFLA_BR_MCAST_QUERY_INTVL, props->mcast_query_interval); - NLA_PUT_U64(msg, IFLA_BR_MCAST_QUERY_RESPONSE_INTVL, props->mcast_query_response_interval); - NLA_PUT_U64(msg, IFLA_BR_MCAST_STARTUP_QUERY_INTVL, props->mcast_startup_query_interval); - break; - } - case NM_LINK_TYPE_VLAN: - { - const NMPlatformLnkVlan *props = extra_data; - - nm_assert(extra_data); - - if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) - goto nla_put_failure; - - NLA_PUT_U16(msg, IFLA_VLAN_ID, props->id); - - { - struct ifla_vlan_flags flags = { - .flags = props->flags & NM_VLAN_FLAGS_ALL, - .mask = NM_VLAN_FLAGS_ALL, - }; - - NLA_PUT(msg, IFLA_VLAN_FLAGS, sizeof(flags), &flags); - } - break; - } - case NM_LINK_TYPE_VRF: - { - const NMPlatformLnkVrf *props = extra_data; - - nm_assert(extra_data); - - if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) - goto nla_put_failure; - - NLA_PUT_U32(msg, IFLA_VRF_TABLE, props->table); - break; - } - case NM_LINK_TYPE_VXLAN: - { - const NMPlatformLnkVxlan *props = extra_data; - - nm_assert(extra_data); - - if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) - goto nla_put_failure; - - NLA_PUT_U32(msg, IFLA_VXLAN_ID, props->id); - - if (props->group) - NLA_PUT(msg, IFLA_VXLAN_GROUP, sizeof(props->group), &props->group); - else if (!IN6_IS_ADDR_UNSPECIFIED(&props->group6)) - NLA_PUT(msg, IFLA_VXLAN_GROUP6, sizeof(props->group6), &props->group6); - - if (props->local) - NLA_PUT(msg, IFLA_VXLAN_LOCAL, sizeof(props->local), &props->local); - else if (!IN6_IS_ADDR_UNSPECIFIED(&props->local6)) - NLA_PUT(msg, IFLA_VXLAN_LOCAL6, sizeof(props->local6), &props->local6); - - if (props->parent_ifindex >= 0) - NLA_PUT_U32(msg, IFLA_VXLAN_LINK, props->parent_ifindex); - - if (props->src_port_min || props->src_port_max) { - struct nm_ifla_vxlan_port_range port_range = { - .low = htons(props->src_port_min), - .high = htons(props->src_port_max), - }; - - NLA_PUT(msg, IFLA_VXLAN_PORT_RANGE, sizeof(port_range), &port_range); - } - - NLA_PUT_U16(msg, IFLA_VXLAN_PORT, htons(props->dst_port)); - NLA_PUT_U8(msg, IFLA_VXLAN_TOS, props->tos); - NLA_PUT_U8(msg, IFLA_VXLAN_TTL, props->ttl); - NLA_PUT_U32(msg, IFLA_VXLAN_AGEING, props->ageing); - NLA_PUT_U32(msg, IFLA_VXLAN_LIMIT, props->limit); - NLA_PUT_U8(msg, IFLA_VXLAN_LEARNING, !!props->learning); - NLA_PUT_U8(msg, IFLA_VXLAN_PROXY, !!props->proxy); - NLA_PUT_U8(msg, IFLA_VXLAN_RSC, !!props->rsc); - NLA_PUT_U8(msg, IFLA_VXLAN_L2MISS, !!props->l2miss); - NLA_PUT_U8(msg, IFLA_VXLAN_L3MISS, !!props->l3miss); - break; - } - case NM_LINK_TYPE_VETH: - { - const char * veth_peer = extra_data; - const struct ifinfomsg ifi = {}; - struct nlattr * info_peer; - - nm_assert(veth_peer); - - if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) - goto nla_put_failure; - if (!(info_peer = nla_nest_start(msg, 1 /*VETH_INFO_PEER*/))) - goto nla_put_failure; - if (nlmsg_append_struct(msg, &ifi) < 0) - goto nla_put_failure; - NLA_PUT_STRING(msg, IFLA_IFNAME, veth_peer); - nla_nest_end(msg, info_peer); - break; - } - case NM_LINK_TYPE_GRE: - case NM_LINK_TYPE_GRETAP: - { - const NMPlatformLnkGre *props = extra_data; - - nm_assert(props); - nm_assert(props->is_tap == (link_type == NM_LINK_TYPE_GRETAP)); - - if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) - goto nla_put_failure; - - if (props->parent_ifindex) - NLA_PUT_U32(msg, IFLA_GRE_LINK, props->parent_ifindex); - NLA_PUT_U32(msg, IFLA_GRE_LOCAL, props->local); - NLA_PUT_U32(msg, IFLA_GRE_REMOTE, props->remote); - NLA_PUT_U8(msg, IFLA_GRE_TTL, props->ttl); - NLA_PUT_U8(msg, IFLA_GRE_TOS, props->tos); - NLA_PUT_U8(msg, IFLA_GRE_PMTUDISC, !!props->path_mtu_discovery); - NLA_PUT_U32(msg, IFLA_GRE_IKEY, htonl(props->input_key)); - NLA_PUT_U32(msg, IFLA_GRE_OKEY, htonl(props->output_key)); - NLA_PUT_U16(msg, IFLA_GRE_IFLAGS, htons(props->input_flags)); - NLA_PUT_U16(msg, IFLA_GRE_OFLAGS, htons(props->output_flags)); - break; - } - case NM_LINK_TYPE_SIT: - { - const NMPlatformLnkSit *props = extra_data; - - nm_assert(props); - - if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) - goto nla_put_failure; - - if (props->parent_ifindex) - NLA_PUT_U32(msg, IFLA_IPTUN_LINK, props->parent_ifindex); - NLA_PUT_U32(msg, IFLA_IPTUN_LOCAL, props->local); - NLA_PUT_U32(msg, IFLA_IPTUN_REMOTE, props->remote); - NLA_PUT_U8(msg, IFLA_IPTUN_TTL, props->ttl); - NLA_PUT_U8(msg, IFLA_IPTUN_TOS, props->tos); - NLA_PUT_U8(msg, IFLA_IPTUN_PMTUDISC, !!props->path_mtu_discovery); - break; - } - case NM_LINK_TYPE_IP6TNL: - { - const NMPlatformLnkIp6Tnl *props = extra_data; - guint32 flowinfo; - - nm_assert(props); - nm_assert(!props->is_gre); - - if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) - goto nla_put_failure; - - if (props->parent_ifindex) - NLA_PUT_U32(msg, IFLA_IPTUN_LINK, props->parent_ifindex); - - if (!IN6_IS_ADDR_UNSPECIFIED(&props->local)) - NLA_PUT(msg, IFLA_IPTUN_LOCAL, sizeof(props->local), &props->local); - if (!IN6_IS_ADDR_UNSPECIFIED(&props->remote)) - NLA_PUT(msg, IFLA_IPTUN_REMOTE, sizeof(props->remote), &props->remote); - - NLA_PUT_U8(msg, IFLA_IPTUN_TTL, props->ttl); - NLA_PUT_U8(msg, IFLA_IPTUN_ENCAP_LIMIT, props->encap_limit); - - flowinfo = props->flow_label & IP6_FLOWINFO_FLOWLABEL_MASK; - flowinfo |= (props->tclass << IP6_FLOWINFO_TCLASS_SHIFT) & IP6_FLOWINFO_TCLASS_MASK; - NLA_PUT_U32(msg, IFLA_IPTUN_FLOWINFO, htonl(flowinfo)); - NLA_PUT_U8(msg, IFLA_IPTUN_PROTO, props->proto); - NLA_PUT_U32(msg, IFLA_IPTUN_FLAGS, props->flags); - break; - } - case NM_LINK_TYPE_IP6GRE: - case NM_LINK_TYPE_IP6GRETAP: - { - const NMPlatformLnkIp6Tnl *props = extra_data; - guint32 flowinfo; - - nm_assert(props); - nm_assert(props->is_gre); - - if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) - goto nla_put_failure; - - if (props->parent_ifindex) - NLA_PUT_U32(msg, IFLA_GRE_LINK, props->parent_ifindex); - - NLA_PUT_U32(msg, IFLA_GRE_IKEY, htonl(props->input_key)); - NLA_PUT_U32(msg, IFLA_GRE_OKEY, htonl(props->output_key)); - NLA_PUT_U16(msg, IFLA_GRE_IFLAGS, htons(props->input_flags)); - NLA_PUT_U16(msg, IFLA_GRE_OFLAGS, htons(props->output_flags)); - - if (!IN6_IS_ADDR_UNSPECIFIED(&props->local)) - NLA_PUT(msg, IFLA_GRE_LOCAL, sizeof(props->local), &props->local); - if (!IN6_IS_ADDR_UNSPECIFIED(&props->local)) - NLA_PUT(msg, IFLA_GRE_REMOTE, sizeof(props->remote), &props->remote); - - NLA_PUT_U8(msg, IFLA_GRE_TTL, props->ttl); - NLA_PUT_U8(msg, IFLA_GRE_ENCAP_LIMIT, props->encap_limit); - - flowinfo = props->flow_label & IP6_FLOWINFO_FLOWLABEL_MASK; - flowinfo |= (props->tclass << IP6_FLOWINFO_TCLASS_SHIFT) & IP6_FLOWINFO_TCLASS_MASK; - NLA_PUT_U32(msg, IFLA_GRE_FLOWINFO, htonl(flowinfo)); - NLA_PUT_U32(msg, IFLA_GRE_FLAGS, props->flags); - break; - } - case NM_LINK_TYPE_IPIP: - { - const NMPlatformLnkIpIp *props = extra_data; - - nm_assert(props); - - if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) - goto nla_put_failure; - - if (props->parent_ifindex) - NLA_PUT_U32(msg, IFLA_IPTUN_LINK, props->parent_ifindex); - NLA_PUT_U32(msg, IFLA_IPTUN_LOCAL, props->local); - NLA_PUT_U32(msg, IFLA_IPTUN_REMOTE, props->remote); - NLA_PUT_U8(msg, IFLA_IPTUN_TTL, props->ttl); - NLA_PUT_U8(msg, IFLA_IPTUN_TOS, props->tos); - NLA_PUT_U8(msg, IFLA_IPTUN_PMTUDISC, !!props->path_mtu_discovery); - break; - } - case NM_LINK_TYPE_MACSEC: - { - const NMPlatformLnkMacsec *props = extra_data; - - nm_assert(props); - - if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) - goto nla_put_failure; - - if (props->icv_length) - NLA_PUT_U8(msg, IFLA_MACSEC_ICV_LEN, 16); - if (props->cipher_suite) - NLA_PUT_U64(msg, IFLA_MACSEC_CIPHER_SUITE, props->cipher_suite); - if (props->replay_protect) - NLA_PUT_U32(msg, IFLA_MACSEC_WINDOW, props->window); - - NLA_PUT_U64(msg, IFLA_MACSEC_SCI, htobe64(props->sci)); - NLA_PUT_U8(msg, IFLA_MACSEC_ENCODING_SA, props->encoding_sa); - NLA_PUT_U8(msg, IFLA_MACSEC_ENCRYPT, props->encrypt); - NLA_PUT_U8(msg, IFLA_MACSEC_PROTECT, props->protect); - NLA_PUT_U8(msg, IFLA_MACSEC_INC_SCI, props->include_sci); - NLA_PUT_U8(msg, IFLA_MACSEC_ES, props->es); - NLA_PUT_U8(msg, IFLA_MACSEC_SCB, props->scb); - NLA_PUT_U8(msg, IFLA_MACSEC_REPLAY_PROTECT, props->replay_protect); - NLA_PUT_U8(msg, IFLA_MACSEC_VALIDATION, props->validation); - break; - }; - case NM_LINK_TYPE_MACVTAP: - case NM_LINK_TYPE_MACVLAN: - { - const NMPlatformLnkMacvlan *props = extra_data; - - nm_assert(props); - - if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) - goto nla_put_failure; - - NLA_PUT_U32(msg, IFLA_MACVLAN_MODE, props->mode); - NLA_PUT_U16(msg, IFLA_MACVLAN_FLAGS, props->no_promisc ? MACVLAN_FLAG_NOPROMISC : 0); - break; - } - default: - nm_assert(!extra_data); - break; - } - - if (data) - nla_nest_end(msg, data); - - nla_nest_end(msg, info); - - return TRUE; -nla_put_failure: - g_return_val_if_reached(FALSE); -} - -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; - - 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); - -#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 (!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 (!(info = nla_nest_start(msg, IFLA_LINKINFO))) - goto nla_put_failure; - - NLA_PUT_STRING(msg, IFLA_INFO_KIND, "vlan"); - - if (!(data = nla_nest_start(msg, IFLA_INFO_DATA))) - goto nla_put_failure; - - if (vlan_id >= 0) - NLA_PUT_U16(msg, IFLA_VLAN_ID, vlan_id); - - if (flags_mask != 0) { - struct ifla_vlan_flags flags = { - .flags = flags_mask & flags_set, - .mask = flags_mask, - }; - - NLA_PUT(msg, IFLA_VLAN_FLAGS, sizeof(flags), &flags); - } - - if (ingress_qos && ingress_qos_len > 0) { - struct nlattr *qos = NULL; - - 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]); - } - } - - if (qos) - nla_nest_end(msg, qos); - } - - 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; - } - NLA_PUT(msg, i, sizeof(egress_qos[i]), &egress_qos[i]); - } - } - - if (qos) - nla_nest_end(msg, qos); - } - - nla_nest_end(msg, data); - nla_nest_end(msg, info); - - return TRUE; -nla_put_failure: - g_return_val_if_reached(FALSE); -} - -static struct nl_msg * -_nl_msg_new_link_full(int nlmsg_type, - int nlmsg_flags, - int ifindex, - const char *ifname, - guint8 family, - unsigned flags_mask, - unsigned flags_set) -{ - nm_auto_nlmsg struct nl_msg *msg = NULL; - const struct ifinfomsg ifi = { - .ifi_family = family, - .ifi_change = flags_mask, - .ifi_flags = flags_set, - .ifi_index = ifindex, - }; - - nm_assert(NM_IN_SET(nlmsg_type, RTM_DELLINK, RTM_NEWLINK, RTM_GETLINK, RTM_SETLINK)); - - msg = nlmsg_alloc_simple(nlmsg_type, nlmsg_flags); - - if (nlmsg_append_struct(msg, &ifi) < 0) - goto nla_put_failure; - - if (ifname) - NLA_PUT_STRING(msg, IFLA_IFNAME, ifname); - - return g_steal_pointer(&msg); - -nla_put_failure: - g_return_val_if_reached(NULL); -} - -static struct nl_msg * -_nl_msg_new_link(int nlmsg_type, int nlmsg_flags, int ifindex, const char *ifname) -{ - return _nl_msg_new_link_full(nlmsg_type, nlmsg_flags, ifindex, ifname, AF_UNSPEC, 0, 0); -} - -/* 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, - guint8 plen, - gconstpointer peer_address, - guint32 flags, - int scope, - guint32 lifetime, - guint32 preferred, - in_addr_t ip4_broadcast_address, - const char * label) -{ - nm_auto_nlmsg struct nl_msg *msg = NULL; - 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)); - - msg = nlmsg_alloc_simple(nlmsg_type, nlmsg_flags); - - 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 - scope = RT_SCOPE_UNIVERSE; - } - am.ifa_scope = scope, - - addr_len = family == AF_INET ? sizeof(in_addr_t) : sizeof(struct in6_addr); - - if (nlmsg_append_struct(msg, &am) < 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 (ip4_broadcast_address != 0) - NLA_PUT(msg, IFA_BROADCAST, sizeof(in_addr_t), &ip4_broadcast_address); - - if (lifetime != NM_PLATFORM_LIFETIME_PERMANENT || preferred != NM_PLATFORM_LIFETIME_PERMANENT) { - struct ifa_cacheinfo ca = { - .ifa_valid = lifetime, - .ifa_prefered = preferred, - }; - - NLA_PUT(msg, IFA_CACHEINFO, sizeof(ca), &ca); - } - - if (flags & ~((guint32) 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); - } - - return g_steal_pointer(&msg); - -nla_put_failure: - g_return_val_if_reached(NULL); -} - -static guint32 -ip_route_get_lock_flag(const NMPlatformIPRoute *route) -{ - return (((guint32) route->lock_window) << RTAX_WINDOW) - | (((guint32) route->lock_cwnd) << RTAX_CWND) - | (((guint32) route->lock_initcwnd) << RTAX_INITCWND) - | (((guint32) route->lock_initrwnd) << RTAX_INITRWND) - | (((guint32) route->lock_mtu) << RTAX_MTU); -} - -/* 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, guint16 nlmsgflags, const NMPObject *obj) -{ - nm_auto_nlmsg struct nl_msg *msg = NULL; - const NMPClass * klass = NMP_OBJECT_GET_CLASS(obj); - gboolean is_v4 = klass->addr_family == AF_INET; - const guint32 lock = ip_route_get_lock_flag(NMP_OBJECT_CAST_IP_ROUTE(obj)); - const guint32 table = - nm_platform_route_table_uncoerce(NMP_OBJECT_CAST_IP_ROUTE(obj)->table_coerced, TRUE); - const struct rtmsg rtmsg = { - .rtm_family = klass->addr_family, - .rtm_tos = is_v4 ? obj->ip4_route.tos : 0, - .rtm_table = table <= 0xFF ? table : RT_TABLE_UNSPEC, - .rtm_protocol = nmp_utils_ip_config_source_coerce_to_rtprot(obj->ip_route.rt_source), - .rtm_scope = - is_v4 ? nm_platform_route_scope_inv(obj->ip4_route.scope_inv) : RT_SCOPE_NOWHERE, - .rtm_type = nm_platform_route_type_uncoerce(NMP_OBJECT_CAST_IP_ROUTE(obj)->type_coerced), - .rtm_flags = obj->ip_route.r_rtm_flags & ((unsigned) (RTNH_F_ONLINK)), - .rtm_dst_len = obj->ip_route.plen, - .rtm_src_len = is_v4 ? 0 : NMP_OBJECT_CAST_IP6_ROUTE(obj)->src_plen, - }; - - gsize addr_len; - - nm_assert( - NM_IN_SET(NMP_OBJECT_GET_TYPE(obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); - nm_assert(NM_IN_SET(nlmsg_type, RTM_NEWROUTE, RTM_DELROUTE)); - - msg = nlmsg_alloc_simple(nlmsg_type, (int) nlmsgflags); - - if (nlmsg_append_struct(msg, &rtmsg) < 0) - goto nla_put_failure; - - addr_len = is_v4 ? sizeof(in_addr_t) : sizeof(struct in6_addr); - - NLA_PUT(msg, - RTA_DST, - addr_len, - is_v4 ? (gconstpointer) &obj->ip4_route.network - : (gconstpointer) &obj->ip6_route.network); - - if (!is_v4) { - if (!IN6_IS_ADDR_UNSPECIFIED(&NMP_OBJECT_CAST_IP6_ROUTE(obj)->src)) - NLA_PUT(msg, RTA_SRC, addr_len, &obj->ip6_route.src); - } - - NLA_PUT_U32(msg, - RTA_PRIORITY, - is_v4 ? nm_platform_ip4_route_get_effective_metric(&obj->ip4_route) - : nm_platform_ip6_route_get_effective_metric(&obj->ip6_route)); - - if (table > 0xFF) - NLA_PUT_U32(msg, RTA_TABLE, table); - - if (is_v4) { - if (NMP_OBJECT_CAST_IP4_ROUTE(obj)->pref_src) - NLA_PUT(msg, RTA_PREFSRC, addr_len, &obj->ip4_route.pref_src); - } else { - if (!IN6_IS_ADDR_UNSPECIFIED(&NMP_OBJECT_CAST_IP6_ROUTE(obj)->pref_src)) - NLA_PUT(msg, RTA_PREFSRC, addr_len, &obj->ip6_route.pref_src); - } - - if (obj->ip_route.mss || obj->ip_route.window || obj->ip_route.cwnd || obj->ip_route.initcwnd - || obj->ip_route.initrwnd || obj->ip_route.mtu || lock) { - struct nlattr *metrics; - - metrics = nla_nest_start(msg, RTA_METRICS); - if (!metrics) - goto nla_put_failure; - - if (obj->ip_route.mss) - NLA_PUT_U32(msg, RTAX_ADVMSS, obj->ip_route.mss); - if (obj->ip_route.window) - NLA_PUT_U32(msg, RTAX_WINDOW, obj->ip_route.window); - if (obj->ip_route.cwnd) - NLA_PUT_U32(msg, RTAX_CWND, obj->ip_route.cwnd); - if (obj->ip_route.initcwnd) - NLA_PUT_U32(msg, RTAX_INITCWND, obj->ip_route.initcwnd); - if (obj->ip_route.initrwnd) - NLA_PUT_U32(msg, RTAX_INITRWND, obj->ip_route.initrwnd); - if (obj->ip_route.mtu) - NLA_PUT_U32(msg, RTAX_MTU, obj->ip_route.mtu); - if (lock) - NLA_PUT_U32(msg, RTAX_LOCK, lock); - - nla_nest_end(msg, metrics); - } - - /* We currently don't have need for multi-hop routes... */ - if (is_v4) { - NLA_PUT(msg, RTA_GATEWAY, addr_len, &obj->ip4_route.gateway); - } else { - if (!IN6_IS_ADDR_UNSPECIFIED(&obj->ip6_route.gateway)) - NLA_PUT(msg, RTA_GATEWAY, addr_len, &obj->ip6_route.gateway); - } - NLA_PUT_U32(msg, RTA_OIF, obj->ip_route.ifindex); - - if (!is_v4 && obj->ip6_route.rt_pref != NM_ICMPV6_ROUTER_PREF_MEDIUM) - NLA_PUT_U8(msg, RTA_PREF, obj->ip6_route.rt_pref); - - return g_steal_pointer(&msg); - -nla_put_failure: - g_return_val_if_reached(NULL); -} - -static struct nl_msg * -_nl_msg_new_routing_rule(int nlmsg_type, int nlmsg_flags, const NMPlatformRoutingRule *routing_rule) -{ - nm_auto_nlmsg struct nl_msg *msg = NULL; - const guint8 addr_size = nm_utils_addr_family_to_size(routing_rule->addr_family); - guint32 table; - - msg = nlmsg_alloc_simple(nlmsg_type, nlmsg_flags); - - table = routing_rule->table; - - if (NM_IN_SET(routing_rule->addr_family, AF_INET, AF_INET6) - && routing_rule->action == FR_ACT_TO_TBL && routing_rule->l3mdev == 0 - && table == RT_TABLE_UNSPEC) { - /* for IPv6, this setting is invalid and rejected by kernel. That's fine. - * - * for IPv4, kernel will automatically assign an unused table. That's not - * fine, because we don't know what we will get. - * - * The caller must not allow that to happen. */ - nm_assert_not_reached(); - } - - { - const struct fib_rule_hdr frh = { - .family = routing_rule->addr_family, - .src_len = routing_rule->src_len, - .dst_len = routing_rule->dst_len, - .tos = routing_rule->tos, - .table = table < 0x100u ? (guint8) table : (guint8) RT_TABLE_UNSPEC, - .action = routing_rule->action, - - /* we only allow setting the "not" flag. */ - .flags = routing_rule->flags & ((guint32) FIB_RULE_INVERT), - }; - - if (nlmsg_append_struct(msg, &frh) < 0) - goto nla_put_failure; - } - - if (table > G_MAXINT8) - NLA_PUT_U32(msg, FRA_TABLE, table); - - if (routing_rule->suppress_prefixlen_inverse != 0) - NLA_PUT_U32(msg, FRA_SUPPRESS_PREFIXLEN, ~routing_rule->suppress_prefixlen_inverse); - - if (routing_rule->suppress_ifgroup_inverse != 0) - NLA_PUT_U32(msg, FRA_SUPPRESS_IFGROUP, ~routing_rule->suppress_ifgroup_inverse); - - if (routing_rule->iifname[0] != '\0') - NLA_PUT_STRING(msg, FRA_IIFNAME, routing_rule->iifname); - - if (routing_rule->oifname[0] != '\0') - NLA_PUT_STRING(msg, FRA_OIFNAME, routing_rule->oifname); - - /* we always set the priority and don't support letting kernel pick one. */ - NLA_PUT_U32(msg, FRA_PRIORITY, routing_rule->priority); - - if (routing_rule->fwmark != 0 || routing_rule->fwmask != 0) { - NLA_PUT_U32(msg, FRA_FWMARK, routing_rule->fwmark); - NLA_PUT_U32(msg, FRA_FWMASK, routing_rule->fwmask); - } - - if (routing_rule->src_len > 0) - NLA_PUT(msg, FRA_SRC, addr_size, &routing_rule->src); - - if (routing_rule->dst_len > 0) - NLA_PUT(msg, FRA_DST, addr_size, &routing_rule->dst); - - if (routing_rule->flow != 0) { - /* only relevant for IPv4. */ - NLA_PUT_U32(msg, FRA_FLOW, routing_rule->flow); - } - - if (routing_rule->tun_id != 0) - NLA_PUT_U64(msg, FRA_TUN_ID, htobe64(routing_rule->tun_id)); - - if (routing_rule->l3mdev) - NLA_PUT_U8(msg, FRA_L3MDEV, routing_rule->l3mdev); - - if (routing_rule->protocol != RTPROT_UNSPEC) - NLA_PUT_U8(msg, FRA_PROTOCOL, routing_rule->protocol); - - if (routing_rule->ip_proto != 0) - NLA_PUT_U8(msg, FRA_IP_PROTO, routing_rule->ip_proto); - - if (routing_rule->sport_range.start || routing_rule->sport_range.end) - NLA_PUT(msg, - FRA_SPORT_RANGE, - sizeof(routing_rule->sport_range), - &routing_rule->sport_range); - - if (routing_rule->dport_range.start || routing_rule->dport_range.end) - NLA_PUT(msg, - FRA_DPORT_RANGE, - sizeof(routing_rule->dport_range), - &routing_rule->dport_range); - - if (routing_rule->uid_range_has) - NLA_PUT(msg, FRA_UID_RANGE, sizeof(routing_rule->uid_range), &routing_rule->uid_range); - - switch (routing_rule->action) { - case FR_ACT_GOTO: - NLA_PUT_U32(msg, FRA_GOTO, routing_rule->goto_target); - break; - } - - return g_steal_pointer(&msg); - -nla_put_failure: - g_return_val_if_reached(NULL); -} - -static struct nl_msg * -_nl_msg_new_qdisc(int nlmsg_type, int nlmsg_flags, const NMPlatformQdisc *qdisc) -{ - nm_auto_nlmsg struct nl_msg *msg = NULL; - struct nlattr * tc_options; - const struct tcmsg tcm = { - .tcm_family = qdisc->addr_family, - .tcm_ifindex = qdisc->ifindex, - .tcm_handle = qdisc->handle, - .tcm_parent = qdisc->parent, - .tcm_info = qdisc->info, - }; - - msg = nlmsg_alloc_simple(nlmsg_type, nlmsg_flags | NMP_NLM_FLAG_F_ECHO); - - if (nlmsg_append_struct(msg, &tcm) < 0) - goto nla_put_failure; - - NLA_PUT_STRING(msg, TCA_KIND, qdisc->kind); - - if (nm_streq(qdisc->kind, "sfq")) { - struct tc_sfq_qopt_v1 opt = {}; - - opt.v0.quantum = qdisc->sfq.quantum; - opt.v0.limit = qdisc->sfq.limit; - opt.v0.perturb_period = qdisc->sfq.perturb_period; - opt.v0.flows = qdisc->sfq.flows; - opt.v0.divisor = qdisc->sfq.divisor; - opt.depth = qdisc->sfq.depth; - - NLA_PUT(msg, TCA_OPTIONS, sizeof(opt), &opt); - } else if (nm_streq(qdisc->kind, "tbf")) { - struct tc_tbf_qopt opt = {}; - - if (!(tc_options = nla_nest_start(msg, TCA_OPTIONS))) - goto nla_put_failure; - - opt.rate.rate = (qdisc->tbf.rate >= (1ULL << 32)) ? ~0U : (guint32) qdisc->tbf.rate; - if (qdisc->tbf.limit) - opt.limit = qdisc->tbf.limit; - else if (qdisc->tbf.latency) { - opt.limit = qdisc->tbf.rate * (double) qdisc->tbf.latency / PSCHED_TIME_UNITS_PER_SEC - + qdisc->tbf.burst; - } - - NLA_PUT(msg, TCA_TBF_PARMS, sizeof(opt), &opt); - if (qdisc->tbf.rate >= (1ULL << 32)) - NLA_PUT_U64(msg, TCA_TBF_RATE64, qdisc->tbf.rate); - NLA_PUT_U32(msg, TCA_TBF_BURST, qdisc->tbf.burst); - - nla_nest_end(msg, tc_options); - } else if (nm_streq(qdisc->kind, "prio")) { - struct tc_prio_qopt opt = {3, {1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}}; - - NLA_PUT(msg, TCA_OPTIONS, sizeof(opt), &opt); - } else { - if (!(tc_options = nla_nest_start(msg, TCA_OPTIONS))) - goto nla_put_failure; - - if (nm_streq(qdisc->kind, "fq_codel")) { - if (qdisc->fq_codel.limit) - NLA_PUT_U32(msg, TCA_FQ_CODEL_LIMIT, qdisc->fq_codel.limit); - if (qdisc->fq_codel.flows) - NLA_PUT_U32(msg, TCA_FQ_CODEL_FLOWS, qdisc->fq_codel.flows); - if (qdisc->fq_codel.target) - NLA_PUT_U32(msg, TCA_FQ_CODEL_TARGET, qdisc->fq_codel.target); - if (qdisc->fq_codel.interval) - NLA_PUT_U32(msg, TCA_FQ_CODEL_INTERVAL, qdisc->fq_codel.interval); - if (qdisc->fq_codel.quantum) - NLA_PUT_U32(msg, TCA_FQ_CODEL_QUANTUM, qdisc->fq_codel.quantum); - if (qdisc->fq_codel.ce_threshold != NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED) - NLA_PUT_U32(msg, TCA_FQ_CODEL_CE_THRESHOLD, qdisc->fq_codel.ce_threshold); - if (qdisc->fq_codel.memory_limit != NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET) - NLA_PUT_U32(msg, TCA_FQ_CODEL_MEMORY_LIMIT, qdisc->fq_codel.memory_limit); - if (qdisc->fq_codel.ecn) - NLA_PUT_U32(msg, TCA_FQ_CODEL_ECN, qdisc->fq_codel.ecn); - } - - nla_nest_end(msg, tc_options); - } - - return g_steal_pointer(&msg); - -nla_put_failure: - g_return_val_if_reached(NULL); -} - -static struct nl_msg * -_nl_msg_new_tfilter(int nlmsg_type, int nlmsg_flags, const NMPlatformTfilter *tfilter) -{ - nm_auto_nlmsg struct nl_msg *msg = NULL; - struct nlattr * tc_options; - struct nlattr * act_tab; - const struct tcmsg tcm = { - .tcm_family = tfilter->addr_family, - .tcm_ifindex = tfilter->ifindex, - .tcm_handle = tfilter->handle, - .tcm_parent = tfilter->parent, - .tcm_info = tfilter->info, - }; - - msg = nlmsg_alloc_simple(nlmsg_type, nlmsg_flags | NMP_NLM_FLAG_F_ECHO); - - if (nlmsg_append_struct(msg, &tcm) < 0) - goto nla_put_failure; - - NLA_PUT_STRING(msg, TCA_KIND, tfilter->kind); - - if (!(tc_options = nla_nest_start(msg, TCA_OPTIONS))) - goto nla_put_failure; - - if (!(act_tab = nla_nest_start(msg, TCA_OPTIONS))) // 3 TCA_ACT_KIND TCA_ACT_KIND - goto nla_put_failure; - - if (tfilter->action.kind) { - const NMPlatformAction *action = &tfilter->action; - struct nlattr * prio; - struct nlattr * act_options; - - if (!(prio = nla_nest_start(msg, 1 /* priority */))) - goto nla_put_failure; - - NLA_PUT_STRING(msg, TCA_ACT_KIND, action->kind); - - if (nm_streq(action->kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) { - const NMPlatformActionSimple *simple = &action->simple; - struct tc_defact sel = { - 0, - }; - - if (!(act_options = nla_nest_start(msg, TCA_ACT_OPTIONS))) - goto nla_put_failure; - - NLA_PUT(msg, TCA_DEF_PARMS, sizeof(sel), &sel); - NLA_PUT(msg, TCA_DEF_DATA, sizeof(simple->sdata), simple->sdata); - - nla_nest_end(msg, act_options); - - } else if (nm_streq(action->kind, NM_PLATFORM_ACTION_KIND_MIRRED)) { - const NMPlatformActionMirred *mirred = &action->mirred; - struct tc_mirred sel = { - 0, - }; - - if (!(act_options = nla_nest_start(msg, TCA_ACT_OPTIONS))) - goto nla_put_failure; - - if (mirred->egress && mirred->redirect) - sel.eaction = TCA_EGRESS_REDIR; - else if (mirred->egress && mirred->mirror) - sel.eaction = TCA_EGRESS_MIRROR; - else if (mirred->ingress && mirred->redirect) - sel.eaction = TCA_INGRESS_REDIR; - else if (mirred->ingress && mirred->mirror) - sel.eaction = TCA_INGRESS_MIRROR; - sel.ifindex = mirred->ifindex; - - NLA_PUT(msg, TCA_MIRRED_PARMS, sizeof(sel), &sel); - - nla_nest_end(msg, act_options); - } - - nla_nest_end(msg, prio); - } - - nla_nest_end(msg, tc_options); - - nla_nest_end(msg, act_tab); - - return g_steal_pointer(&msg); - -nla_put_failure: - g_return_val_if_reached(NULL); -} - -/*****************************************************************************/ - -static struct nl_sock * -_genl_sock(NMLinuxPlatform *platform) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - - return priv->genl; -} - -#define ASSERT_SYSCTL_ARGS(pathid, dirfd, path) \ - G_STMT_START \ - { \ - const char *const _pathid = (pathid); \ - const int _dirfd = (dirfd); \ - const char *const _path = (path); \ - \ - nm_assert(_path &&_path[0]); \ - g_assert(!strstr(_path, "/../")); \ - if (_dirfd < 0) { \ - nm_assert(!_pathid); \ - nm_assert(_path[0] == '/'); \ - nm_assert(g_str_has_prefix(_path, "/proc/sys/") || g_str_has_prefix(_path, "/sys/") \ - || g_str_has_prefix(_path, "/proc/net")); \ - } else { \ - nm_assert(_pathid &&_pathid[0] && _pathid[0] != '/'); \ - nm_assert(_path[0] != '/'); \ - } \ - } \ - G_STMT_END - -/*****************************************************************************/ - -/* core sysctl-set functions can be called from a non-main thread. - * Hence, we require locking from nm-logging. Indicate that by - * setting NM_THREAD_SAFE_ON_MAIN_THREAD to zero. */ -#undef NM_THREAD_SAFE_ON_MAIN_THREAD -#define NM_THREAD_SAFE_ON_MAIN_THREAD 0 - -static void -_log_dbg_sysctl_set_impl(NMPlatform *platform, - const char *pathid, - int dirfd, - const char *path, - const char *value) -{ - GError * error = NULL; - gs_free char *contents = NULL; - gs_free char *value_escaped = g_strescape(value, NULL); - - if (!nm_utils_file_get_contents(dirfd, - path, - 1 * 1024 * 1024, - NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE, - &contents, - NULL, - NULL, - &error)) { - _LOGD("sysctl: setting '%s' to '%s' (current value cannot be read: %s)", - pathid ?: path, - value_escaped, - error->message); - g_clear_error(&error); - return; - } - - g_strstrip(contents); - if (nm_streq(contents, value)) - _LOGD("sysctl: setting '%s' to '%s' (current value is identical)", - pathid ?: path, - value_escaped); - else { - gs_free char *contents_escaped = g_strescape(contents, NULL); - - _LOGD("sysctl: setting '%s' to '%s' (current value is '%s')", - pathid ?: path, - value_escaped, - contents_escaped); - } -} - -#define _log_dbg_sysctl_set(platform, pathid, dirfd, path, value) \ - G_STMT_START \ - { \ - if (_LOGD_ENABLED()) { \ - _log_dbg_sysctl_set_impl(platform, pathid, dirfd, path, value); \ - } \ - } \ - G_STMT_END - -static gboolean -sysctl_set_internal(NMPlatform *platform, - const char *pathid, - int dirfd, - const char *path, - const char *value) -{ - int fd, tries; - gssize nwrote; - gssize len; - char * actual; - gs_free char *actual_free = NULL; - int errsv; - - if (dirfd < 0) { - pathid = path; - - fd = open(path, O_WRONLY | O_TRUNC | O_CLOEXEC); - if (fd == -1) { - errsv = errno; - if (errsv == ENOENT) { - _LOGD("sysctl: failed to open '%s': (%d) %s", - pathid, - errsv, - nm_strerror_native(errsv)); - } else { - _LOGE("sysctl: failed to open '%s': (%d) %s", - pathid, - errsv, - nm_strerror_native(errsv)); - } - errno = errsv; - return FALSE; - } - } else { - fd = openat(dirfd, path, O_WRONLY | O_TRUNC | O_CLOEXEC); - if (fd == -1) { - errsv = errno; - if (errsv == ENOENT) { - _LOGD("sysctl: failed to openat '%s': (%d) %s", - pathid, - errsv, - nm_strerror_native(errsv)); - } else { - _LOGE("sysctl: failed to openat '%s': (%d) %s", - pathid, - errsv, - nm_strerror_native(errsv)); - } - errno = errsv; - return FALSE; - } - } - - _log_dbg_sysctl_set(platform, pathid, dirfd, path, value); - - /* Most sysfs and sysctl options don't care about a trailing LF, while some - * (like infiniband) do. So always add the LF. Also, neither sysfs nor - * sysctl support partial writes so the LF must be added to the string we're - * about to write. - */ - len = strlen(value) + 1; - nm_assert(len > 0); - if (len > 512) - actual = actual_free = g_malloc(len + 1); - else - actual = g_alloca(len + 1); - memcpy(actual, value, len - 1); - actual[len - 1] = '\n'; - actual[len] = '\0'; - - /* Try to write the entire value three times if a partial write occurs */ - errsv = 0; - for (tries = 0, nwrote = 0; tries < 3 && nwrote < len - 1; tries++) { - nwrote = write(fd, actual, len); - if (nwrote == -1) { - errsv = errno; - if (errsv == EINTR) { - _LOGD("sysctl: interrupted, will try again"); - continue; - } - break; - } - } - if (nwrote == -1) { - NMLogLevel level = LOGL_ERR; - - if (errsv == EEXIST) { - level = LOGL_DEBUG; - } else if (errsv == EINVAL - && nm_utils_sysctl_ip_conf_is_path(AF_INET6, path, NULL, "mtu")) { - /* setting the MTU can fail under regular conditions. Suppress - * logging a warning. */ - level = LOGL_DEBUG; - } - - _NMLOG(level, - "sysctl: failed to set '%s' to '%s': (%d) %s", - path, - value, - errsv, - nm_strerror_native(errsv)); - } else if (nwrote < len - 1) { - _LOGE("sysctl: failed to set '%s' to '%s' after three attempts", path, value); - } - - if (nwrote < len - 1) { - if (nm_close(fd) != 0) { - if (errsv != 0) - errno = errsv; - } else if (errsv != 0) - errno = errsv; - else - errno = EIO; - return FALSE; - } - if (nm_close(fd) != 0) { - /* errno is already properly set. */ - return FALSE; - } - - /* success. errno is undefined (no need to set). */ - return TRUE; -} - -#undef NM_THREAD_SAFE_ON_MAIN_THREAD -#define NM_THREAD_SAFE_ON_MAIN_THREAD 1 - -/*****************************************************************************/ - -static gboolean -sysctl_set(NMPlatform *platform, const char *pathid, int dirfd, const char *path, const char *value) -{ - nm_auto_pop_netns NMPNetns *netns = NULL; - - g_return_val_if_fail(path, FALSE); - g_return_val_if_fail(value, FALSE); - - ASSERT_SYSCTL_ARGS(pathid, dirfd, path); - - if (dirfd < 0 && !nm_platform_netns_push(platform, &netns)) { - errno = ENETDOWN; - return FALSE; - } - - return sysctl_set_internal(platform, pathid, dirfd, path, value); -} - -typedef struct { - NMPlatform * platform; - char * pathid; - int dirfd; - char * path; - char ** values; - GCancellable * cancellable; - NMPlatformAsyncCallback callback; - gpointer callback_data; -} SysctlAsyncInfo; - -static void -sysctl_async_info_free(SysctlAsyncInfo *info) -{ - g_object_unref(info->platform); - g_free(info->pathid); - if (info->dirfd >= 0) - nm_close(info->dirfd); - g_free(info->path); - g_strfreev(info->values); - g_object_unref(info->cancellable); - g_slice_free(SysctlAsyncInfo, info); -} - -static void -sysctl_async_cb(GObject *object, GAsyncResult *res, gpointer user_data) -{ - NMPlatform * platform; - GTask * task = G_TASK(res); - SysctlAsyncInfo *info; - gs_free_error GError *error = NULL; - gs_free char * values_str = NULL; - - info = g_task_get_task_data(task); - - if (g_task_propagate_boolean(task, &error)) { - platform = info->platform; - _LOGD("sysctl: successfully set-async '%s' to values '%s'", - info->pathid ?: info->path, - (values_str = g_strjoinv(", ", info->values))); - } - - if (info->callback) - info->callback(error, info->callback_data); -} - -static void -sysctl_async_thread_fn(GTask * task, - gpointer source_object, - gpointer task_data, - GCancellable *cancellable) -{ - nm_auto_pop_netns NMPNetns *netns = NULL; - SysctlAsyncInfo * info = task_data; - GError * error = NULL; - char ** value; - - if (g_task_return_error_if_cancelled(task)) - return; - - if (info->dirfd < 0 && !nm_platform_netns_push(info->platform, &netns)) { - g_set_error_literal(&error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "sysctl: failed changing namespace"); - g_task_return_error(task, error); - return; - } - - for (value = info->values; *value; value++) { - if (!sysctl_set_internal(info->platform, info->pathid, info->dirfd, info->path, *value)) { - g_set_error(&error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "sysctl: failed setting '%s' to value '%s': %s", - info->pathid ?: info->path, - *value, - nm_strerror_native(errno)); - g_task_return_error(task, error); - return; - } - if (g_task_return_error_if_cancelled(task)) - return; - } - g_task_return_boolean(task, TRUE); -} - -static void -sysctl_set_async_return_idle(gpointer user_data, GCancellable *cancellable) -{ - gs_unref_object NMPlatform *platform = NULL; - gs_free_error GError *cancelled_error = NULL; - gs_free_error GError * error = NULL; - NMPlatformAsyncCallback callback; - gpointer callback_data; - - nm_utils_user_data_unpack(user_data, &platform, &callback, &callback_data, &error); - g_cancellable_set_error_if_cancelled(cancellable, &cancelled_error); - callback(cancelled_error ?: error, callback_data); -} - -static void -sysctl_set_async(NMPlatform * platform, - const char * pathid, - int dirfd, - const char * path, - const char *const * values, - NMPlatformAsyncCallback callback, - gpointer data, - GCancellable * cancellable) -{ - SysctlAsyncInfo *info; - GTask * task; - int dirfd_dup, errsv; - gpointer packed; - GError * error = NULL; - - g_return_if_fail(platform); - g_return_if_fail(path); - g_return_if_fail(values && values[0]); - g_return_if_fail(cancellable); - g_return_if_fail(!data || callback); - - ASSERT_SYSCTL_ARGS(pathid, dirfd, path); - - if (dirfd >= 0) { - dirfd_dup = fcntl(dirfd, F_DUPFD_CLOEXEC, 0); - if (dirfd_dup < 0) { - if (!callback) - return; - errsv = errno; - g_set_error(&error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "sysctl: failure duplicating directory fd: %s", - nm_strerror_native(errsv)); - packed = nm_utils_user_data_pack(g_object_ref(platform), callback, data, error); - nm_utils_invoke_on_idle(cancellable, sysctl_set_async_return_idle, packed); - return; - } - } else - dirfd_dup = -1; - - info = g_slice_new0(SysctlAsyncInfo); - info->platform = g_object_ref(platform); - info->pathid = g_strdup(pathid); - info->dirfd = dirfd_dup; - info->path = g_strdup(path); - info->values = g_strdupv((char **) values); - info->callback = callback; - info->callback_data = data; - info->cancellable = g_object_ref(cancellable); - - task = g_task_new(platform, cancellable, sysctl_async_cb, NULL); - g_task_set_task_data(task, info, (GDestroyNotify) sysctl_async_info_free); - g_task_set_return_on_cancel(task, FALSE); - g_task_run_in_thread(task, sysctl_async_thread_fn); - g_object_unref(task); -} - -static GSList *sysctl_clear_cache_list; - -void -_nm_logging_clear_platform_logging_cache(void) -{ - while (sysctl_clear_cache_list) { - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(sysctl_clear_cache_list->data); - - sysctl_clear_cache_list = - g_slist_delete_link(sysctl_clear_cache_list, sysctl_clear_cache_list); - - g_hash_table_destroy(priv->sysctl_get_prev_values); - priv->sysctl_get_prev_values = NULL; - } -} - -typedef struct { - const char *path; - CList lst; - char * value; - char path_data[]; -} SysctlCacheEntry; - -static void -sysctl_cache_entry_free(SysctlCacheEntry *entry) -{ - c_list_unlink_stale(&entry->lst); - g_free(entry->value); - g_free(entry); -} - -static void -_log_dbg_sysctl_get_impl(NMPlatform *platform, const char *pathid, const char *contents) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - SysctlCacheEntry * entry = NULL; - - if (!priv->sysctl_get_prev_values) { - sysctl_clear_cache_list = g_slist_prepend(sysctl_clear_cache_list, platform); - c_list_init(&priv->sysctl_list); - priv->sysctl_get_prev_values = - g_hash_table_new_full(nm_pstr_hash, - nm_pstr_equal, - (GDestroyNotify) sysctl_cache_entry_free, - NULL); - } else - entry = g_hash_table_lookup(priv->sysctl_get_prev_values, &pathid); - - if (entry) { - if (!nm_streq(entry->value, contents)) { - gs_free char *contents_escaped = g_strescape(contents, NULL); - gs_free char *prev_value_escaped = g_strescape(entry->value, NULL); - - _LOGD("sysctl: reading '%s': '%s' (changed from '%s' on last read)", - pathid, - contents_escaped, - prev_value_escaped); - g_free(entry->value); - entry->value = g_strdup(contents); - } - nm_c_list_move_front(&priv->sysctl_list, &entry->lst); - } else { - gs_free char * contents_escaped = g_strescape(contents, NULL); - SysctlCacheEntry *old; - size_t len; - - len = strlen(pathid); - entry = g_malloc(sizeof(SysctlCacheEntry) + len + 1); - entry->value = g_strdup(contents); - entry->path = entry->path_data; - memcpy(entry->path_data, pathid, len + 1); - - /* Remove oldest entry when the cache becomes too big */ - if (g_hash_table_size(priv->sysctl_get_prev_values) > 1000) { - old = c_list_last_entry(&priv->sysctl_list, SysctlCacheEntry, lst); - g_hash_table_remove(priv->sysctl_get_prev_values, old); - } - - _LOGD("sysctl: reading '%s': '%s'", pathid, contents_escaped); - - g_hash_table_add(priv->sysctl_get_prev_values, entry); - c_list_link_front(&priv->sysctl_list, &entry->lst); - } -} - -#define _log_dbg_sysctl_get(platform, pathid, contents) \ - G_STMT_START \ - { \ - if (_LOGD_ENABLED()) \ - _log_dbg_sysctl_get_impl(platform, pathid, contents); \ - } \ - G_STMT_END - -static char * -sysctl_get(NMPlatform *platform, const char *pathid, int dirfd, const char *path) -{ - nm_auto_pop_netns NMPNetns *netns = NULL; - GError * error = NULL; - gs_free char * contents = NULL; - - ASSERT_SYSCTL_ARGS(pathid, dirfd, path); - - if (dirfd < 0) { - if (!nm_platform_netns_push(platform, &netns)) { - errno = EBUSY; - return NULL; - } - pathid = path; - } - - if (!nm_utils_file_get_contents(dirfd, - path, - 1 * 1024 * 1024, - NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE, - &contents, - NULL, - NULL, - &error)) { - NMLogLevel log_level = LOGL_ERR; - int errsv = EBUSY; - - if (g_error_matches(error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) { - errsv = ENOENT; - log_level = LOGL_DEBUG; - } else if (g_error_matches(error, G_FILE_ERROR, G_FILE_ERROR_NODEV) - || g_error_matches(error, G_FILE_ERROR, G_FILE_ERROR_FAILED)) { - /* We assume FAILED means EOPNOTSUP and don't log a error message. */ - log_level = LOGL_DEBUG; - } - - _NMLOG(log_level, "error reading %s: %s", pathid, error->message); - g_clear_error(&error); - errno = errsv; - return NULL; - } - - g_strstrip(contents); - - _log_dbg_sysctl_get(platform, pathid, contents); - - /* errno is left undefined (as we don't return NULL). */ - return g_steal_pointer(&contents); -} - -/*****************************************************************************/ - -static void -process_events(NMPlatform *platform) -{ - delayed_action_handle_all(platform, TRUE); -} - -/*****************************************************************************/ - -static const RefreshAllInfo * -refresh_all_type_get_info(RefreshAllType refresh_all_type) -{ - static const RefreshAllInfo infos[] = { -#define R(_refresh_all_type, _obj_type, _addr_family) \ - [_refresh_all_type] = { \ - .obj_type = _obj_type, \ - .addr_family = _addr_family, \ - } - R(REFRESH_ALL_TYPE_LINKS, NMP_OBJECT_TYPE_LINK, AF_UNSPEC), - R(REFRESH_ALL_TYPE_IP4_ADDRESSES, NMP_OBJECT_TYPE_IP4_ADDRESS, AF_UNSPEC), - R(REFRESH_ALL_TYPE_IP6_ADDRESSES, NMP_OBJECT_TYPE_IP6_ADDRESS, AF_UNSPEC), - R(REFRESH_ALL_TYPE_IP4_ROUTES, NMP_OBJECT_TYPE_IP4_ROUTE, AF_UNSPEC), - R(REFRESH_ALL_TYPE_IP6_ROUTES, NMP_OBJECT_TYPE_IP6_ROUTE, AF_UNSPEC), - R(REFRESH_ALL_TYPE_ROUTING_RULES_IP4, NMP_OBJECT_TYPE_ROUTING_RULE, AF_INET), - R(REFRESH_ALL_TYPE_ROUTING_RULES_IP6, NMP_OBJECT_TYPE_ROUTING_RULE, AF_INET6), - R(REFRESH_ALL_TYPE_QDISCS, NMP_OBJECT_TYPE_QDISC, AF_UNSPEC), - R(REFRESH_ALL_TYPE_TFILTERS, NMP_OBJECT_TYPE_TFILTER, AF_UNSPEC), -#undef R - }; - - nm_assert(_NM_INT_NOT_NEGATIVE(refresh_all_type)); - nm_assert(refresh_all_type < G_N_ELEMENTS(infos)); - nm_assert(nmp_class_from_type(infos[refresh_all_type].obj_type)); - - return &infos[refresh_all_type]; -} - -static NM_UTILS_LOOKUP_DEFINE( - delayed_action_type_to_refresh_all_type, - DelayedActionType, - RefreshAllType, - NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT(0), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS, REFRESH_ALL_TYPE_LINKS), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES, - REFRESH_ALL_TYPE_IP4_ADDRESSES), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, - REFRESH_ALL_TYPE_IP6_ADDRESSES), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, REFRESH_ALL_TYPE_IP4_ROUTES), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, REFRESH_ALL_TYPE_IP6_ROUTES), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4, - REFRESH_ALL_TYPE_ROUTING_RULES_IP4), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6, - REFRESH_ALL_TYPE_ROUTING_RULES_IP6), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, REFRESH_ALL_TYPE_QDISCS), - NM_UTILS_LOOKUP_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, REFRESH_ALL_TYPE_TFILTERS), - NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER(), ); - -static DelayedActionType -delayed_action_type_from_refresh_all_type(RefreshAllType refresh_all_type) -{ - DelayedActionType t; - - nm_assert(refresh_all_type_get_info(refresh_all_type)); - - t = (((DelayedActionType) 1) << refresh_all_type); - - nm_assert(refresh_all_type == delayed_action_type_to_refresh_all_type(t)); - - return t; -} - -static RefreshAllType -refresh_all_type_from_needle_object(const NMPObject *obj_needle) -{ - switch (NMP_OBJECT_GET_TYPE(obj_needle)) { - case NMP_OBJECT_TYPE_LINK: - return REFRESH_ALL_TYPE_LINKS; - case NMP_OBJECT_TYPE_IP4_ADDRESS: - return REFRESH_ALL_TYPE_IP4_ADDRESSES; - case NMP_OBJECT_TYPE_IP6_ADDRESS: - return REFRESH_ALL_TYPE_IP6_ADDRESSES; - case NMP_OBJECT_TYPE_IP4_ROUTE: - return REFRESH_ALL_TYPE_IP4_ROUTES; - case NMP_OBJECT_TYPE_IP6_ROUTE: - return REFRESH_ALL_TYPE_IP6_ROUTES; - case NMP_OBJECT_TYPE_QDISC: - return REFRESH_ALL_TYPE_QDISCS; - case NMP_OBJECT_TYPE_TFILTER: - return REFRESH_ALL_TYPE_TFILTERS; - case NMP_OBJECT_TYPE_ROUTING_RULE: - switch (NMP_OBJECT_CAST_ROUTING_RULE(obj_needle)->addr_family) { - case AF_INET: - return REFRESH_ALL_TYPE_ROUTING_RULES_IP4; - case AF_INET6: - return REFRESH_ALL_TYPE_ROUTING_RULES_IP6; - } - nm_assert_not_reached(); - return 0; - default: - nm_assert_not_reached(); - return 0; - } -} - -static const NMPLookup * -refresh_all_type_init_lookup(RefreshAllType refresh_all_type, NMPLookup *lookup) -{ - const RefreshAllInfo *refresh_all_info; - - nm_assert(lookup); - - refresh_all_info = refresh_all_type_get_info(refresh_all_type); - - nm_assert(refresh_all_info); - - if (NM_IN_SET(refresh_all_info->obj_type, NMP_OBJECT_TYPE_ROUTING_RULE)) { - return nmp_lookup_init_object_by_addr_family(lookup, - refresh_all_info->obj_type, - refresh_all_info->addr_family); - } - - /* not yet implemented. */ - nm_assert(refresh_all_info->addr_family == AF_UNSPEC); - - return nmp_lookup_init_obj_type(lookup, refresh_all_info->obj_type); -} - -static DelayedActionType -delayed_action_refresh_from_needle_object(const NMPObject *obj_needle) -{ - return delayed_action_type_from_refresh_all_type( - refresh_all_type_from_needle_object(obj_needle)); -} - -static NM_UTILS_LOOKUP_STR_DEFINE( - delayed_action_to_string, - DelayedActionType, - NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT("unknown"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS, "refresh-all-links"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES, - "refresh-all-ip4-addresses"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, - "refresh-all-ip6-addresses"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, "refresh-all-ip4-routes"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, "refresh-all-ip6-routes"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP4, - "refresh-all-routing-rules-ip4"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_IP6, - "refresh-all-routing-rules-ip6"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS, "refresh-all-qdiscs"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, "refresh-all-tfilters"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_REFRESH_LINK, "refresh-link"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_MASTER_CONNECTED, "master-connected"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_READ_NETLINK, "read-netlink"), - NM_UTILS_LOOKUP_STR_ITEM(DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE, "wait-for-nl-response"), - NM_UTILS_LOOKUP_ITEM_IGNORE(DELAYED_ACTION_TYPE_NONE), - NM_UTILS_LOOKUP_ITEM_IGNORE(DELAYED_ACTION_TYPE_REFRESH_ALL), - NM_UTILS_LOOKUP_ITEM_IGNORE(DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL), - NM_UTILS_LOOKUP_ITEM_IGNORE(__DELAYED_ACTION_TYPE_MAX), ); - -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_nsec(); - char b[255]; - - nm_utils_strbuf_append( - &buf, - &buf_size, - " (seq %u, timeout in %s%" G_GINT64_FORMAT ".%09" G_GINT64_FORMAT - ", response-type %d%s%s)", - data->seq_number, - timeout < 0 ? "-" : "", - (timeout < 0 ? -timeout : timeout) / NM_UTILS_NSEC_PER_SEC, - (timeout < 0 ? -timeout : timeout) % NM_UTILS_NSEC_PER_SEC, - (int) data->response_type, - data->seq_result ? ", " : "", - data->seq_result - ? wait_for_nl_response_to_string(data->seq_result, NULL, 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 gboolean -delayed_action_refresh_all_in_progress(NMPlatform *platform, DelayedActionType action_type) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - RefreshAllType refresh_all_type; - - nm_assert(nm_utils_is_power_of_two(action_type)); - nm_assert(NM_FLAGS_ANY(action_type, DELAYED_ACTION_TYPE_REFRESH_ALL)); - nm_assert(!NM_FLAGS_ANY(action_type, ~DELAYED_ACTION_TYPE_REFRESH_ALL)); - - if (NM_FLAGS_ANY(priv->delayed_action.flags, action_type)) - return TRUE; - - refresh_all_type = delayed_action_type_to_refresh_all_type(action_type); - return (priv->delayed_action.refresh_all_in_progress[refresh_all_type] > 0); -} - -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; - - 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"); - - if (priv->delayed_action.list_wait_for_nl_response->len <= 1) - priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE; - if (data->out_seq_result) - *data->out_seq_result = seq_result; - switch (data->response_type) { - case DELAYED_ACTION_RESPONSE_TYPE_VOID: - break; - case DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS: - if (data->response.out_refresh_all_in_progress) { - nm_assert(*data->response.out_refresh_all_in_progress > 0); - *data->response.out_refresh_all_in_progress -= 1; - data->response.out_refresh_all_in_progress = NULL; - } - break; - case DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET: - if (data->response.out_route_get) { - nm_assert(!*data->response.out_route_get); - data->response.out_route_get = NULL; - } - break; - } - - g_array_remove_index_fast(priv->delayed_action.list_wait_for_nl_response, idx); -} - -static void -delayed_action_wait_for_nl_response_complete_check(NMPlatform * platform, - WaitForNlResponseResult force_result, - guint32 * out_next_seq_number, - gint64 * out_next_timeout_abs_ns, - gint64 * p_now_ns) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - guint i; - guint32 next_seq_number = 0; - gint64 next_timeout_abs_ns = 0; - int now_ns = 0; - - for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len;) { - const DelayedActionWaitForNlResponseData *data = - &g_array_index(priv->delayed_action.list_wait_for_nl_response, - DelayedActionWaitForNlResponseData, - i); - - if (data->seq_result) - delayed_action_wait_for_nl_response_complete(platform, i, data->seq_result); - else if (p_now_ns - && ((now_ns ?: (now_ns = nm_utils_get_monotonic_timestamp_nsec())) - >= data->timeout_abs_ns)) { - /* the caller can optionally check for timeout by providing a p_now_ns argument. */ - delayed_action_wait_for_nl_response_complete( - platform, - i, - WAIT_FOR_NL_RESPONSE_RESULT_FAILED_TIMEOUT); - } else if (force_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN) - delayed_action_wait_for_nl_response_complete(platform, i, force_result); - else { - if (next_seq_number == 0 || next_timeout_abs_ns > data->timeout_abs_ns) { - next_seq_number = data->seq_number; - next_timeout_abs_ns = data->timeout_abs_ns; - } - i++; - } - } - - if (force_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN) { - 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); - } - - NM_SET_OUT(out_next_seq_number, next_seq_number); - NM_SET_OUT(out_next_timeout_abs_ns, next_timeout_abs_ns); - NM_SET_OUT(p_now_ns, now_ns); -} - -static void -delayed_action_wait_for_nl_response_complete_all(NMPlatform * platform, - WaitForNlResponseResult fallback_result) -{ - delayed_action_wait_for_nl_response_complete_check(platform, fallback_result, NULL, NULL, NULL); -} - -/*****************************************************************************/ - -static void -delayed_action_handle_MASTER_CONNECTED(NMPlatform *platform, int master_ifindex) -{ - nm_auto_nmpobj const NMPObject *obj_old = NULL; - nm_auto_nmpobj const NMPObject *obj_new = NULL; - NMPCacheOpsType cache_op; - - cache_op = nmp_cache_update_link_master_connected(nm_platform_get_cache(platform), - master_ifindex, - &obj_old, - &obj_new); - if (cache_op == NMP_CACHE_OPS_UNCHANGED) - return; - cache_on_change(platform, cache_op, obj_old, obj_new); - nm_platform_cache_update_emit_signal(platform, cache_op, obj_old, obj_new); -} - -static void -delayed_action_handle_REFRESH_LINK(NMPlatform *platform, int ifindex) -{ - do_request_link_no_delayed_actions(platform, ifindex, NULL); -} - -static void -delayed_action_handle_REFRESH_ALL(NMPlatform *platform, DelayedActionType flags) -{ - do_request_all_no_delayed_actions(platform, flags); -} - -static void -delayed_action_handle_READ_NETLINK(NMPlatform *platform) -{ - 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 -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) - return FALSE; - - /* First process DELAYED_ACTION_TYPE_MASTER_CONNECTED actions. - * This type of action is entirely cache-internal and is here to resolve a - * cache inconsistency. It should be fixed right away. */ - if (NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_MASTER_CONNECTED)) { - nm_assert(priv->delayed_action.list_master_connected->len > 0); - - user_data = priv->delayed_action.list_master_connected->pdata[0]; - g_ptr_array_remove_index_fast(priv->delayed_action.list_master_connected, 0); - if (priv->delayed_action.list_master_connected->len == 0) - priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_MASTER_CONNECTED; - nm_assert(_nm_utils_ptrarray_find_first( - (gconstpointer *) priv->delayed_action.list_master_connected->pdata, - priv->delayed_action.list_master_connected->len, - user_data) - < 0); - - _LOGt_delayed_action(DELAYED_ACTION_TYPE_MASTER_CONNECTED, user_data, "handle"); - delayed_action_handle_MASTER_CONNECTED(platform, GPOINTER_TO_INT(user_data)); - return TRUE; - } - nm_assert(priv->delayed_action.list_master_connected->len == 0); - - /* Next we prefer read-netlink, because the buffer size is limited and we want to process events - * from netlink early. */ - if (NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_READ_NETLINK)) { - _LOGt_delayed_action(DELAYED_ACTION_TYPE_READ_NETLINK, NULL, "handle"); - priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_READ_NETLINK; - delayed_action_handle_READ_NETLINK(platform); - return TRUE; - } - - if (NM_FLAGS_ANY(priv->delayed_action.flags, DELAYED_ACTION_TYPE_REFRESH_ALL)) { - DelayedActionType flags, iflags; - - flags = priv->delayed_action.flags & DELAYED_ACTION_TYPE_REFRESH_ALL; - - priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_REFRESH_ALL; - - if (_LOGt_ENABLED()) { - FOR_EACH_DELAYED_ACTION(iflags, flags) - _LOGt_delayed_action(iflags, NULL, "handle"); - } - - delayed_action_handle_REFRESH_ALL(platform, flags); - return TRUE; - } - - 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( - (gconstpointer *) 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"); - - delayed_action_handle_REFRESH_LINK(platform, GPOINTER_TO_INT(user_data)); - - 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 -delayed_action_handle_all(NMPlatform *platform, gboolean read_netlink) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - gboolean any = FALSE; - - 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--; - - cache_prune_all(platform); - - return any; -} - -static void -delayed_action_schedule(NMPlatform *platform, DelayedActionType action_type, gpointer user_data) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - DelayedActionType iflags; - - nm_assert(action_type != DELAYED_ACTION_TYPE_NONE); - - switch (action_type) { - case DELAYED_ACTION_TYPE_REFRESH_LINK: - if (_nm_utils_ptrarray_find_first( - (gconstpointer *) 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); - break; - case DELAYED_ACTION_TYPE_MASTER_CONNECTED: - if (_nm_utils_ptrarray_find_first( - (gconstpointer *) 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); - 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; - - if (_LOGt_ENABLED()) { - FOR_EACH_DELAYED_ACTION(iflags, action_type) - _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, - char ** out_errmsg, - DelayedActionWaitForNlResponseType response_type, - gpointer response_out_data) -{ - DelayedActionWaitForNlResponseData data = { - .seq_number = seq_number, - .timeout_abs_ns = - nm_utils_get_monotonic_timestamp_nsec() + (200 * (NM_UTILS_NSEC_PER_SEC / 1000)), - .out_seq_result = out_seq_result, - .out_errmsg = out_errmsg, - .response_type = response_type, - .response.out_data = response_out_data, - }; - - delayed_action_schedule(platform, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE, &data); -} - -/*****************************************************************************/ - -static void -cache_prune_one_type(NMPlatform *platform, const NMPLookup *lookup) -{ - NMDedupMultiIter iter; - const NMPObject *obj; - NMPCacheOpsType cache_op; - NMPCache * cache = nm_platform_get_cache(platform); - - nm_dedup_multi_iter_init(&iter, nmp_cache_lookup(cache, lookup)); - while (nm_dedup_multi_iter_next(&iter)) { - const NMDedupMultiEntry *main_entry; - - /* we only track the dirty flag for the OBJECT-TYPE index. That means, - * for other lookup types we need to check the dirty flag of the main-entry. */ - main_entry = nmp_cache_reresolve_main_entry(cache, iter.current, lookup); - if (!main_entry->dirty) - continue; - - obj = main_entry->obj; - - _LOGt("cache-prune: prune %s", - nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_ALL, NULL, 0)); - - { - nm_auto_nmpobj const NMPObject *obj_old = NULL; - - cache_op = nmp_cache_remove(cache, obj, TRUE, TRUE, &obj_old); - nm_assert(cache_op == NMP_CACHE_OPS_REMOVED); - cache_on_change(platform, cache_op, obj_old, NULL); - nm_platform_cache_update_emit_signal(platform, cache_op, obj_old, NULL); - } - } -} - -static void -cache_prune_all(NMPlatform *platform) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - RefreshAllType refresh_all_type; - - for (refresh_all_type = _REFRESH_ALL_TYPE_FIRST; refresh_all_type < _REFRESH_ALL_TYPE_NUM; - refresh_all_type++) { - NMPLookup lookup; - - if (priv->pruning[refresh_all_type] == 0) - continue; - priv->pruning[refresh_all_type] -= 1; - if (priv->pruning[refresh_all_type] > 0) - continue; - refresh_all_type_init_lookup(refresh_all_type, &lookup); - cache_prune_one_type(platform, &lookup); - } -} - -static void -cache_on_change(NMPlatform * platform, - NMPCacheOpsType cache_op, - const NMPObject *obj_old, - const NMPObject *obj_new) -{ - const NMPClass *klass; - char str_buf[sizeof(_nm_utils_to_string_buffer)]; - char str_buf2[sizeof(_nm_utils_to_string_buffer)]; - NMPCache * cache = nm_platform_get_cache(platform); - - ASSERT_nmp_cache_ops(cache, cache_op, obj_old, obj_new); - nm_assert(cache_op != NMP_CACHE_OPS_UNCHANGED); - - klass = obj_old ? NMP_OBJECT_GET_CLASS(obj_old) : NMP_OBJECT_GET_CLASS(obj_new); - - _LOGt( - "update-cache-%s: %s: %s%s%s", - klass->obj_type_name, - (cache_op == NMP_CACHE_OPS_UPDATED ? "UPDATE" - : (cache_op == NMP_CACHE_OPS_REMOVED ? "REMOVE" - : (cache_op == NMP_CACHE_OPS_ADDED) ? "ADD" - : "???")), - (cache_op != NMP_CACHE_OPS_ADDED - ? nmp_object_to_string(obj_old, NMP_OBJECT_TO_STRING_ALL, str_buf2, sizeof(str_buf2)) - : nmp_object_to_string(obj_new, NMP_OBJECT_TO_STRING_ALL, str_buf2, sizeof(str_buf2))), - (cache_op == NMP_CACHE_OPS_UPDATED) ? " -> " : "", - (cache_op == NMP_CACHE_OPS_UPDATED - ? nmp_object_to_string(obj_new, NMP_OBJECT_TO_STRING_ALL, str_buf, sizeof(str_buf)) - : "")); - - switch (klass->obj_type) { - case NMP_OBJECT_TYPE_LINK: - { - /* check whether changing a slave link can cause a master link (bridge or bond) to go up/down */ - if (obj_old - && nmp_cache_link_connected_needs_toggle_by_ifindex(cache, - obj_old->link.master, - obj_new, - obj_old)) - delayed_action_schedule(platform, - DELAYED_ACTION_TYPE_MASTER_CONNECTED, - GINT_TO_POINTER(obj_old->link.master)); - if (obj_new && (!obj_old || obj_old->link.master != obj_new->link.master) - && nmp_cache_link_connected_needs_toggle_by_ifindex(cache, - obj_new->link.master, - obj_new, - obj_old)) - delayed_action_schedule(platform, - DELAYED_ACTION_TYPE_MASTER_CONNECTED, - GINT_TO_POINTER(obj_new->link.master)); - } - { - /* check whether we are about to change a master link that needs toggling connected state. */ - if (obj_new /* <-- nonsensical, make coverity happy */ - && nmp_cache_link_connected_needs_toggle(cache, obj_new, obj_new, obj_old)) - delayed_action_schedule(platform, - DELAYED_ACTION_TYPE_MASTER_CONNECTED, - GINT_TO_POINTER(obj_new->link.ifindex)); - } - { - int ifindex = 0; - - /* if we remove a link (from netlink), we must refresh the addresses, routes, qdiscs and tfilters */ - if (cache_op == NMP_CACHE_OPS_REMOVED - && obj_old /* <-- nonsensical, make coverity happy */) - ifindex = obj_old->link.ifindex; - else if (cache_op == NMP_CACHE_OPS_UPDATED && obj_old - && obj_new /* <-- nonsensical, make coverity happy */ - && !obj_new->_link.netlink.is_in_netlink - && obj_new->_link.netlink.is_in_netlink - != obj_old->_link.netlink.is_in_netlink) - ifindex = obj_new->link.ifindex; - - if (ifindex > 0) { - delayed_action_schedule(platform, - 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 - | DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL - | DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS - | DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, - NULL); - } - } - { - int ifindex = -1; - - /* 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 - * (https://bugzilla.redhat.com/show_bug.cgi?id=1262908). */ - - if (cache_op == NMP_CACHE_OPS_REMOVED - && obj_old /* <-- nonsensical, make coverity happy */ - && obj_old->_link.netlink.is_in_netlink) - ifindex = obj_old->link.ifindex; - else if (cache_op == NMP_CACHE_OPS_UPDATED && obj_old - && obj_new /* <-- nonsensical, make coverity happy */ - && obj_old->_link.netlink.is_in_netlink - && !obj_new->_link.netlink.is_in_netlink) - ifindex = obj_new->link.ifindex; - - if (ifindex > 0) { - NMPLookup lookup; - NMDedupMultiIter iter; - const NMPlatformLink *l; - - nmp_lookup_init_obj_type(&lookup, NMP_OBJECT_TYPE_LINK); - nmp_cache_iter_for_each_link (&iter, nmp_cache_lookup(cache, &lookup), &l) { - if (l->parent == ifindex) - delayed_action_schedule(platform, - DELAYED_ACTION_TYPE_REFRESH_LINK, - GINT_TO_POINTER(l->ifindex)); - } - } - } - { - /* if a link goes down, we must refresh routes */ - if (cache_op == NMP_CACHE_OPS_UPDATED && obj_old - && obj_new /* <-- nonsensical, make coverity happy */ - && obj_old->_link.netlink.is_in_netlink && obj_new->_link.netlink.is_in_netlink - && ((NM_FLAGS_HAS(obj_old->link.n_ifi_flags, IFF_UP) - && !NM_FLAGS_HAS(obj_new->link.n_ifi_flags, IFF_UP)) - || (NM_FLAGS_HAS(obj_old->link.n_ifi_flags, IFF_LOWER_UP) - && !NM_FLAGS_HAS(obj_new->link.n_ifi_flags, IFF_LOWER_UP)))) { - /* FIXME: I suspect that IFF_LOWER_UP must not be considered, and I - * think kernel does send RTM_DELROUTE events for IPv6 routes, so - * we might not need to refresh IPv6 routes. */ - delayed_action_schedule(platform, - DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES - | DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, - NULL); - } - } - if (NM_IN_SET(cache_op, NMP_CACHE_OPS_ADDED, NMP_CACHE_OPS_UPDATED) - && (obj_new && obj_new->_link.netlink.is_in_netlink) - && (!obj_old || !obj_old->_link.netlink.is_in_netlink)) { - gboolean re_request_link = FALSE; - const NMPlatformLnkTun *lnk_tun; - - if (!obj_new->_link.netlink.lnk - && NM_IN_SET(obj_new->link.type, - NM_LINK_TYPE_GRE, - NM_LINK_TYPE_GRETAP, - NM_LINK_TYPE_IP6TNL, - NM_LINK_TYPE_IP6GRE, - NM_LINK_TYPE_IP6GRETAP, - NM_LINK_TYPE_INFINIBAND, - NM_LINK_TYPE_MACVLAN, - NM_LINK_TYPE_MACVLAN, - NM_LINK_TYPE_SIT, - NM_LINK_TYPE_TUN, - NM_LINK_TYPE_VLAN, - NM_LINK_TYPE_VXLAN)) { - /* 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 */ - re_request_link = TRUE; - } else if (obj_new->link.type == NM_LINK_TYPE_TUN && obj_new->_link.netlink.lnk - && (lnk_tun = &(obj_new->_link.netlink.lnk)->lnk_tun) && !lnk_tun->persist - && lnk_tun->pi && !lnk_tun->vnet_hdr && !lnk_tun->multi_queue - && !lnk_tun->owner_valid && !lnk_tun->group_valid) { - /* kernel has/had a know issue that the first notification for TUN device would - * be sent with invalid parameters. The message looks like that kind, so refetch - * it. */ - re_request_link = TRUE; - } else if (obj_new->link.type == NM_LINK_TYPE_VETH && obj_new->link.parent == 0) { - /* the initial notification when adding a veth pair can lack the parent/IFLA_LINK - * (https://bugzilla.redhat.com/show_bug.cgi?id=1285827). - * Request it again. */ - re_request_link = TRUE; - } else if (obj_new->link.type == NM_LINK_TYPE_ETHERNET - && obj_new->link.l_address.len == 0) { - /* Due to a kernel bug, we sometimes receive spurious NEWLINK - * messages after a wifi interface has disappeared. Since the - * link is not present anymore we can't determine its type and - * thus it will show up as a Ethernet one, with no address - * specified. Request the link again to check if it really - * exists. https://bugzilla.redhat.com/show_bug.cgi?id=1302037 - */ - re_request_link = TRUE; - } - if (re_request_link) { - delayed_action_schedule(platform, - DELAYED_ACTION_TYPE_REFRESH_LINK, - GINT_TO_POINTER(obj_new->link.ifindex)); - } - } - { - /* on enslave/release, we also refresh the master. */ - int ifindex1 = 0, ifindex2 = 0; - gboolean changed_master, changed_connected; - - changed_master = - (obj_new && obj_new->_link.netlink.is_in_netlink && obj_new->link.master > 0 - ? obj_new->link.master - : 0) - != (obj_old && obj_old->_link.netlink.is_in_netlink && obj_old->link.master > 0 - ? obj_old->link.master - : 0); - changed_connected = (obj_new && obj_new->_link.netlink.is_in_netlink - ? NM_FLAGS_HAS(obj_new->link.n_ifi_flags, IFF_LOWER_UP) - : 2) - != (obj_old && obj_old->_link.netlink.is_in_netlink - ? NM_FLAGS_HAS(obj_old->link.n_ifi_flags, IFF_LOWER_UP) - : 2); - - if (changed_master || changed_connected) { - ifindex1 = - (obj_old && obj_old->_link.netlink.is_in_netlink && obj_old->link.master > 0) - ? obj_old->link.master - : 0; - ifindex2 = - (obj_new && obj_new->_link.netlink.is_in_netlink && obj_new->link.master > 0) - ? obj_new->link.master - : 0; - - if (ifindex1 > 0) - delayed_action_schedule(platform, - DELAYED_ACTION_TYPE_REFRESH_LINK, - GINT_TO_POINTER(ifindex1)); - if (ifindex2 > 0 && ifindex1 != ifindex2) - delayed_action_schedule(platform, - DELAYED_ACTION_TYPE_REFRESH_LINK, - GINT_TO_POINTER(ifindex2)); - } - } - break; - case NMP_OBJECT_TYPE_IP4_ADDRESS: - case NMP_OBJECT_TYPE_IP6_ADDRESS: - { - /* Address deletion is sometimes accompanied by route deletion. We need to - * check all routes belonging to the same interface. */ - if (cache_op == NMP_CACHE_OPS_REMOVED) { - delayed_action_schedule(platform, - (klass->obj_type == NMP_OBJECT_TYPE_IP4_ADDRESS) - ? DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES - : DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, - NULL); - } - } break; - default: - break; - } -} - -/*****************************************************************************/ - -static guint32 -_nlh_seq_next_get(NMLinuxPlatformPrivate *priv) -{ - /* generate a new sequence number, but never return zero. - * Wrapping numbers are not a problem, because we don't rely - * on strictly increasing sequence numbers. */ - return (++priv->nlh_seq_next) ?: (++priv->nlh_seq_next); -} - -/** - * _nl_send_nlmsghdr: - * @platform: - * @nlhdr: - * @out_seq_result: - * @response_type: - * @response_out_data: - * - * Returns: 0 on success or a negative errno. - */ -static int -_nl_send_nlmsghdr(NMPlatform * platform, - struct nlmsghdr * nlhdr, - WaitForNlResponseResult * out_seq_result, - char ** out_errmsg, - DelayedActionWaitForNlResponseType response_type, - gpointer response_out_data) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - guint32 seq; - int errsv; - - nm_assert(nlhdr); - - seq = _nlh_seq_next_get(priv); - nlhdr->nlmsg_seq = seq; - - { - struct sockaddr_nl nladdr = { - .nl_family = AF_NETLINK, - }; - struct iovec iov = {.iov_base = nlhdr, .iov_len = nlhdr->nlmsg_len}; - struct msghdr msg = { - .msg_name = &nladdr, - .msg_namelen = sizeof(nladdr), - .msg_iov = &iov, - .msg_iovlen = 1, - }; - int try_count; - - if (!nlhdr->nlmsg_pid) - nlhdr->nlmsg_pid = nl_socket_get_local_port(priv->nlh); - nlhdr->nlmsg_flags |= (NLM_F_REQUEST | NLM_F_ACK); - - try_count = 0; -again: - errsv = sendmsg(nl_socket_get_fd(priv->nlh), &msg, 0); - if (errsv < 0) { - errsv = errno; - if (errsv == EINTR && try_count++ < 100) - goto again; - _LOGD("netlink: nl-send-nlmsghdr: failed sending message: %s (%d)", - nm_strerror_native(errsv), - errsv); - return -nm_errno_from_native(errsv); - } - } - - delayed_action_schedule_WAIT_FOR_NL_RESPONSE(platform, - seq, - out_seq_result, - out_errmsg, - response_type, - response_out_data); - return 0; -} - -/** - * _nl_send_nlmsg: - * @platform: - * @nlmsg: - * @out_seq_result: - * @response_type: - * @response_out_data: - * - * Returns: 0 on success, or a negative libnl3 error code (beware, it's not an errno). - */ -static int -_nl_send_nlmsg(NMPlatform * platform, - struct nl_msg * nlmsg, - WaitForNlResponseResult * out_seq_result, - char ** out_errmsg, - DelayedActionWaitForNlResponseType response_type, - gpointer response_out_data) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - struct nlmsghdr * nlhdr; - guint32 seq; - int nle; - - nlhdr = nlmsg_hdr(nlmsg); - seq = _nlh_seq_next_get(priv); - nlhdr->nlmsg_seq = seq; - - nle = nl_send_auto(priv->nlh, nlmsg); - if (nle < 0) { - _LOGD("netlink: nl-send-nlmsg: failed sending message: %s (%d)", nm_strerror(nle), nle); - return nle; - } - - delayed_action_schedule_WAIT_FOR_NL_RESPONSE(platform, - seq, - out_seq_result, - out_errmsg, - response_type, - response_out_data); - return 0; -} - -static void -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; - int nle; - - if (name && !name[0]) - name = NULL; - - g_return_if_fail(ifindex > 0 || name); - - _LOGD("do-request-link: %d %s", ifindex, name ?: ""); - - if (ifindex > 0) { - const NMDedupMultiEntry *entry; - - entry = nmp_cache_lookup_entry_link(nm_platform_get_cache(platform), ifindex); - if (entry) { - priv->pruning[REFRESH_ALL_TYPE_LINKS] += 1; - nm_dedup_multi_entry_set_dirty(entry, TRUE); - } - } - - event_handler_read_netlink(platform, FALSE); - - nlmsg = _nl_msg_new_link(RTM_GETLINK, 0, ifindex, name); - if (nlmsg) { - nle = _nl_send_nlmsg(platform, nlmsg, NULL, NULL, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL); - if (nle < 0) { - _LOGE("do-request-link: %d %s: failed sending netlink request \"%s\" (%d)", - ifindex, - name ?: "", - nm_strerror(nle), - -nle); - return; - } - } -} - -static void -do_request_link(NMPlatform *platform, int ifindex, const char *name) -{ - do_request_link_no_delayed_actions(platform, ifindex, name); - delayed_action_handle_all(platform, FALSE); -} - -static struct nl_msg * -_nl_msg_new_dump(NMPObjectType obj_type, int preferred_addr_family) -{ - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - const NMPClass * klass; - - klass = nmp_class_from_type(obj_type); - - nm_assert(klass); - nm_assert(klass->rtm_gettype > 0); - - nlmsg = nlmsg_alloc_simple(klass->rtm_gettype, NLM_F_DUMP); - - if (klass->addr_family != AF_UNSPEC) { - /* if the class specifies a particular address family, then it is preferred. */ - nm_assert(NM_IN_SET(preferred_addr_family, AF_UNSPEC, klass->addr_family)); - preferred_addr_family = klass->addr_family; - } - - switch (klass->obj_type) { - case NMP_OBJECT_TYPE_QDISC: - case NMP_OBJECT_TYPE_TFILTER: - { - const struct tcmsg tcmsg = { - .tcm_family = preferred_addr_family, - }; - - if (nlmsg_append_struct(nlmsg, &tcmsg) < 0) - g_return_val_if_reached(NULL); - } break; - case NMP_OBJECT_TYPE_LINK: - case NMP_OBJECT_TYPE_IP4_ADDRESS: - case NMP_OBJECT_TYPE_IP6_ADDRESS: - case NMP_OBJECT_TYPE_IP4_ROUTE: - case NMP_OBJECT_TYPE_IP6_ROUTE: - case NMP_OBJECT_TYPE_ROUTING_RULE: - { - const struct rtgenmsg gmsg = { - .rtgen_family = preferred_addr_family, - }; - - if (nlmsg_append_struct(nlmsg, &gmsg) < 0) - g_return_val_if_reached(NULL); - } break; - default: - g_return_val_if_reached(NULL); - } - - return g_steal_pointer(&nlmsg); -} - -static void -do_request_all_no_delayed_actions(NMPlatform *platform, DelayedActionType action_type) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - DelayedActionType action_type_prune; - DelayedActionType iflags; - - nm_assert(!NM_FLAGS_ANY(action_type, ~DELAYED_ACTION_TYPE_REFRESH_ALL)); - action_type &= DELAYED_ACTION_TYPE_REFRESH_ALL; - - action_type_prune = action_type; - - /* calling nmp_cache_dirty_set_all_main() with a non-main lookup-index requires an extra - * cache lookup for every entry. - * - * Avoid that, by special casing routing-rules here. */ - if (NM_FLAGS_ALL(action_type_prune, DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL)) { - NMPLookup lookup; - - priv->pruning[REFRESH_ALL_TYPE_ROUTING_RULES_IP4] += 1; - priv->pruning[REFRESH_ALL_TYPE_ROUTING_RULES_IP6] += 1; - nmp_lookup_init_obj_type(&lookup, NMP_OBJECT_TYPE_ROUTING_RULE); - nmp_cache_dirty_set_all_main(nm_platform_get_cache(platform), &lookup); - action_type_prune &= ~DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL; - } - - FOR_EACH_DELAYED_ACTION(iflags, action_type_prune) - { - RefreshAllType refresh_all_type = delayed_action_type_to_refresh_all_type(iflags); - NMPLookup lookup; - - priv->pruning[refresh_all_type] += 1; - refresh_all_type_init_lookup(refresh_all_type, &lookup); - nmp_cache_dirty_set_all_main(nm_platform_get_cache(platform), &lookup); - } - - FOR_EACH_DELAYED_ACTION(iflags, action_type) - { - RefreshAllType refresh_all_type = delayed_action_type_to_refresh_all_type(iflags); - const RefreshAllInfo *refresh_all_info = refresh_all_type_get_info(refresh_all_type); - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - int * out_refresh_all_in_progress; - - out_refresh_all_in_progress = - &priv->delayed_action.refresh_all_in_progress[refresh_all_type]; - nm_assert(*out_refresh_all_in_progress >= 0); - *out_refresh_all_in_progress += 1; - - /* clear any delayed action that request a refresh of this object type. */ - priv->delayed_action.flags &= ~iflags; - _LOGt_delayed_action(iflags, NULL, "handle (do-request-all)"); - - if (refresh_all_type == REFRESH_ALL_TYPE_LINKS) { - nm_assert( - (priv->delayed_action.list_refresh_link->len > 0) - == NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_REFRESH_LINK)); - if (NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_REFRESH_LINK)) { - _LOGt_delayed_action(DELAYED_ACTION_TYPE_REFRESH_LINK, - NULL, - "clear (do-request-all)"); - priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_REFRESH_LINK; - g_ptr_array_set_size(priv->delayed_action.list_refresh_link, 0); - } - } - - event_handler_read_netlink(platform, FALSE); - - nlmsg = _nl_msg_new_dump(refresh_all_info->obj_type, refresh_all_info->addr_family); - if (!nlmsg) - goto next_after_fail; - - if (_nl_send_nlmsg(platform, - nlmsg, - NULL, - NULL, - DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS, - out_refresh_all_in_progress) - < 0) - goto next_after_fail; - - continue; - -next_after_fail: - nm_assert(*out_refresh_all_in_progress > 0); - *out_refresh_all_in_progress -= 1; - } -} - -static void -do_request_one_type_by_needle_object(NMPlatform *platform, const NMPObject *obj_needle) -{ - do_request_all_no_delayed_actions(platform, - delayed_action_refresh_from_needle_object(obj_needle)); - delayed_action_handle_all(platform, FALSE); -} - -static void -event_seq_check_refresh_all(NMPlatform *platform, guint32 seq_number) -{ - NMLinuxPlatformPrivate * priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - DelayedActionWaitForNlResponseData *data; - guint i; - - if (NM_IN_SET(seq_number, 0, priv->nlh_seq_last_seen)) - 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->response_type == DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS - && data->response.out_refresh_all_in_progress - && data->seq_number == priv->nlh_seq_last_seen) { - *data->response.out_refresh_all_in_progress -= 1; - data->response.out_refresh_all_in_progress = NULL; - break; - } - } - } - - priv->nlh_seq_last_seen = seq_number; -} - -static void -event_seq_check(NMPlatform * platform, - guint32 seq_number, - WaitForNlResponseResult seq_result, - const char * msg) -{ - NMLinuxPlatformPrivate * priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - DelayedActionWaitForNlResponseData *data; - guint i; - - 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 sequence 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; - if (data->out_errmsg && !*data->out_errmsg) - *data->out_errmsg = g_strdup(msg); - return; - } - } - } - -#if NM_MORE_LOGGING - if (seq_number != priv->nlh_seq_last_handled) - _LOGt("netlink: recvmsg: unwaited sequence number %u", seq_number); - priv->nlh_seq_last_handled = seq_number; -#endif -} - -static void -event_valid_msg(NMPlatform *platform, struct nl_msg *msg, gboolean handle_events) -{ - NMLinuxPlatformPrivate *priv; - nm_auto_nmpobj NMPObject *obj = NULL; - NMPCacheOpsType cache_op; - struct nlmsghdr * msghdr; - char buf_nlmsghdr[400]; - gboolean is_del = FALSE; - gboolean is_dump = FALSE; - NMPCache * cache = nm_platform_get_cache(platform); - - msghdr = nlmsg_hdr(msg); - - if (!_nm_platform_kernel_support_detected(NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS) - && msghdr->nlmsg_type == RTM_NEWADDR) { - /* IFA_FLAGS is set for IPv4 and IPv6 addresses. It was added first to IPv6, - * but if we encounter an IPv4 address with IFA_FLAGS, we surely have support. */ - if (nlmsg_valid_hdr(msghdr, sizeof(struct ifaddrmsg)) - && NM_IN_SET(((struct ifaddrmsg *) nlmsg_data(msghdr))->ifa_family, - AF_INET, - AF_INET6)) { - /* 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 for IPv6. They were added together in kernel 3.14, - * dated 30 March, 2014. - * - * For IPv4, IFA_F_NOPREFIXROUTE was added later, but there is no easy - * way to detect kernel support. */ - _nm_platform_kernel_support_init( - NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS, - !!nlmsg_find_attr(msghdr, sizeof(struct ifaddrmsg), IFA_FLAGS) ? 1 : -1); - } - } - - if (!handle_events) - return; - - if (NM_IN_SET(msghdr->nlmsg_type, - RTM_DELLINK, - RTM_DELADDR, - RTM_DELROUTE, - RTM_DELRULE, - RTM_DELQDISC, - RTM_DELTFILTER)) { - /* The event notifies about a deleted object. We don't need to initialize all - * fields of the object. */ - is_del = TRUE; - } - - obj = nmp_object_new_from_nl(platform, cache, msg, is_del); - if (!obj) { - _LOGT("event-notification: %s: ignore", - nl_nlmsghdr_to_str(msghdr, buf_nlmsghdr, sizeof(buf_nlmsghdr))); - return; - } - - if (!is_del - && NM_IN_SET(msghdr->nlmsg_type, - RTM_NEWADDR, - RTM_NEWLINK, - RTM_NEWROUTE, - RTM_NEWRULE, - RTM_NEWQDISC, - RTM_NEWTFILTER)) { - is_dump = - delayed_action_refresh_all_in_progress(platform, - delayed_action_refresh_from_needle_object(obj)); - } - - _LOGT("event-notification: %s%s: %s", - nl_nlmsghdr_to_str(msghdr, buf_nlmsghdr, sizeof(buf_nlmsghdr)), - is_dump ? ", in-dump" : "", - nmp_object_to_string(obj, - is_del ? NMP_OBJECT_TO_STRING_ID : NMP_OBJECT_TO_STRING_PUBLIC, - NULL, - 0)); - - { - nm_auto_nmpobj const NMPObject *obj_old = NULL; - nm_auto_nmpobj const NMPObject *obj_new = NULL; - - switch (msghdr->nlmsg_type) { - case RTM_GETLINK: - case RTM_NEWADDR: - case RTM_NEWLINK: - case RTM_NEWQDISC: - case RTM_NEWRULE: - case RTM_NEWTFILTER: - cache_op = nmp_cache_update_netlink(cache, obj, is_dump, &obj_old, &obj_new); - if (cache_op != NMP_CACHE_OPS_UNCHANGED) { - cache_on_change(platform, cache_op, obj_old, obj_new); - nm_platform_cache_update_emit_signal(platform, cache_op, obj_old, obj_new); - } - break; - - case RTM_NEWROUTE: - { - nm_auto_nmpobj const NMPObject *obj_replace = NULL; - gboolean resync_required = FALSE; - gboolean only_dirty = FALSE; - gboolean is_ipv6; - - /* IPv4 routes that are a response to RTM_GETROUTE must have - * the cloned flag while IPv6 routes don't have to. */ - is_ipv6 = NMP_OBJECT_GET_TYPE(obj) == NMP_OBJECT_TYPE_IP6_ROUTE; - if (is_ipv6 || NM_FLAGS_HAS(obj->ip_route.r_rtm_flags, RTM_F_CLONED)) { - nm_assert(is_ipv6 || !nmp_object_is_alive(obj)); - priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - if (NM_FLAGS_HAS(priv->delayed_action.flags, - DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) { - guint i; - - 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++) { - DelayedActionWaitForNlResponseData *data = - &g_array_index(priv->delayed_action.list_wait_for_nl_response, - DelayedActionWaitForNlResponseData, - i); - - if (data->response_type == DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET - && data->response.out_route_get) { - nm_assert(!*data->response.out_route_get); - if (data->seq_number == nlmsg_hdr(msg)->nlmsg_seq) { - *data->response.out_route_get = nmp_object_clone(obj, FALSE); - data->response.out_route_get = NULL; - break; - } - } - } - } - } - - cache_op = nmp_cache_update_netlink_route(cache, - obj, - is_dump, - msghdr->nlmsg_flags, - &obj_old, - &obj_new, - &obj_replace, - &resync_required); - if (cache_op != NMP_CACHE_OPS_UNCHANGED) { - if (obj_replace) { - const NMDedupMultiEntry *entry_replace; - - /* we found an object that is to be replaced by the RTM_NEWROUTE message. - * While we invoke the signal, the platform cache might change and invalidate - * the findings. Mitigate that (for the most part), by marking the entry as - * dirty and only delete @obj_replace if it is still dirty afterwards. - * - * Yes, there is a tiny tiny chance for still getting it wrong. But in practice, - * the signal handlers do not cause to call the platform again, so the cache - * is not really changing. -- if they would, it would anyway be dangerous to overflow - * the stack and it's not ensured that the processing of netlink messages is - * reentrant (maybe it is). - */ - entry_replace = nmp_cache_lookup_entry(cache, obj_replace); - nm_assert(entry_replace && entry_replace->obj == obj_replace); - nm_dedup_multi_entry_set_dirty(entry_replace, TRUE); - only_dirty = TRUE; - } - cache_on_change(platform, cache_op, obj_old, obj_new); - nm_platform_cache_update_emit_signal(platform, cache_op, obj_old, obj_new); - } - - if (obj_replace) { - /* the RTM_NEWROUTE message indicates that another route was replaced. - * Remove it now. */ - cache_op = nmp_cache_remove(cache, obj_replace, TRUE, only_dirty, NULL); - if (cache_op != NMP_CACHE_OPS_UNCHANGED) { - nm_assert(cache_op == NMP_CACHE_OPS_REMOVED); - cache_on_change(platform, cache_op, obj_replace, NULL); - nm_platform_cache_update_emit_signal(platform, cache_op, obj_replace, NULL); - } - } - - if (resync_required) { - /* we'd like to avoid such resyncs as they are expensive and we should only rely on the - * netlink events. This needs investigation. */ - _LOGT("schedule resync of routes after RTM_NEWROUTE"); - delayed_action_schedule(platform, - delayed_action_refresh_from_needle_object(obj), - NULL); - } - break; - } - - case RTM_DELADDR: - case RTM_DELLINK: - case RTM_DELQDISC: - case RTM_DELROUTE: - case RTM_DELRULE: - case RTM_DELTFILTER: - cache_op = nmp_cache_remove_netlink(cache, obj, &obj_old, &obj_new); - if (cache_op != NMP_CACHE_OPS_UNCHANGED) { - cache_on_change(platform, cache_op, obj_old, obj_new); - nm_platform_cache_update_emit_signal(platform, cache_op, obj_old, obj_new); - } - break; - default: - break; - } - } -} - -/*****************************************************************************/ - -static int -do_add_link_with_lookup(NMPlatform * platform, - NMLinkType link_type, - const char * name, - struct nl_msg * nlmsg, - const NMPlatformLink **out_link) -{ - const NMPObject * obj = NULL; - WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char * errmsg = NULL; - int nle; - char s_buf[256]; - NMPCache * cache = nm_platform_get_cache(platform); - - event_handler_read_netlink(platform, FALSE); - - nle = _nl_send_nlmsg(platform, - nlmsg, - &seq_result, - &errmsg, - DELAYED_ACTION_RESPONSE_TYPE_VOID, - NULL); - if (nle < 0) { - _LOGE("do-add-link[%s/%s]: failed sending netlink request \"%s\" (%d)", - name, - nm_link_type_to_string(link_type), - nm_strerror(nle), - -nle); - NM_SET_OUT(out_link, NULL); - return nle; - } - - delayed_action_handle_all(platform, FALSE); - - nm_assert(seq_result); - - _NMLOG(seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK ? LOGL_DEBUG : LOGL_WARN, - "do-add-link[%s/%s]: %s", - name, - nm_link_type_to_string(link_type), - wait_for_nl_response_to_string(seq_result, errmsg, s_buf, sizeof(s_buf))); - - if (out_link) { - obj = nmp_cache_lookup_link_full(cache, 0, name, FALSE, link_type, NULL, NULL); - *out_link = NMP_OBJECT_CAST_LINK(obj); - } - - return wait_for_nl_response_to_nmerr(seq_result); -} - -static int -do_add_addrroute(NMPlatform * platform, - const NMPObject *obj_id, - struct nl_msg * nlmsg, - gboolean suppress_netlink_failure) -{ - WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char * errmsg = NULL; - int nle; - char s_buf[256]; - - 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(platform, FALSE); - - nle = _nl_send_nlmsg(platform, - nlmsg, - &seq_result, - &errmsg, - DELAYED_ACTION_RESPONSE_TYPE_VOID, - NULL); - if (nle < 0) { - _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), - nm_strerror(nle), - -nle); - return -NME_PL_NETLINK; - } - - delayed_action_handle_all(platform, FALSE); - - nm_assert(seq_result); - - _NMLOG((seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK - || (suppress_netlink_failure && seq_result < 0)) - ? LOGL_DEBUG - : LOGL_WARN, - "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, errmsg, s_buf, sizeof(s_buf))); - - if (NMP_OBJECT_GET_TYPE(obj_id) == NMP_OBJECT_TYPE_IP6_ADDRESS) { - /* 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. - * - * rh#1484434 */ - if (!nmp_cache_lookup_obj(nm_platform_get_cache(platform), obj_id)) - do_request_one_type_by_needle_object(platform, obj_id); - } - - return wait_for_nl_response_to_nmerr(seq_result); -} - -static gboolean -do_delete_object(NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *nlmsg) -{ - WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char * errmsg = NULL; - int nle; - char s_buf[256]; - gboolean success; - const char * log_detail = ""; - - event_handler_read_netlink(platform, FALSE); - - nle = _nl_send_nlmsg(platform, - nlmsg, - &seq_result, - &errmsg, - DELAYED_ACTION_RESPONSE_TYPE_VOID, - NULL); - 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), - nm_strerror(nle), - -nle); - return FALSE; - } - - delayed_action_handle_all(platform, FALSE); - - nm_assert(seq_result); - - success = TRUE; - 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 - success = FALSE; - - _NMLOG(success ? LOGL_DEBUG : LOGL_WARN, - "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, errmsg, s_buf, sizeof(s_buf)), - log_detail); - - if (NM_IN_SET(NMP_OBJECT_GET_TYPE(obj_id), - NMP_OBJECT_TYPE_IP6_ADDRESS, - NMP_OBJECT_TYPE_QDISC, - NMP_OBJECT_TYPE_TFILTER)) { - /* In rare cases, the object is still there after we receive 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. - * - * rh#1484434 */ - if (nmp_cache_lookup_obj(nm_platform_get_cache(platform), obj_id)) - do_request_one_type_by_needle_object(platform, obj_id); - } - - return success; -} - -static int -do_change_link(NMPlatform * platform, - ChangeLinkType change_link_type, - int ifindex, - struct nl_msg * nlmsg, - const ChangeLinkData *data) -{ - nm_auto_pop_netns NMPNetns *netns = NULL; - int nle; - WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char * errmsg = NULL; - char s_buf[256]; - int result = 0; - NMLogLevel log_level = LOGL_DEBUG; - const char * log_result = "failure"; - const char * log_detail = ""; - gs_free char * log_detail_free = NULL; - const NMPObject * obj_cache; - - if (!nm_platform_netns_push(platform, &netns)) { - log_level = LOGL_ERR; - log_detail = ", failure to change network namespace"; - goto out; - } - -retry: - nle = _nl_send_nlmsg(platform, - nlmsg, - &seq_result, - &errmsg, - DELAYED_ACTION_RESPONSE_TYPE_VOID, - NULL); - if (nle < 0) { - log_level = LOGL_ERR; - log_detail_free = - g_strdup_printf(", failure sending netlink request: %s (%d)", nm_strerror(nle), -nle); - log_detail = log_detail_free; - goto out; - } - - /* 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)); - - 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 = -NME_PL_NO_FIRMWARE; - } else if (NM_IN_SET(-((int) seq_result), ERANGE) - && change_link_type == CHANGE_LINK_TYPE_SET_MTU) { - log_detail = ", setting MTU to requested size is not possible"; - result = -NME_PL_CANT_SET_MTU; - } else if (NM_IN_SET(-((int) seq_result), ENFILE) - && change_link_type == CHANGE_LINK_TYPE_SET_ADDRESS - && (obj_cache = nmp_cache_lookup_link(nm_platform_get_cache(platform), ifindex)) - && obj_cache->link.l_address.len == data->set_address.length - && memcmp(obj_cache->link.l_address.data, - data->set_address.address, - data->set_address.length) - == 0) { - /* workaround ENFILE which may be wrongly returned (bgo #770456). - * If the MAC address is as expected, assume success? */ - log_result = "success"; - log_detail = " (assume success changing address)"; - result = 0; - } else if (NM_IN_SET(-((int) seq_result), ENODEV)) { - log_level = LOGL_DEBUG; - result = -NME_PL_NOT_FOUND; - } else if (-((int) seq_result) == EAFNOSUPPORT) { - log_level = LOGL_DEBUG; - result = -NME_PL_OPNOTSUPP; - } else { - log_level = LOGL_WARN; - result = -NME_UNSPEC; - } - -out: - _NMLOG(log_level, - "do-change-link[%d]: %s changing link: %s%s", - ifindex, - log_result, - wait_for_nl_response_to_string(seq_result, errmsg, s_buf, sizeof(s_buf)), - log_detail); - return result; -} - -static int -link_add(NMPlatform * platform, - NMLinkType type, - const char * name, - int parent, - const void * address, - size_t address_len, - guint32 mtu, - gconstpointer extra_data, - const NMPlatformLink **out_link) -{ - 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 - * or automatically in response to creating a bond master, it will also - * create a 'bond0' interface. Since the bond we're about to create may - * or may not be named 'bond0' prevent potential confusion about a bond - * that the user didn't want by telling the bonding module not to create - * bond0 automatically. - */ - if (!g_file_test("/sys/class/net/bonding_masters", G_FILE_TEST_EXISTS)) - (void) nm_utils_modprobe(NULL, TRUE, "bonding", "max_bonds=0", NULL); - } - - nlmsg = _nl_msg_new_link(RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL, 0, name); - if (!nlmsg) - return -NME_UNSPEC; - - if (parent > 0) - NLA_PUT_U32(nlmsg, IFLA_LINK, parent); - - if (address && address_len) - NLA_PUT(nlmsg, IFLA_ADDRESS, address_len, address); - - if (mtu) - NLA_PUT_U32(nlmsg, IFLA_MTU, mtu); - - if (!_nl_msg_new_link_set_linkinfo(nlmsg, type, extra_data)) - return -NME_UNSPEC; - - return do_add_link_with_lookup(platform, type, name, nlmsg, out_link); -nla_put_failure: - g_return_val_if_reached(-NME_BUG); -} - -static gboolean -link_delete(NMPlatform *platform, int ifindex) -{ - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - NMPObject obj_id; - const NMPObject * obj; - - obj = nmp_cache_lookup_link(nm_platform_get_cache(platform), ifindex); - if (!obj || !obj->_link.netlink.is_in_netlink) - return FALSE; - - nlmsg = _nl_msg_new_link(RTM_DELLINK, 0, ifindex, NULL); - - nmp_object_stackinit_id_link(&obj_id, ifindex); - return do_delete_object(platform, &obj_id, nlmsg); -} - -static gboolean -link_refresh(NMPlatform *platform, int ifindex) -{ - do_request_link(platform, ifindex, NULL); - return !!nm_platform_link_get_obj(platform, ifindex, TRUE); -} - -static gboolean -link_set_netns(NMPlatform *platform, int ifindex, int netns_fd) -{ - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - - nlmsg = _nl_msg_new_link(RTM_NEWLINK, 0, ifindex, NULL); - if (!nlmsg) - return FALSE; - - NLA_PUT(nlmsg, IFLA_NET_NS_FD, 4, &netns_fd); - return (do_change_link(platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) >= 0); - -nla_put_failure: - g_return_val_if_reached(FALSE); -} - -static int -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_full(RTM_NEWLINK, 0, ifindex, NULL, AF_UNSPEC, flags_mask, flags_set); - if (!nlmsg) - return -NME_UNSPEC; - return do_change_link(platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL); -} - -static gboolean -link_set_up(NMPlatform *platform, int ifindex, gboolean *out_no_firmware) -{ - int r; - - r = link_change_flags(platform, ifindex, IFF_UP, IFF_UP); - NM_SET_OUT(out_no_firmware, (r == -NME_PL_NO_FIRMWARE)); - return r >= 0; -} - -static gboolean -link_set_down(NMPlatform *platform, int ifindex) -{ - return (link_change_flags(platform, ifindex, IFF_UP, 0) >= 0); -} - -static gboolean -link_set_arp(NMPlatform *platform, int ifindex) -{ - return (link_change_flags(platform, ifindex, IFF_NOARP, 0) >= 0); -} - -static gboolean -link_set_noarp(NMPlatform *platform, int ifindex) -{ - return (link_change_flags(platform, ifindex, IFF_NOARP, IFF_NOARP) >= 0); -} - -static int -link_set_user_ipv6ll_enabled(NMPlatform *platform, int ifindex, gboolean enabled) -{ - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - guint8 mode = enabled ? NM_IN6_ADDR_GEN_MODE_NONE : NM_IN6_ADDR_GEN_MODE_EUI64; - - _LOGD("link: change %d: user-ipv6ll: set IPv6 address generation mode to %s", - ifindex, - nm_platform_link_inet6_addrgenmode2str(mode, NULL, 0)); - - if (!nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL)) { - _LOGD("link: change %d: user-ipv6ll: not supported", ifindex); - return -NME_PL_OPNOTSUPP; - } - - nlmsg = _nl_msg_new_link(RTM_NEWLINK, 0, ifindex, NULL); - if (!nlmsg || !_nl_msg_new_link_set_afspec(nlmsg, mode, NULL)) - g_return_val_if_reached(-NME_BUG); - - return do_change_link(platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL); -} - -static gboolean -link_set_token(NMPlatform *platform, int ifindex, NMUtilsIPv6IfaceId iid) -{ - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - _LOGD("link: change %d: token: set IPv6 address generation token to %s", - ifindex, - nm_utils_inet6_interface_identifier_to_token(iid, sbuf)); - - nlmsg = _nl_msg_new_link(RTM_NEWLINK, 0, ifindex, NULL); - if (!nlmsg || !_nl_msg_new_link_set_afspec(nlmsg, -1, &iid)) - g_return_val_if_reached(FALSE); - - return (do_change_link(platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) >= 0); -} - -static gboolean -link_supports_carrier_detect(NMPlatform *platform, int ifindex) -{ - nm_auto_pop_netns NMPNetns *netns = NULL; - - if (!nm_platform_netns_push(platform, &netns)) - return FALSE; - - /* We use netlink for the actual carrier detection, but netlink can't tell - * us whether the device actually supports carrier detection in the first - * place. We assume any device that does implements one of these two APIs. - */ - return nmp_utils_ethtool_supports_carrier_detect(ifindex) - || nmp_utils_mii_supports_carrier_detect(ifindex); -} - -static gboolean -link_supports_vlans(NMPlatform *platform, int ifindex) -{ - nm_auto_pop_netns NMPNetns *netns = NULL; - const NMPObject * obj; - - obj = nm_platform_link_get_obj(platform, ifindex, TRUE); - - /* Only ARPHRD_ETHER links can possibly support VLANs. */ - if (!obj || obj->link.arptype != ARPHRD_ETHER) - return FALSE; - - if (!nm_platform_netns_push(platform, &netns)) - return FALSE; - - return nmp_utils_ethtool_supports_vlans(ifindex); -} - -static gboolean -link_supports_sriov(NMPlatform *platform, int ifindex) -{ - nm_auto_pop_netns NMPNetns *netns = NULL; - nm_auto_close int dirfd = -1; - char ifname[IFNAMSIZ]; - int num = -1; - - if (!nm_platform_netns_push(platform, &netns)) - return FALSE; - - dirfd = nm_platform_sysctl_open_netdir(platform, ifindex, ifname); - if (dirfd < 0) - return FALSE; - - num = - nm_platform_sysctl_get_int32(platform, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, "device/sriov_numvfs"), - -1); - - return num != -1; -} - -static int -link_set_address(NMPlatform *platform, int ifindex, gconstpointer address, size_t length) -{ - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - const ChangeLinkData d = { - .set_address = - { - .address = address, - .length = length, - }, - }; - - if (!address || !length) - g_return_val_if_reached(-NME_BUG); - - nlmsg = _nl_msg_new_link(RTM_NEWLINK, 0, ifindex, NULL); - if (!nlmsg) - g_return_val_if_reached(-NME_BUG); - - NLA_PUT(nlmsg, IFLA_ADDRESS, length, address); - - return do_change_link(platform, CHANGE_LINK_TYPE_SET_ADDRESS, ifindex, nlmsg, &d); -nla_put_failure: - g_return_val_if_reached(-NME_BUG); -} - -static int -link_set_name(NMPlatform *platform, int ifindex, const char *name) -{ - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - - nlmsg = _nl_msg_new_link(RTM_NEWLINK, 0, ifindex, NULL); - if (!nlmsg) - g_return_val_if_reached(-NME_BUG); - - NLA_PUT(nlmsg, IFLA_IFNAME, strlen(name) + 1, name); - - return (do_change_link(platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) >= 0); -nla_put_failure: - g_return_val_if_reached(FALSE); -} - -static gboolean -link_get_permanent_address(NMPlatform *platform, int ifindex, guint8 *buf, size_t *length) -{ - nm_auto_pop_netns NMPNetns *netns = NULL; - - if (!nm_platform_netns_push(platform, &netns)) - return FALSE; - - return nmp_utils_ethtool_get_permanent_address(ifindex, buf, length); -} - -static int -link_set_mtu(NMPlatform *platform, int ifindex, guint32 mtu) -{ - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - - nlmsg = _nl_msg_new_link(RTM_NEWLINK, 0, ifindex, NULL); - if (!nlmsg) - return FALSE; - - NLA_PUT_U32(nlmsg, IFLA_MTU, mtu); - - return do_change_link(platform, CHANGE_LINK_TYPE_SET_MTU, ifindex, nlmsg, NULL); -nla_put_failure: - g_return_val_if_reached(FALSE); -} - -static void -sriov_idle_cb(gpointer user_data, GCancellable *cancellable) -{ - gs_unref_object NMPlatform *platform = NULL; - gs_free_error GError *cancelled_error = NULL; - gs_free_error GError * error = NULL; - NMPlatformAsyncCallback callback; - gpointer callback_data; - - g_cancellable_set_error_if_cancelled(cancellable, &cancelled_error); - nm_utils_user_data_unpack(user_data, &platform, &error, &callback, &callback_data); - callback(cancelled_error ?: error, callback_data); -} - -static void -link_set_sriov_params_async(NMPlatform * platform, - int ifindex, - guint num_vfs, - NMOptionBool autoprobe, - NMPlatformAsyncCallback callback, - gpointer data, - GCancellable * cancellable) -{ - nm_auto_pop_netns NMPNetns *netns = NULL; - gs_free_error GError *error = NULL; - nm_auto_close int dirfd = -1; - int current_autoprobe; - guint i, total; - gint64 current_num; - char ifname[IFNAMSIZ]; - gpointer packed; - const char * values[3]; - char buf[64]; - - g_return_if_fail(callback || !data); - g_return_if_fail(cancellable); - - if (!nm_platform_netns_push(platform, &netns)) { - g_set_error_literal(&error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "couldn't change namespace"); - goto out_idle; - } - - dirfd = nm_platform_sysctl_open_netdir(platform, ifindex, ifname); - if (!dirfd) { - g_set_error_literal(&error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "couldn't open netdir"); - goto out_idle; - } - - total = nm_platform_sysctl_get_int_checked( - platform, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, "device/sriov_totalvfs"), - 10, - 0, - G_MAXUINT, - 0); - if (!errno && num_vfs > total) { - _LOGW("link: %d only supports %u VFs (requested %u)", ifindex, total, num_vfs); - num_vfs = total; - } - - /* - * Take special care when setting new values: - * - don't touch anything if the right values are already set - * - to change the number of VFs or autoprobe we need to destroy existing VFs - * - the autoprobe setting is irrelevant when numvfs is zero - */ - current_num = nm_platform_sysctl_get_int_checked( - platform, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, "device/sriov_numvfs"), - 10, - 0, - G_MAXUINT, - -1); - current_autoprobe = nm_platform_sysctl_get_int_checked( - platform, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, "device/sriov_drivers_autoprobe"), - 10, - 0, - 1, - -1); - - if (current_autoprobe == -1 && errno == ENOENT) { - /* older kernel versions don't have this sysctl. Assume the value is - * "1". */ - current_autoprobe = 1; - } - - if (current_num == num_vfs - && (autoprobe == NM_OPTION_BOOL_DEFAULT || current_autoprobe == autoprobe)) - goto out_idle; - - if (NM_IN_SET(autoprobe, NM_OPTION_BOOL_TRUE, NM_OPTION_BOOL_FALSE) - && current_autoprobe != autoprobe - && !nm_platform_sysctl_set( - NM_PLATFORM_GET, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, "device/sriov_drivers_autoprobe"), - nm_sprintf_buf(buf, "%d", (int) autoprobe))) { - g_set_error(&error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "couldn't set SR-IOV drivers-autoprobe to %d: %s", - (int) autoprobe, - nm_strerror_native(errno)); - goto out_idle; - } - - if (current_num == 0 && num_vfs == 0) - goto out_idle; - - i = 0; - if (current_num != 0) - values[i++] = "0"; - if (num_vfs != 0) - values[i++] = nm_sprintf_bufa(32, "%u", num_vfs); - values[i++] = NULL; - - sysctl_set_async(platform, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, "device/sriov_numvfs"), - values, - callback, - data, - cancellable); - return; - -out_idle: - if (callback) { - packed = nm_utils_user_data_pack(g_object_ref(platform), - g_steal_pointer(&error), - callback, - data); - nm_utils_invoke_on_idle(cancellable, sriov_idle_cb, packed); - } -} - -static gboolean -link_set_sriov_vfs(NMPlatform *platform, int ifindex, const NMPlatformVF *const *vfs) -{ - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - struct nlattr * list, *info, *vlan_list; - guint i; - - nlmsg = _nl_msg_new_link(RTM_NEWLINK, 0, ifindex, NULL); - if (!nlmsg) - g_return_val_if_reached(-NME_BUG); - - if (!(list = nla_nest_start(nlmsg, IFLA_VFINFO_LIST))) - goto nla_put_failure; - - for (i = 0; vfs[i]; i++) { - const NMPlatformVF *vf = vfs[i]; - - if (!(info = nla_nest_start(nlmsg, IFLA_VF_INFO))) - goto nla_put_failure; - - if (vf->spoofchk >= 0) { - struct _ifla_vf_setting ivs = {0}; - - ivs.vf = vf->index; - ivs.setting = vf->spoofchk; - NLA_PUT(nlmsg, IFLA_VF_SPOOFCHK, sizeof(ivs), &ivs); - } - - if (vf->trust >= 0) { - struct _ifla_vf_setting ivs = {0}; - - ivs.vf = vf->index; - ivs.setting = vf->trust; - NLA_PUT(nlmsg, IFLA_VF_TRUST, sizeof(ivs), &ivs); - } - - if (vf->mac.len) { - struct ifla_vf_mac ivm = {0}; - - ivm.vf = vf->index; - memcpy(ivm.mac, vf->mac.data, vf->mac.len); - NLA_PUT(nlmsg, IFLA_VF_MAC, sizeof(ivm), &ivm); - } - - if (vf->min_tx_rate || vf->max_tx_rate) { - struct _ifla_vf_rate ivr = {0}; - - ivr.vf = vf->index; - ivr.min_tx_rate = vf->min_tx_rate; - ivr.max_tx_rate = vf->max_tx_rate; - NLA_PUT(nlmsg, IFLA_VF_RATE, sizeof(ivr), &ivr); - } - - /* Kernel only supports one VLAN per VF now. If this - * changes in the future, we need to figure out how to - * clear existing VLANs and set new ones in one message - * with the new API.*/ - if (vf->num_vlans > 1) { - _LOGW("multiple VLANs per VF are not supported at the moment"); - return FALSE; - } else { - struct _ifla_vf_vlan_info ivvi = {0}; - - if (!(vlan_list = nla_nest_start(nlmsg, IFLA_VF_VLAN_LIST))) - goto nla_put_failure; - - ivvi.vf = vf->index; - if (vf->num_vlans == 1) { - ivvi.vlan = vf->vlans[0].id; - ivvi.qos = vf->vlans[0].qos; - ivvi.vlan_proto = htons(vf->vlans[0].proto_ad ? ETH_P_8021AD : ETH_P_8021Q); - } else { - /* Clear existing VLAN */ - ivvi.vlan = 0; - ivvi.qos = 0; - ivvi.vlan_proto = htons(ETH_P_8021Q); - } - - NLA_PUT(nlmsg, IFLA_VF_VLAN_INFO, sizeof(ivvi), &ivvi); - nla_nest_end(nlmsg, vlan_list); - } - nla_nest_end(nlmsg, info); - } - nla_nest_end(nlmsg, list); - - return (do_change_link(platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) >= 0); -nla_put_failure: - g_return_val_if_reached(FALSE); -} - -static gboolean -link_set_bridge_vlans(NMPlatform * platform, - int ifindex, - gboolean on_master, - const NMPlatformBridgeVlan *const *vlans) -{ - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - struct nlattr * list; - struct bridge_vlan_info vinfo = {}; - guint i; - - nlmsg = - _nl_msg_new_link_full(vlans ? RTM_SETLINK : RTM_DELLINK, 0, ifindex, NULL, AF_BRIDGE, 0, 0); - if (!nlmsg) - g_return_val_if_reached(-NME_BUG); - - if (!(list = nla_nest_start(nlmsg, IFLA_AF_SPEC))) - goto nla_put_failure; - - NLA_PUT_U16(nlmsg, IFLA_BRIDGE_FLAGS, on_master ? BRIDGE_FLAGS_MASTER : BRIDGE_FLAGS_SELF); - - if (vlans) { - /* Add VLANs */ - for (i = 0; vlans[i]; i++) { - const NMPlatformBridgeVlan *vlan = vlans[i]; - gboolean is_range = vlan->vid_start != vlan->vid_end; - - vinfo.vid = vlan->vid_start; - vinfo.flags = is_range ? BRIDGE_VLAN_INFO_RANGE_BEGIN : 0; - - if (vlan->untagged) - vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED; - if (vlan->pvid) - vinfo.flags |= BRIDGE_VLAN_INFO_PVID; - - NLA_PUT(nlmsg, IFLA_BRIDGE_VLAN_INFO, sizeof(vinfo), &vinfo); - - if (is_range) { - vinfo.vid = vlan->vid_end; - vinfo.flags = BRIDGE_VLAN_INFO_RANGE_END; - NLA_PUT(nlmsg, IFLA_BRIDGE_VLAN_INFO, sizeof(vinfo), &vinfo); - } - } - } else { - /* Flush existing VLANs */ - vinfo.vid = 1; - vinfo.flags = BRIDGE_VLAN_INFO_RANGE_BEGIN; - NLA_PUT(nlmsg, IFLA_BRIDGE_VLAN_INFO, sizeof(vinfo), &vinfo); - - vinfo.vid = 4094; - vinfo.flags = BRIDGE_VLAN_INFO_RANGE_END; - NLA_PUT(nlmsg, IFLA_BRIDGE_VLAN_INFO, sizeof(vinfo), &vinfo); - } - - nla_nest_end(nlmsg, list); - - return (do_change_link(platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) >= 0); -nla_put_failure: - g_return_val_if_reached(FALSE); -} - -static char * -link_get_physical_port_id(NMPlatform *platform, int ifindex) -{ - nm_auto_close int dirfd = -1; - char ifname_verified[IFNAMSIZ]; - - dirfd = nm_platform_sysctl_open_netdir(platform, ifindex, ifname_verified); - if (dirfd < 0) - return NULL; - return sysctl_get(platform, NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname_verified, "phys_port_id")); -} - -static guint -link_get_dev_id(NMPlatform *platform, int ifindex) -{ - nm_auto_close int dirfd = -1; - char ifname_verified[IFNAMSIZ]; - - dirfd = nm_platform_sysctl_open_netdir(platform, ifindex, ifname_verified); - if (dirfd < 0) - return 0; - return nm_platform_sysctl_get_int_checked( - platform, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname_verified, "dev_id"), - 16, - 0, - G_MAXUINT16, - 0); -} - -static gboolean -link_tun_add(NMPlatform * platform, - const char * name, - const NMPlatformLnkTun *props, - const NMPlatformLink ** out_link, - int * out_fd) -{ - const NMPObject * obj; - struct ifreq ifr = {}; - nm_auto_close int fd = -1; - - nm_assert(NM_IN_SET(props->type, IFF_TAP, IFF_TUN)); - nm_assert(props->persist || out_fd); - - fd = open("/dev/net/tun", O_RDWR | O_CLOEXEC); - if (fd < 0) - return FALSE; - - nm_utils_ifname_cpy(ifr.ifr_name, name); - ifr.ifr_flags = ((short) props->type) | ((short) IFF_TUN_EXCL) - | (!props->pi ? (short) IFF_NO_PI : (short) 0) - | (props->vnet_hdr ? (short) IFF_VNET_HDR : (short) 0) - | (props->multi_queue ? (short) NM_IFF_MULTI_QUEUE : (short) 0); - if (ioctl(fd, TUNSETIFF, &ifr)) - return FALSE; - - if (props->owner_valid) { - if (ioctl(fd, TUNSETOWNER, (uid_t) props->owner)) - return FALSE; - } - - if (props->group_valid) { - if (ioctl(fd, TUNSETGROUP, (gid_t) props->group)) - return FALSE; - } - - if (props->persist) { - if (ioctl(fd, TUNSETPERSIST, 1)) - return FALSE; - } - - do_request_link(platform, 0, name); - obj = nmp_cache_lookup_link_full(nm_platform_get_cache(platform), - 0, - name, - FALSE, - NM_LINK_TYPE_TUN, - NULL, - NULL); - - if (!obj) - return FALSE; - - NM_SET_OUT(out_link, &obj->link); - NM_SET_OUT(out_fd, nm_steal_fd(&fd)); - return TRUE; -} - -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; - - map = g_new(NMVlanQosMapping, len); - - 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 entries, 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]; - } - - *out_map = map; - *out_n_map = j; -} - -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) -{ - const NMPObject * obj_cache; - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - 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; - - obj_cache = nmp_cache_lookup_link(nm_platform_get_cache(platform), ifindex); - if (!obj_cache || !obj_cache->_link.netlink.is_in_netlink) { - _LOGD("link: change %d: %s: link does not exist", ifindex, "vlan"); - return FALSE; - } - - lnk = obj_cache->_link.netlink.lnk ? &obj_cache->_link.netlink.lnk->_lnk_vlan : NULL; - - 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); - - nlmsg = _nl_msg_new_link(RTM_NEWLINK, 0, ifindex, NULL); - 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); - - return (do_change_link(platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) >= 0); -} - -static gboolean -link_enslave(NMPlatform *platform, int master, int slave) -{ - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - int ifindex = slave; - - nlmsg = _nl_msg_new_link(RTM_NEWLINK, 0, ifindex, NULL); - if (!nlmsg) - return FALSE; - - NLA_PUT_U32(nlmsg, IFLA_MASTER, master); - - return (do_change_link(platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) >= 0); -nla_put_failure: - g_return_val_if_reached(FALSE); -} - -static gboolean -link_release(NMPlatform *platform, int master, int slave) -{ - return link_enslave(platform, 0, slave); -} - -/*****************************************************************************/ - -static gboolean -_infiniband_partition_action(NMPlatform * platform, - InfinibandAction action, - int parent, - int p_key, - const NMPlatformLink **out_link) -{ - nm_auto_close int dirfd = -1; - char ifname_parent[IFNAMSIZ]; - const NMPObject * obj; - char id[20]; - char name[IFNAMSIZ]; - gboolean success; - - nm_assert(NM_IN_SET(action, INFINIBAND_ACTION_CREATE_CHILD, INFINIBAND_ACTION_DELETE_CHILD)); - nm_assert(p_key > 0 && p_key <= 0xffff && p_key != 0x8000); - - dirfd = nm_platform_sysctl_open_netdir(platform, parent, ifname_parent); - if (dirfd < 0) { - errno = ENOENT; - return FALSE; - } - - nm_sprintf_buf(id, "0x%04x", p_key); - if (action == INFINIBAND_ACTION_CREATE_CHILD) - success = - nm_platform_sysctl_set(platform, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname_parent, "create_child"), - id); - else - success = - nm_platform_sysctl_set(platform, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname_parent, "delete_child"), - id); - - if (!success) { - if (action == INFINIBAND_ACTION_DELETE_CHILD && errno == ENODEV) - return TRUE; - return FALSE; - } - - nm_utils_new_infiniband_name(name, ifname_parent, p_key); - do_request_link(platform, 0, name); - - if (action == INFINIBAND_ACTION_DELETE_CHILD) - return TRUE; - - obj = nmp_cache_lookup_link_full(nm_platform_get_cache(platform), - 0, - name, - FALSE, - NM_LINK_TYPE_INFINIBAND, - NULL, - NULL); - if (out_link) - *out_link = obj ? &obj->link : NULL; - return !!obj; -} - -static gboolean -infiniband_partition_add(NMPlatform * platform, - int parent, - int p_key, - const NMPlatformLink **out_link) -{ - return _infiniband_partition_action(platform, - INFINIBAND_ACTION_CREATE_CHILD, - parent, - p_key, - out_link); -} - -static gboolean -infiniband_partition_delete(NMPlatform *platform, int parent, int p_key) -{ - return _infiniband_partition_action(platform, - INFINIBAND_ACTION_DELETE_CHILD, - parent, - p_key, - NULL); -} - -/*****************************************************************************/ - -static GObject * -get_ext_data(NMPlatform *platform, int ifindex) -{ - const NMPObject *obj; - - obj = nmp_cache_lookup_link(nm_platform_get_cache(platform), ifindex); - if (!obj) - return NULL; - - return obj->_link.ext_data; -} - -/*****************************************************************************/ - -#define WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, retval) \ - nm_auto_pop_netns NMPNetns *netns = NULL; \ - NMWifiUtils * wifi_data; \ - if (!nm_platform_netns_push(platform, &netns)) \ - return retval; \ - wifi_data = NM_WIFI_UTILS(get_ext_data(platform, ifindex)); \ - if (!wifi_data) \ - return retval; - -static gboolean -wifi_get_capabilities(NMPlatform *platform, int ifindex, NMDeviceWifiCapabilities *caps) -{ - WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, FALSE); - if (caps) - *caps = nm_wifi_utils_get_caps(wifi_data); - return TRUE; -} - -static guint32 -wifi_get_frequency(NMPlatform *platform, int ifindex) -{ - WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, 0); - return nm_wifi_utils_get_freq(wifi_data); -} - -static gboolean -wifi_get_station(NMPlatform * platform, - int ifindex, - NMEtherAddr *out_bssid, - int * out_quality, - guint32 * out_rate) -{ - WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, FALSE); - return nm_wifi_utils_get_station(wifi_data, out_bssid, out_quality, out_rate); -} - -static NM80211Mode -wifi_get_mode(NMPlatform *platform, int ifindex) -{ - WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, NM_802_11_MODE_UNKNOWN); - return nm_wifi_utils_get_mode(wifi_data); -} - -static void -wifi_set_mode(NMPlatform *platform, int ifindex, NM80211Mode mode) -{ - WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, ); - nm_wifi_utils_set_mode(wifi_data, mode); -} - -static void -wifi_set_powersave(NMPlatform *platform, int ifindex, guint32 powersave) -{ - WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, ); - nm_wifi_utils_set_powersave(wifi_data, powersave); -} - -static guint32 -wifi_find_frequency(NMPlatform *platform, int ifindex, const guint32 *freqs) -{ - WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, 0); - return nm_wifi_utils_find_freq(wifi_data, freqs); -} - -static void -wifi_indicate_addressing_running(NMPlatform *platform, int ifindex, gboolean running) -{ - WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, ); - nm_wifi_utils_indicate_addressing_running(wifi_data, running); -} - -static NMSettingWirelessWakeOnWLan -wifi_get_wake_on_wlan(NMPlatform *platform, int ifindex) -{ - WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, FALSE); - return nm_wifi_utils_get_wake_on_wlan(wifi_data); -} - -static gboolean -wifi_set_wake_on_wlan(NMPlatform *platform, int ifindex, NMSettingWirelessWakeOnWLan wowl) -{ - WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, FALSE); - return nm_wifi_utils_set_wake_on_wlan(wifi_data, wowl); -} - -/*****************************************************************************/ - -static gboolean -link_can_assume(NMPlatform *platform, int ifindex) -{ - NMPLookup lookup; - const NMPObject *link, *o; - NMDedupMultiIter iter; - NMPCache * cache = nm_platform_get_cache(platform); - - if (ifindex <= 0) - return FALSE; - - link = nm_platform_link_get_obj(platform, ifindex, TRUE); - if (!link) - return FALSE; - - if (!NM_FLAGS_HAS(link->link.n_ifi_flags, IFF_UP)) - return FALSE; - - if (link->link.master > 0) - return TRUE; - - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex); - if (nmp_cache_lookup(cache, &lookup)) - return TRUE; - - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP6_ADDRESS, ifindex); - nmp_cache_iter_for_each (&iter, nmp_cache_lookup(cache, &lookup), &o) { - nm_assert(NMP_OBJECT_GET_TYPE(o) == NMP_OBJECT_TYPE_IP6_ADDRESS); - if (!IN6_IS_ADDR_LINKLOCAL(&o->ip6_address.address)) - return TRUE; - } - return FALSE; -} - -/*****************************************************************************/ - -static guint32 -mesh_get_channel(NMPlatform *platform, int ifindex) -{ - WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, 0); - return nm_wifi_utils_get_mesh_channel(wifi_data); -} - -static gboolean -mesh_set_channel(NMPlatform *platform, int ifindex, guint32 channel) -{ - WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, FALSE); - return nm_wifi_utils_set_mesh_channel(wifi_data, channel); -} - -static gboolean -mesh_set_ssid(NMPlatform *platform, int ifindex, const guint8 *ssid, gsize len) -{ - WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, FALSE); - return nm_wifi_utils_set_mesh_ssid(wifi_data, ssid, len); -} - -/*****************************************************************************/ - -#define WPAN_GET_WPAN_DATA(wpan_data, platform, ifindex, retval) \ - NMWpanUtils *wpan_data = NM_WPAN_UTILS(get_ext_data(platform, ifindex)); \ - if (!wpan_data) \ - return retval; - -static guint16 -wpan_get_pan_id(NMPlatform *platform, int ifindex) -{ - WPAN_GET_WPAN_DATA(wpan_data, platform, ifindex, G_MAXINT16); - return nm_wpan_utils_get_pan_id(wpan_data); -} - -static gboolean -wpan_set_pan_id(NMPlatform *platform, int ifindex, guint16 pan_id) -{ - WPAN_GET_WPAN_DATA(wpan_data, platform, ifindex, FALSE); - return nm_wpan_utils_set_pan_id(wpan_data, pan_id); -} - -static guint16 -wpan_get_short_addr(NMPlatform *platform, int ifindex) -{ - WPAN_GET_WPAN_DATA(wpan_data, platform, ifindex, G_MAXINT16); - return nm_wpan_utils_get_short_addr(wpan_data); -} - -static gboolean -wpan_set_short_addr(NMPlatform *platform, int ifindex, guint16 short_addr) -{ - WPAN_GET_WPAN_DATA(wpan_data, platform, ifindex, FALSE); - return nm_wpan_utils_set_short_addr(wpan_data, short_addr); -} - -static gboolean -wpan_set_channel(NMPlatform *platform, int ifindex, guint8 page, guint8 channel) -{ - WPAN_GET_WPAN_DATA(wpan_data, platform, ifindex, FALSE); - return nm_wpan_utils_set_channel(wpan_data, page, channel); -} - -/*****************************************************************************/ - -static gboolean -link_get_wake_on_lan(NMPlatform *platform, int ifindex) -{ - nm_auto_pop_netns NMPNetns *netns = NULL; - NMLinkType type = nm_platform_link_get_type(platform, ifindex); - - if (!nm_platform_netns_push(platform, &netns)) - return FALSE; - - if (type == NM_LINK_TYPE_ETHERNET) - return nmp_utils_ethtool_get_wake_on_lan(ifindex); - else if (type == NM_LINK_TYPE_WIFI) { - NMWifiUtils *wifi_data = NM_WIFI_UTILS(get_ext_data(platform, ifindex)); - - if (!wifi_data) - return FALSE; - - return !NM_IN_SET(nm_wifi_utils_get_wake_on_wlan(wifi_data), - NM_SETTING_WIRELESS_WAKE_ON_WLAN_NONE, - NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE); - - } else - return FALSE; -} - -static gboolean -link_get_driver_info(NMPlatform *platform, - int ifindex, - char ** out_driver_name, - char ** out_driver_version, - char ** out_fw_version) -{ - nm_auto_pop_netns NMPNetns *netns = NULL; - NMPUtilsEthtoolDriverInfo driver_info; - - if (!nm_platform_netns_push(platform, &netns)) - return FALSE; - - if (!nmp_utils_ethtool_get_driver_info(ifindex, &driver_info)) - return FALSE; - NM_SET_OUT(out_driver_name, g_strdup(driver_info.driver)); - NM_SET_OUT(out_driver_version, g_strdup(driver_info.version)); - NM_SET_OUT(out_fw_version, g_strdup(driver_info.fw_version)); - return TRUE; -} - -/*****************************************************************************/ - -static gboolean -ip4_address_add(NMPlatform *platform, - int ifindex, - in_addr_t addr, - guint8 plen, - in_addr_t peer_addr, - in_addr_t broadcast_address, - guint32 lifetime, - guint32 preferred, - guint32 flags, - const char *label) -{ - 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, - flags, - nm_utils_ip4_address_is_link_local(addr) ? RT_SCOPE_LINK - : RT_SCOPE_UNIVERSE, - lifetime, - preferred, - broadcast_address, - label); - - nmp_object_stackinit_id_ip4_address(&obj_id, ifindex, addr, plen, peer_addr); - return (do_add_addrroute(platform, &obj_id, nlmsg, FALSE) >= 0); -} - -static gboolean -ip6_address_add(NMPlatform * platform, - int ifindex, - struct in6_addr addr, - guint8 plen, - struct in6_addr peer_addr, - guint32 lifetime, - guint32 preferred, - guint32 flags) -{ - 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_INET6, - ifindex, - &addr, - plen, - IN6_IS_ADDR_UNSPECIFIED(&peer_addr) ? NULL : &peer_addr, - flags, - RT_SCOPE_UNIVERSE, - lifetime, - preferred, - 0, - NULL); - - nmp_object_stackinit_id_ip6_address(&obj_id, ifindex, &addr); - return (do_add_addrroute(platform, &obj_id, nlmsg, FALSE) >= 0); -} - -static gboolean -ip4_address_delete(NMPlatform *platform, - int ifindex, - in_addr_t addr, - guint8 plen, - in_addr_t peer_address) -{ - 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, - 0, - NULL); - if (!nlmsg) - g_return_val_if_reached(FALSE); - - 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, guint8 plen) -{ - 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, - 0, - NULL); - if (!nlmsg) - g_return_val_if_reached(FALSE); - - nmp_object_stackinit_id_ip6_address(&obj_id, ifindex, &addr); - return do_delete_object(platform, &obj_id, nlmsg); -} - -/*****************************************************************************/ - -static int -ip_route_add(NMPlatform * platform, - NMPNlmFlags flags, - int addr_family, - const NMPlatformIPRoute *route) -{ - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - NMPObject obj; - - nmp_object_stackinit(&obj, - NMP_OBJECT_TYPE_IP_ROUTE(NM_IS_IPv4(addr_family)), - (const NMPlatformObject *) route); - - nm_platform_ip_route_normalize(addr_family, NMP_OBJECT_CAST_IP_ROUTE(&obj)); - - nlmsg = _nl_msg_new_route(RTM_NEWROUTE, flags & NMP_NLM_FLAG_FMASK, &obj); - if (!nlmsg) - g_return_val_if_reached(-NME_BUG); - return do_add_addrroute(platform, - &obj, - nlmsg, - NM_FLAGS_HAS(flags, NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE)); -} - -static gboolean -object_delete(NMPlatform *platform, const NMPObject *obj) -{ - nm_auto_nmpobj const NMPObject *obj_keep_alive = NULL; - nm_auto_nlmsg struct nl_msg * nlmsg = NULL; - - if (!NMP_OBJECT_IS_STACKINIT(obj)) - obj_keep_alive = nmp_object_ref(obj); - - switch (NMP_OBJECT_GET_TYPE(obj)) { - case NMP_OBJECT_TYPE_IP4_ROUTE: - case NMP_OBJECT_TYPE_IP6_ROUTE: - nlmsg = _nl_msg_new_route(RTM_DELROUTE, 0, obj); - break; - case NMP_OBJECT_TYPE_ROUTING_RULE: - nlmsg = _nl_msg_new_routing_rule(RTM_DELRULE, 0, NMP_OBJECT_CAST_ROUTING_RULE(obj)); - break; - case NMP_OBJECT_TYPE_QDISC: - nlmsg = _nl_msg_new_qdisc(RTM_DELQDISC, 0, NMP_OBJECT_CAST_QDISC(obj)); - break; - case NMP_OBJECT_TYPE_TFILTER: - nlmsg = _nl_msg_new_tfilter(RTM_DELTFILTER, 0, NMP_OBJECT_CAST_TFILTER(obj)); - break; - default: - break; - } - - if (!nlmsg) - g_return_val_if_reached(FALSE); - return do_delete_object(platform, obj, nlmsg); -} - -/*****************************************************************************/ - -static int -ip_route_get(NMPlatform * platform, - int addr_family, - gconstpointer address, - int oif_ifindex, - NMPObject ** out_route) -{ - const gboolean is_v4 = (addr_family == AF_INET); - const int addr_len = is_v4 ? 4 : 16; - int try_count = 0; - WaitForNlResponseResult seq_result; - int nle; - nm_auto_nmpobj NMPObject *route = NULL; - - nm_assert(NM_IS_LINUX_PLATFORM(platform)); - nm_assert(NM_IN_SET(addr_family, AF_INET, AF_INET6)); - nm_assert(address); - - do { - struct { - struct nlmsghdr n; - struct rtmsg r; - char buf[64]; - } req = { - .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)), - .n.nlmsg_flags = NLM_F_REQUEST, - .n.nlmsg_type = RTM_GETROUTE, - .r.rtm_family = addr_family, - .r.rtm_tos = 0, - .r.rtm_dst_len = is_v4 ? 32 : 128, - .r.rtm_flags = 0x1000 /* RTM_F_LOOKUP_TABLE */, - }; - - nm_clear_pointer(&route, nmp_object_unref); - - if (!_nl_addattr_l(&req.n, sizeof(req), RTA_DST, address, addr_len)) - nm_assert_not_reached(); - - if (oif_ifindex > 0) { - gint32 ii = oif_ifindex; - - if (!_nl_addattr_l(&req.n, sizeof(req), RTA_OIF, &ii, sizeof(ii))) - nm_assert_not_reached(); - } - - seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - nle = _nl_send_nlmsghdr(platform, - &req.n, - &seq_result, - NULL, - DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET, - &route); - if (nle < 0) { - _LOGE("get-route: failure sending netlink request \"%s\" (%d)", - nm_strerror_native(-nle), - -nle); - return -NME_UNSPEC; - } - - delayed_action_handle_all(platform, FALSE); - - /* Retry, if we failed due to a cache resync. That can happen when the netlink - * socket fills up and we lost the response. */ - } while (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC && ++try_count < 10); - - if (seq_result < 0) { - /* negative seq_result is an errno from kernel. Map it to negative - * int (which are also errno). */ - return (int) seq_result; - } - - if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) { - if (route) { - NM_SET_OUT(out_route, g_steal_pointer(&route)); - return 0; - } - seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN; - } - - return -NME_UNSPEC; -} - -/*****************************************************************************/ - -static int -routing_rule_add(NMPlatform *platform, NMPNlmFlags flags, const NMPlatformRoutingRule *routing_rule) -{ - WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - nm_auto_nlmsg struct nl_msg *msg = NULL; - gs_free char * errmsg = NULL; - char s_buf[256]; - int nle; - - msg = _nl_msg_new_routing_rule(RTM_NEWRULE, flags, routing_rule); - - event_handler_read_netlink(platform, FALSE); - - nle = _nl_send_nlmsg(platform, - msg, - &seq_result, - &errmsg, - DELAYED_ACTION_RESPONSE_TYPE_VOID, - NULL); - if (nle < 0) { - _LOGE("do-add-rule: failed sending netlink request \"%s\" (%d)", nm_strerror(nle), -nle); - return -NME_PL_NETLINK; - } - - delayed_action_handle_all(platform, FALSE); - - nm_assert(seq_result); - - _NMLOG(seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK ? LOGL_DEBUG : LOGL_WARN, - "do-add-rule: %s", - wait_for_nl_response_to_string(seq_result, errmsg, s_buf, sizeof(s_buf))); - - if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) - return 0; - if (seq_result < 0) - return seq_result; - return -NME_UNSPEC; -} - -/*****************************************************************************/ - -static int -qdisc_add(NMPlatform *platform, NMPNlmFlags flags, const NMPlatformQdisc *qdisc) -{ - WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char * errmsg = NULL; - int nle; - char s_buf[256]; - nm_auto_nlmsg struct nl_msg *msg = NULL; - - /* Note: @qdisc must not be copied or kept alive because the lifetime of qdisc.kind - * is undefined. */ - - msg = _nl_msg_new_qdisc(RTM_NEWQDISC, flags, qdisc); - - event_handler_read_netlink(platform, FALSE); - - nle = _nl_send_nlmsg(platform, - msg, - &seq_result, - &errmsg, - DELAYED_ACTION_RESPONSE_TYPE_VOID, - NULL); - if (nle < 0) { - _LOGE("do-add-qdisc: failed sending netlink request \"%s\" (%d)", nm_strerror(nle), -nle); - return -NME_PL_NETLINK; - } - - delayed_action_handle_all(platform, FALSE); - - nm_assert(seq_result); - - _NMLOG(seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK ? LOGL_DEBUG : LOGL_WARN, - "do-add-qdisc: %s", - wait_for_nl_response_to_string(seq_result, errmsg, s_buf, sizeof(s_buf))); - - if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) - return 0; - if (seq_result < 0) - return seq_result; - return -NME_UNSPEC; -} - -/*****************************************************************************/ - -static int -tfilter_add(NMPlatform *platform, NMPNlmFlags flags, const NMPlatformTfilter *tfilter) -{ - WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; - gs_free char * errmsg = NULL; - int nle; - char s_buf[256]; - nm_auto_nlmsg struct nl_msg *msg = NULL; - - /* Note: @tfilter must not be copied or kept alive because the lifetime of tfilter.kind - * and tfilter.action.kind is undefined. */ - - msg = _nl_msg_new_tfilter(RTM_NEWTFILTER, flags, tfilter); - - event_handler_read_netlink(platform, FALSE); - - nle = _nl_send_nlmsg(platform, - msg, - &seq_result, - &errmsg, - DELAYED_ACTION_RESPONSE_TYPE_VOID, - NULL); - if (nle < 0) { - _LOGE("do-add-tfilter: failed sending netlink request \"%s\" (%d)", nm_strerror(nle), -nle); - return -NME_PL_NETLINK; - } - - delayed_action_handle_all(platform, FALSE); - - nm_assert(seq_result); - - _NMLOG(seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK ? LOGL_DEBUG : LOGL_WARN, - "do-add-tfilter: %s", - wait_for_nl_response_to_string(seq_result, errmsg, s_buf, sizeof(s_buf))); - - if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) - return 0; - - return -NME_UNSPEC; -} - -/*****************************************************************************/ - -static gboolean -event_handler(int fd, GIOCondition io_condition, gpointer user_data) -{ - delayed_action_handle_all(NM_PLATFORM(user_data), TRUE); - return TRUE; -} - -/*****************************************************************************/ - -/* copied from libnl3's recvmsgs() */ -static int -event_handler_recvmsgs(NMPlatform *platform, gboolean handle_events) -{ - NMLinuxPlatformPrivate * priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - struct nl_sock * sk = priv->nlh; - int n; - int err = 0; - gboolean multipart = 0; - gboolean interrupted = FALSE; - struct nlmsghdr * hdr; - WaitForNlResponseResult seq_result; - struct sockaddr_nl nla = {0}; - struct ucred creds; - gboolean creds_has; - nm_auto_free unsigned char *buf = NULL; - -continue_reading: - nm_clear_pointer(&buf, free); - n = nl_recv(sk, &nla, &buf, &creds, &creds_has); - - if (n <= 0) { - if (n == -NME_NL_MSG_TRUNC) { - int buf_size; - - /* the message receive buffer was too small. We lost one message, which - * is unfortunate. Try to double the buffer size for the next time. */ - buf_size = nl_socket_get_msg_buf_size(sk); - if (buf_size < 512 * 1024) { - buf_size *= 2; - _LOGT("netlink: recvmsg: increase message buffer size for recvmsg() to %d bytes", - buf_size); - if (nl_socket_set_msg_buf_size(sk, buf_size) < 0) - nm_assert_not_reached(); - if (!handle_events) - goto continue_reading; - } - } - - return n; - } - - hdr = (struct nlmsghdr *) buf; - while (nlmsg_ok(hdr, n)) { - nm_auto_nlmsg struct nl_msg *msg = NULL; - gboolean abort_parsing = FALSE; - gboolean process_valid_msg = FALSE; - guint32 seq_number; - char buf_nlmsghdr[400]; - const char * extack_msg = NULL; - - msg = nlmsg_alloc_convert(hdr); - - nlmsg_set_proto(msg, NETLINK_ROUTE); - nlmsg_set_src(msg, &nla); - - if (!creds_has || creds.pid) { - if (!creds_has) - _LOGT("netlink: recvmsg: received message without credentials"); - else - _LOGT("netlink: recvmsg: received non-kernel message (pid %d)", creds.pid); - err = 0; - goto stop; - } - - _LOGt("netlink: recvmsg: new message %s", - nl_nlmsghdr_to_str(hdr, buf_nlmsghdr, sizeof(buf_nlmsghdr))); - - nlmsg_set_creds(msg, &creds); - - if (hdr->nlmsg_flags & NLM_F_MULTI) - multipart = TRUE; - - 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 = TRUE; - } - - /* 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 = FALSE; - 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 returning - * NL_SKIP or NL_PROCEED (dangerous) */ - err = -NME_NL_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 = -NME_NL_MSG_TRUNC; - abort_parsing = TRUE; - } else if (e->error) { - int errsv = nm_errno_native(e->error); - - if (NM_FLAGS_HAS(hdr->nlmsg_flags, NLM_F_ACK_TLVS) - && hdr->nlmsg_len >= sizeof(*e) + e->msg.nlmsg_len) { - static const struct nla_policy policy[] = { - [NLMSGERR_ATTR_MSG] = {.type = NLA_STRING}, - [NLMSGERR_ATTR_OFFS] = {.type = NLA_U32}, - }; - struct nlattr *tb[G_N_ELEMENTS(policy)]; - struct nlattr *tlvs; - - tlvs = (struct nlattr *) ((char *) e + sizeof(*e) + e->msg.nlmsg_len - - NLMSG_HDRLEN); - if (nla_parse_arr(tb, - tlvs, - hdr->nlmsg_len - sizeof(*e) - e->msg.nlmsg_len, - policy) - >= 0) { - if (tb[NLMSGERR_ATTR_MSG]) - extack_msg = nla_get_string(tb[NLMSGERR_ATTR_MSG]); - } - } - - /* Error message reported back from kernel. */ - _LOGD("netlink: recvmsg: error message from kernel: %s (%d)%s%s%s for request %d", - nm_strerror_native(errsv), - errsv, - NM_PRINT_FMT_QUOTED(extack_msg, " \"", extack_msg, "\"", ""), - nlmsg_hdr(msg)->nlmsg_seq); - seq_result = -NM_ERRNO_NATIVE(errsv); - } else - seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; - } else - process_valid_msg = TRUE; - - seq_number = nlmsg_hdr(msg)->nlmsg_seq; - - /* check whether the seq number is different from before, and - * whether the previous number (@nlh_seq_last_seen) is a pending - * refresh-all request. In that case, the pending request is thereby - * completed. - * - * We must do that before processing the message with event_valid_msg(), - * because we must track the completion of the pending request before that. */ - event_seq_check_refresh_all(platform, seq_number); - - if (process_valid_msg) { - /* 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, handle_events); - - seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; - } - - event_seq_check(platform, seq_number, seq_result, extack_msg); - - if (abort_parsing) - goto stop; - - err = 0; - hdr = nlmsg_next(hdr, &n); - } - - if (multipart) { - /* Multipart message not yet complete, continue reading */ - goto continue_reading; - } -stop: - if (!handle_events) { - /* when we don't handle events, we want to drain all messages from the socket - * without handling the messages (but still check for sequence numbers). - * Repeat reading. */ - goto continue_reading; - } - - if (interrupted) - return -NME_NL_DUMP_INTR; - return err; -} - -/*****************************************************************************/ - -static gboolean -event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks) -{ - nm_auto_pop_netns NMPNetns *netns = NULL; - NMLinuxPlatformPrivate * priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - int r; - struct pollfd pfd; - gboolean any = FALSE; - int timeout_msec; - struct { - guint32 seq_number; - gint64 timeout_abs_ns; - gint64 now_ns; - } next; - - if (!nm_platform_netns_push(platform, &netns)) { - delayed_action_wait_for_nl_response_complete_all(platform, - WAIT_FOR_NL_RESPONSE_RESULT_FAILED_SETNS); - return FALSE; - } - - for (;;) { - for (;;) { - int nle; - - nle = event_handler_recvmsgs(platform, TRUE); - - if (nle < 0) { - switch (nle) { - case -EAGAIN: - goto after_read; - case -NME_NL_DUMP_INTR: - _LOGD("netlink: read: uncritical failure to retrieve incoming events: %s (%d)", - nm_strerror(nle), - nle); - break; - case -NME_NL_MSG_TRUNC: - case -ENOBUFS: - _LOGI("netlink: read: %s. Need to resynchronize platform cache", ({ - const char *_reason = "unknown"; - switch (nle) { - case -NME_NL_MSG_TRUNC: - _reason = "message truncated"; - break; - case -ENOBUFS: - _reason = "too many netlink events"; - break; - } - _reason; - })); - event_handler_recvmsgs(platform, FALSE); - delayed_action_wait_for_nl_response_complete_all( - platform, - WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC); - - 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 - | DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL - | DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS - | DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, - NULL); - break; - default: - _LOGE("netlink: read: failed to retrieve incoming events: %s (%d)", - nm_strerror(nle), - nle); - break; - } - } - any = TRUE; - } - -after_read: - - if (!NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) - return any; - - delayed_action_wait_for_nl_response_complete_check(platform, - WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN, - &next.seq_number, - &next.timeout_abs_ns, - &next.now_ns); - - if (!wait_for_acks - || !NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) - return any; - - nm_assert(next.seq_number); - nm_assert(next.now_ns > 0); - nm_assert(next.timeout_abs_ns > next.now_ns); - - _LOGT("netlink: read: wait for ACK for sequence number %u...", next.seq_number); - - timeout_msec = (next.timeout_abs_ns - next.now_ns) / (NM_UTILS_NSEC_PER_SEC / 1000); - - memset(&pfd, 0, sizeof(pfd)); - pfd.fd = nl_socket_get_fd(priv->nlh); - pfd.events = POLLIN; - r = poll(&pfd, 1, MAX(1, timeout_msec)); - - if (r == 0) { - /* timeout and there is nothing to read. */ - goto after_read; - } - - if (r < 0) { - int errsv = errno; - - if (errsv != EINTR) { - _LOGE("netlink: read: poll failed with %s", nm_strerror_native(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. */ - } - } -} - -/*****************************************************************************/ - -static void -cache_update_link_udev(NMPlatform *platform, int ifindex, struct udev_device *udevice) -{ - nm_auto_nmpobj const NMPObject *obj_old = NULL; - nm_auto_nmpobj const NMPObject *obj_new = NULL; - NMPCacheOpsType cache_op; - - cache_op = nmp_cache_update_link_udev(nm_platform_get_cache(platform), - ifindex, - udevice, - &obj_old, - &obj_new); - - if (cache_op != NMP_CACHE_OPS_UNCHANGED) { - nm_auto_pop_netns NMPNetns *netns = NULL; - - cache_on_change(platform, cache_op, obj_old, obj_new); - if (!nm_platform_netns_push(platform, &netns)) - return; - nm_platform_cache_update_emit_signal(platform, cache_op, obj_old, obj_new); - } -} - -static void -udev_device_added(NMPlatform *platform, struct udev_device *udevice) -{ - const char *ifname; - const char *ifindex_s; - int ifindex; - - ifname = udev_device_get_sysname(udevice); - if (!ifname) { - _LOGD("udev-add: failed to get device's interface"); - return; - } - - ifindex_s = udev_device_get_property_value(udevice, "IFINDEX"); - if (!ifindex_s) { - _LOGW("udev-add[%s]failed to get device's ifindex", ifname); - return; - } - ifindex = _nm_utils_ascii_str_to_int64(ifindex_s, 10, 1, G_MAXINT, 0); - if (ifindex <= 0) { - _LOGW("udev-add[%s]: retrieved invalid IFINDEX=%d", ifname, ifindex); - return; - } - - if (!udev_device_get_syspath(udevice)) { - _LOGD("udev-add[%s,%d]: couldn't determine device path; ignoring...", ifname, ifindex); - return; - } - - _LOGT("udev-add[%s,%d]: device added", ifname, ifindex); - cache_update_link_udev(platform, ifindex, udevice); -} - -static gboolean -_udev_device_removed_match_link(const NMPObject *obj, gpointer udevice) -{ - return obj->_link.udev.device == udevice; -} - -static void -udev_device_removed(NMPlatform *platform, struct udev_device *udevice) -{ - const char *ifindex_s; - int ifindex = 0; - - ifindex_s = udev_device_get_property_value(udevice, "IFINDEX"); - ifindex = _nm_utils_ascii_str_to_int64(ifindex_s, 10, 1, G_MAXINT, 0); - if (ifindex <= 0) { - const NMPObject *obj; - - obj = nmp_cache_lookup_link_full(nm_platform_get_cache(platform), - 0, - NULL, - FALSE, - NM_LINK_TYPE_NONE, - _udev_device_removed_match_link, - udevice); - if (obj) - ifindex = obj->link.ifindex; - } - - _LOGD("udev-remove: IFINDEX=%d", ifindex); - if (ifindex <= 0) - return; - - cache_update_link_udev(platform, ifindex, NULL); -} - -static void -handle_udev_event(NMUdevClient *udev_client, struct udev_device *udevice, gpointer user_data) -{ - nm_auto_pop_netns NMPNetns *netns = NULL; - NMPlatform * platform = NM_PLATFORM(user_data); - const char * subsys; - const char * ifindex; - guint64 seqnum; - const char * action; - - action = udev_device_get_action(udevice); - g_return_if_fail(action); - - subsys = udev_device_get_subsystem(udevice); - g_return_if_fail(nm_streq0(subsys, "net")); - - if (!nm_platform_netns_push(platform, &netns)) - return; - - ifindex = udev_device_get_property_value(udevice, "IFINDEX"); - seqnum = udev_device_get_seqnum(udevice); - _LOGD("UDEV event: action '%s' subsys '%s' device '%s' (%s); seqnum=%" G_GUINT64_FORMAT, - action, - subsys, - udev_device_get_sysname(udevice), - ifindex ?: "unknown", - seqnum); - - if (NM_IN_STRSET(action, "add", "move")) - udev_device_added(platform, udevice); - else if (NM_IN_STRSET(action, "remove")) - udev_device_removed(platform, udevice); -} - -/*****************************************************************************/ - -void -nm_linux_platform_setup(void) -{ - nm_platform_setup(nm_linux_platform_new(FALSE, FALSE)); -} - -/*****************************************************************************/ - -static void -nm_linux_platform_init(NMLinuxPlatform *self) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(self); - - 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)); -} - -static void -constructed(GObject *_object) -{ - NMPlatform * platform = NM_PLATFORM(_object); - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - int nle; - int fd; - - nm_assert(!platform->_netns || platform->_netns == nmp_netns_get_current()); - - if (nm_platform_get_use_udev(platform)) { - priv->udev_client = nm_udev_client_new(NM_MAKE_STRV("net"), handle_udev_event, platform); - } - - _LOGD("create (%s netns, %s, %s udev)", - !platform->_netns ? "ignore" : "use", - !platform->_netns && nmp_netns_is_initial() - ? "initial netns" - : (!nmp_netns_get_current() - ? "no netns support" - : nm_sprintf_bufa(100, - "in netns[%p]%s", - nmp_netns_get_current(), - nmp_netns_get_current() == nmp_netns_get_initial() ? "/main" - : "")), - nm_platform_get_use_udev(platform) ? "use" : "no"); - - priv->genl = nl_socket_alloc(); - g_assert(priv->genl); - - nle = nl_connect(priv->genl, NETLINK_GENERIC); - if (nle) { - _LOGE("unable to connect the generic netlink socket \"%s\" (%d)", nm_strerror(nle), -nle); - nl_socket_free(priv->genl); - priv->genl = NULL; - } - - priv->nlh = nl_socket_alloc(); - g_assert(priv->nlh); - - 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); - - /* use 8 MB for receive socket kernel queue. */ - nle = nl_socket_set_buffer_size(priv->nlh, 8 * 1024 * 1024, 0); - g_assert(!nle); - - nle = nl_socket_set_ext_ack(priv->nlh, TRUE); - if (nle) - _LOGD("could not enable extended acks on netlink socket"); - - /* explicitly set the msg buffer size and disable MSG_PEEK. - * If we later encounter NME_NL_MSG_TRUNC, we will adjust the buffer size. */ - nl_socket_disable_msg_peek(priv->nlh); - nle = nl_socket_set_msg_buf_size(priv->nlh, 32 * 1024); - g_assert(!nle); - - nle = nl_socket_add_memberships(priv->nlh, - RTNLGRP_IPV4_IFADDR, - RTNLGRP_IPV4_ROUTE, - RTNLGRP_IPV4_RULE, - RTNLGRP_IPV6_RULE, - RTNLGRP_IPV6_IFADDR, - RTNLGRP_IPV6_ROUTE, - RTNLGRP_LINK, - RTNLGRP_TC, - 0); - g_assert(!nle); - - fd = nl_socket_get_fd(priv->nlh); - - _LOGD("Netlink socket for events established: port=%u, fd=%d", - nl_socket_get_local_port(priv->nlh), - fd); - - priv->event_source = - nm_g_unix_fd_source_new(fd, - G_IO_IN | G_IO_NVAL | G_IO_PRI | G_IO_ERR | G_IO_HUP, - G_PRIORITY_DEFAULT, - event_handler, - platform, - NULL); - g_source_attach(priv->event_source, NULL); - - /* complete construction of the GObject instance before populating the cache. */ - G_OBJECT_CLASS(nm_linux_platform_parent_class)->constructed(_object); - - _LOGD("populate platform cache"); - 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 - | DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL - | DELAYED_ACTION_TYPE_REFRESH_ALL_QDISCS | DELAYED_ACTION_TYPE_REFRESH_ALL_TFILTERS, - NULL); - - delayed_action_handle_all(platform, FALSE); - - /* Set up udev monitoring */ - if (priv->udev_client) { - struct udev_enumerate * enumerator; - struct udev_list_entry *devices, *l; - - /* And read initial device list */ - enumerator = nm_udev_client_enumerate_new(priv->udev_client); - - udev_enumerate_add_match_is_initialized(enumerator); - - udev_enumerate_scan_devices(enumerator); - - devices = udev_enumerate_get_list_entry(enumerator); - for (l = devices; l; l = udev_list_entry_get_next(l)) { - struct udev_device *udevice; - - udevice = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerator), - udev_list_entry_get_name(l)); - if (!udevice) - continue; - - udev_device_added(platform, udevice); - udev_device_unref(udevice); - } - - udev_enumerate_unref(enumerator); - } -} - -/* Similar to systemd's path_is_read_only_fs(), at - * https://github.com/systemd/systemd/blob/v246/src/basic/stat-util.c#L132 */ -static int -path_is_read_only_fs(const char *path) -{ - struct statvfs st; - - if (statvfs(path, &st) < 0) - return -errno; - - if (st.f_flag & ST_RDONLY) - return TRUE; - - /* On NFS, statvfs() might not reflect whether we can actually - * write to the remote share. Let's try again with - * access(W_OK) which is more reliable, at least sometimes. */ - if (access(path, W_OK) < 0 && errno == EROFS) - return TRUE; - - return FALSE; -} - -NMPlatform * -nm_linux_platform_new(gboolean log_with_ptr, gboolean netns_support) -{ - gboolean use_udev = FALSE; - - if (nmp_netns_is_initial() && path_is_read_only_fs("/sys") == FALSE) - use_udev = TRUE; - - return g_object_new(NM_TYPE_LINUX_PLATFORM, - NM_PLATFORM_LOG_WITH_PTR, - log_with_ptr, - NM_PLATFORM_USE_UDEV, - use_udev, - NM_PLATFORM_NETNS_SUPPORT, - netns_support, - NULL); -} - -static void -dispose(GObject *object) -{ - NMPlatform * platform = NM_PLATFORM(object); - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform); - - _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); - - G_OBJECT_CLASS(nm_linux_platform_parent_class)->dispose(object); -} - -static void -finalize(GObject *object) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(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); - - nl_socket_free(priv->genl); - - nm_clear_g_source_inst(&priv->event_source); - - nl_socket_free(priv->nlh); - - 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); - } - - priv->udev_client = nm_udev_client_destroy(priv->udev_client); - - G_OBJECT_CLASS(nm_linux_platform_parent_class)->finalize(object); -} - -static void -nm_linux_platform_class_init(NMLinuxPlatformClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMPlatformClass *platform_class = NM_PLATFORM_CLASS(klass); - - object_class->constructed = constructed; - object_class->dispose = dispose; - object_class->finalize = finalize; - - platform_class->sysctl_set = sysctl_set; - platform_class->sysctl_set_async = sysctl_set_async; - platform_class->sysctl_get = sysctl_get; - - platform_class->link_add = link_add; - platform_class->link_delete = link_delete; - - platform_class->link_refresh = link_refresh; - - platform_class->link_set_netns = link_set_netns; - - platform_class->link_set_up = link_set_up; - platform_class->link_set_down = link_set_down; - platform_class->link_set_arp = link_set_arp; - platform_class->link_set_noarp = link_set_noarp; - - platform_class->link_set_user_ipv6ll_enabled = link_set_user_ipv6ll_enabled; - platform_class->link_set_token = link_set_token; - - platform_class->link_set_address = link_set_address; - platform_class->link_get_permanent_address = link_get_permanent_address; - platform_class->link_set_mtu = link_set_mtu; - platform_class->link_set_name = link_set_name; - platform_class->link_set_sriov_params_async = link_set_sriov_params_async; - platform_class->link_set_sriov_vfs = link_set_sriov_vfs; - platform_class->link_set_bridge_vlans = link_set_bridge_vlans; - - platform_class->link_get_physical_port_id = link_get_physical_port_id; - platform_class->link_get_dev_id = link_get_dev_id; - platform_class->link_get_wake_on_lan = link_get_wake_on_lan; - platform_class->link_get_driver_info = link_get_driver_info; - - platform_class->link_supports_carrier_detect = link_supports_carrier_detect; - platform_class->link_supports_vlans = link_supports_vlans; - platform_class->link_supports_sriov = link_supports_sriov; - - platform_class->link_enslave = link_enslave; - platform_class->link_release = link_release; - - platform_class->link_can_assume = link_can_assume; - - platform_class->link_vlan_change = link_vlan_change; - platform_class->link_wireguard_change = link_wireguard_change; - - platform_class->infiniband_partition_add = infiniband_partition_add; - platform_class->infiniband_partition_delete = infiniband_partition_delete; - - platform_class->wifi_get_capabilities = wifi_get_capabilities; - platform_class->wifi_get_frequency = wifi_get_frequency; - platform_class->wifi_get_station = wifi_get_station; - 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; - platform_class->wifi_get_wake_on_wlan = wifi_get_wake_on_wlan; - platform_class->wifi_set_wake_on_wlan = wifi_set_wake_on_wlan; - - platform_class->mesh_get_channel = mesh_get_channel; - platform_class->mesh_set_channel = mesh_set_channel; - platform_class->mesh_set_ssid = mesh_set_ssid; - - platform_class->wpan_get_pan_id = wpan_get_pan_id; - platform_class->wpan_set_pan_id = wpan_set_pan_id; - platform_class->wpan_get_short_addr = wpan_get_short_addr; - platform_class->wpan_set_short_addr = wpan_set_short_addr; - platform_class->wpan_set_channel = wpan_set_channel; - - platform_class->link_tun_add = link_tun_add; - - platform_class->object_delete = object_delete; - platform_class->ip4_address_add = ip4_address_add; - platform_class->ip6_address_add = ip6_address_add; - platform_class->ip4_address_delete = ip4_address_delete; - platform_class->ip6_address_delete = ip6_address_delete; - - platform_class->ip_route_add = ip_route_add; - platform_class->ip_route_get = ip_route_get; - - platform_class->routing_rule_add = routing_rule_add; - - platform_class->qdisc_add = qdisc_add; - platform_class->tfilter_add = tfilter_add; - - platform_class->process_events = process_events; -} diff --git a/src/core/platform/nm-linux-platform.h b/src/core/platform/nm-linux-platform.h deleted file mode 100644 index 6837e64a..00000000 --- a/src/core/platform/nm-linux-platform.h +++ /dev/null @@ -1,30 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2012 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_LINUX_PLATFORM_H__ -#define __NETWORKMANAGER_LINUX_PLATFORM_H__ - -#include "nm-platform.h" - -#define NM_TYPE_LINUX_PLATFORM (nm_linux_platform_get_type()) -#define NM_LINUX_PLATFORM(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_LINUX_PLATFORM, NMLinuxPlatform)) -#define NM_LINUX_PLATFORM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_LINUX_PLATFORM, NMLinuxPlatformClass)) -#define NM_IS_LINUX_PLATFORM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_LINUX_PLATFORM)) -#define NM_IS_LINUX_PLATFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_LINUX_PLATFORM)) -#define NM_LINUX_PLATFORM_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_LINUX_PLATFORM, NMLinuxPlatformClass)) - -typedef struct _NMLinuxPlatform NMLinuxPlatform; -typedef struct _NMLinuxPlatformClass NMLinuxPlatformClass; - -GType nm_linux_platform_get_type(void); - -NMPlatform *nm_linux_platform_new(gboolean log_with_ptr, gboolean netns_support); - -void nm_linux_platform_setup(void); - -#endif /* __NETWORKMANAGER_LINUX_PLATFORM_H__ */ diff --git a/src/core/platform/nm-platform-private.h b/src/core/platform/nm-platform-private.h deleted file mode 100644 index cf805689..00000000 --- a/src/core/platform/nm-platform-private.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#ifndef __NM_PLATFORM_PRIVATE_H__ -#define __NM_PLATFORM_PRIVATE_H__ - -#include "nm-platform.h" -#include "nmp-object.h" - -NMPCache *nm_platform_get_cache(NMPlatform *self); - -#define NMTST_ASSERT_PLATFORM_NETNS_CURRENT(platform) \ - G_STMT_START \ - { \ - NMPlatform *_platform = (platform); \ - \ - nm_assert(NM_IS_PLATFORM(_platform)); \ - nm_assert(NM_IN_SET(nm_platform_netns_get(_platform), NULL, nmp_netns_get_current())); \ - } \ - G_STMT_END - -void nm_platform_cache_update_emit_signal(NMPlatform * platform, - NMPCacheOpsType cache_op, - const NMPObject *obj_old, - const NMPObject *obj_new); - -#endif /* __NM_PLATFORM_PRIVATE_H__ */ diff --git a/src/core/platform/nm-platform.c b/src/core/platform/nm-platform.c deleted file mode 100644 index 0e5f8ab5..00000000 --- a/src/core/platform/nm-platform.c +++ /dev/null @@ -1,8966 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2012 - 2018 Red Hat, Inc. - */ - -#include "src/core/nm-default-daemon.h" - -#include "nm-platform.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "nm-utils.h" -#include "nm-core-internal.h" -#include "nm-glib-aux/nm-dedup-multi.h" -#include "nm-udev-aux/nm-udev-utils.h" -#include "nm-glib-aux/nm-secret-utils.h" - -#include "nm-core-utils.h" -#include "nm-platform/nm-platform-utils.h" -#include "nm-platform-private.h" -#include "nmp-object.h" -#include "nm-platform/nmp-netns.h" - -/*****************************************************************************/ - -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)); - -G_STATIC_ASSERT(_nm_alignof(NMPlatformIPRoute) == _nm_alignof(NMPlatformIP4Route)); -G_STATIC_ASSERT(_nm_alignof(NMPlatformIPRoute) == _nm_alignof(NMPlatformIP6Route)); -G_STATIC_ASSERT(_nm_alignof(NMPlatformIPRoute) == _nm_alignof(NMPlatformIPXRoute)); - -G_STATIC_ASSERT(_nm_alignof(NMPlatformIPAddress) == _nm_alignof(NMPlatformIP4Address)); -G_STATIC_ASSERT(_nm_alignof(NMPlatformIPAddress) == _nm_alignof(NMPlatformIP6Address)); -G_STATIC_ASSERT(_nm_alignof(NMPlatformIPAddress) == _nm_alignof(NMPlatformIPXAddress)); - -/*****************************************************************************/ - -G_STATIC_ASSERT(sizeof(((NMPLinkAddress *) NULL)->data) == NM_UTILS_HWADDR_LEN_MAX); -G_STATIC_ASSERT(sizeof(((NMPlatformLink *) NULL)->l_address.data) == NM_UTILS_HWADDR_LEN_MAX); -G_STATIC_ASSERT(sizeof(((NMPlatformLink *) NULL)->l_broadcast.data) == NM_UTILS_HWADDR_LEN_MAX); - -static const char * -_nmp_link_address_to_string(const NMPLinkAddress *addr, - char buf[static(NM_UTILS_HWADDR_LEN_MAX * 3)]) -{ - nm_assert(addr); - - if (addr->len > 0) { - if (!_nm_utils_hwaddr_ntoa(addr->data, addr->len, TRUE, buf, NM_UTILS_HWADDR_LEN_MAX * 3)) { - buf[0] = '\0'; - g_return_val_if_reached(buf); - } - } else - buf[0] = '\0'; - - return buf; -} - -gconstpointer -nmp_link_address_get(const NMPLinkAddress *addr, size_t *length) -{ - if (!addr || addr->len <= 0) { - NM_SET_OUT(length, 0); - return NULL; - } - - if (addr->len > NM_UTILS_HWADDR_LEN_MAX) { - NM_SET_OUT(length, 0); - g_return_val_if_reached(NULL); - } - - NM_SET_OUT(length, addr->len); - return addr->data; -} - -GBytes * -nmp_link_address_get_as_bytes(const NMPLinkAddress *addr) -{ - gconstpointer data; - size_t length; - - data = nmp_link_address_get(addr, &length); - - return length > 0 ? g_bytes_new(data, length) : NULL; -} - -/*****************************************************************************/ - -#define _NMLOG_DOMAIN LOGD_PLATFORM -#define _NMLOG_PREFIX_NAME "platform" - -#define NMLOG_COMMON(level, name, ...) \ - char __prefix[32]; \ - const char * __p_prefix = _NMLOG_PREFIX_NAME; \ - const NMPlatform *const __self = (self); \ - const char * __name = name; \ - \ - if (__self && NM_PLATFORM_GET_PRIVATE(__self)->log_with_ptr) { \ - g_snprintf(__prefix, sizeof(__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \ - __p_prefix = __prefix; \ - } \ - _nm_log(__level, \ - _NMLOG_DOMAIN, \ - 0, \ - __name, \ - NULL, \ - "%s: %s%s%s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - __p_prefix, \ - NM_PRINT_FMT_QUOTED(__name, "(", __name, ") ", "") _NM_UTILS_MACRO_REST(__VA_ARGS__)); - -#define _NMLOG(level, ...) \ - G_STMT_START \ - { \ - const NMLogLevel __level = (level); \ - \ - if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) { \ - NMLOG_COMMON(level, NULL, __VA_ARGS__); \ - } \ - } \ - G_STMT_END - -#define _NMLOG2(level, ...) \ - G_STMT_START \ - { \ - const NMLogLevel __level = (level); \ - \ - if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) { \ - NMLOG_COMMON(level, name, __VA_ARGS__); \ - } \ - } \ - G_STMT_END - -#define _NMLOG3(level, ...) \ - G_STMT_START \ - { \ - const NMLogLevel __level = (level); \ - \ - if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) { \ - NMLOG_COMMON(level, \ - ifindex > 0 ? nm_platform_link_get_name(self, ifindex) : NULL, \ - __VA_ARGS__); \ - } \ - } \ - G_STMT_END - -/*****************************************************************************/ - -static guint signals[_NM_PLATFORM_SIGNAL_ID_LAST] = {0}; - -enum { - PROP_0, - PROP_NETNS_SUPPORT, - PROP_USE_UDEV, - PROP_LOG_WITH_PTR, - LAST_PROP, -}; - -typedef struct _NMPlatformPrivate { - bool use_udev : 1; - bool log_with_ptr : 1; - - guint ip4_dev_route_blacklist_check_id; - guint ip4_dev_route_blacklist_gc_timeout_id; - GHashTable * ip4_dev_route_blacklist_hash; - NMDedupMultiIndex *multi_idx; - NMPCache * cache; -} NMPlatformPrivate; - -G_DEFINE_TYPE(NMPlatform, nm_platform, G_TYPE_OBJECT) - -#define NM_PLATFORM_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMPlatform, NM_IS_PLATFORM) - -/*****************************************************************************/ - -static void _ip4_dev_route_blacklist_schedule(NMPlatform *self); - -/*****************************************************************************/ - -gboolean -nm_platform_get_use_udev(NMPlatform *self) -{ - return NM_PLATFORM_GET_PRIVATE(self)->use_udev; -} - -gboolean -nm_platform_get_log_with_ptr(NMPlatform *self) -{ - return NM_PLATFORM_GET_PRIVATE(self)->log_with_ptr; -} - -/*****************************************************************************/ - -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_REGISTER(NMPlatform); - -/* Just always initialize a @klass instance. NM_PLATFORM_GET_CLASS() - * is only a plain read on the self instance, which the compiler - * like can optimize out. - */ -#define _CHECK_SELF_VOID(self, klass) \ - NMPlatformClass *klass; \ - do { \ - g_return_if_fail(NM_IS_PLATFORM(self)); \ - klass = NM_PLATFORM_GET_CLASS(self); \ - (void) klass; \ - } while (0) - -#define _CHECK_SELF(self, klass, err_val) \ - NMPlatformClass *klass; \ - do { \ - g_return_val_if_fail(NM_IS_PLATFORM(self), err_val); \ - klass = NM_PLATFORM_GET_CLASS(self); \ - (void) klass; \ - } while (0) - -#define _CHECK_SELF_NETNS(self, klass, netns, err_val) \ - nm_auto_pop_netns NMPNetns *netns = NULL; \ - NMPlatformClass * klass; \ - do { \ - g_return_val_if_fail(NM_IS_PLATFORM(self), err_val); \ - klass = NM_PLATFORM_GET_CLASS(self); \ - (void) klass; \ - if (!nm_platform_netns_push(self, &netns)) \ - return (err_val); \ - } while (0) - -/** - * nm_platform_setup: - * @instance: the #NMPlatform instance - * - * Failing to set up #NMPlatform singleton results in a fatal error, - * as well as trying to initialize it multiple times without freeing - * it. - * - * NetworkManager will typically use only one platform object during - * its run. Test programs might want to switch platform implementations, - * though. - */ -void -nm_platform_setup(NMPlatform *instance) -{ - g_return_if_fail(NM_IS_PLATFORM(instance)); - g_return_if_fail(!singleton_instance); - - singleton_instance = instance; - - nm_singleton_instance_register(); - - nm_log_dbg(LOGD_CORE, - "setup %s singleton (" NM_HASH_OBFUSCATE_PTR_FMT ")", - "NMPlatform", - NM_HASH_OBFUSCATE_PTR(instance)); -} - -/** - * nm_platform_get: - * @self: platform instance - * - * Retrieve #NMPlatform singleton. Use this whenever you want to connect to - * #NMPlatform signals. It is an error to call it before nm_platform_setup(). - * - * Returns: (transfer none): The #NMPlatform singleton reference. - */ -NMPlatform * -nm_platform_get() -{ - g_assert(singleton_instance); - - return singleton_instance; -} - -/*****************************************************************************/ - -NMDedupMultiIndex * -nm_platform_get_multi_idx(NMPlatform *self) -{ - g_return_val_if_fail(NM_IS_PLATFORM(self), NULL); - - return NM_PLATFORM_GET_PRIVATE(self)->multi_idx; -} - -/*****************************************************************************/ - -static NM_UTILS_LOOKUP_STR_DEFINE( - _nmp_nlm_flag_to_string_lookup, - NMPNlmFlags, - NM_UTILS_LOOKUP_DEFAULT(NULL), - NM_UTILS_LOOKUP_ITEM(NMP_NLM_FLAG_ADD, "add"), - NM_UTILS_LOOKUP_ITEM(NMP_NLM_FLAG_CHANGE, "change"), - NM_UTILS_LOOKUP_ITEM(NMP_NLM_FLAG_REPLACE, "replace"), - NM_UTILS_LOOKUP_ITEM(NMP_NLM_FLAG_PREPEND, "prepend"), - NM_UTILS_LOOKUP_ITEM(NMP_NLM_FLAG_APPEND, "append"), - NM_UTILS_LOOKUP_ITEM(NMP_NLM_FLAG_TEST, "test"), - NM_UTILS_LOOKUP_ITEM_IGNORE(NMP_NLM_FLAG_F_APPEND), - NM_UTILS_LOOKUP_ITEM_IGNORE(NMP_NLM_FLAG_FMASK), - NM_UTILS_LOOKUP_ITEM_IGNORE(NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE), - NM_UTILS_LOOKUP_ITEM_IGNORE(NMP_NLM_FLAG_F_ECHO), ); - -#define _nmp_nlm_flag_to_string(flags) \ - ({ \ - NMPNlmFlags _flags = (flags); \ - \ - _nmp_nlm_flag_to_string_lookup(flags) \ - ?: nm_sprintf_bufa(100, "new[0x%x]", (unsigned) _flags); \ - }) - -/*****************************************************************************/ - -volatile int _nm_platform_kernel_support_state[_NM_PLATFORM_KERNEL_SUPPORT_NUM] = {}; - -static const struct { - bool compile_time_default; - const char *name; - const char *desc; -} _nm_platform_kernel_support_info[_NM_PLATFORM_KERNEL_SUPPORT_NUM] = { - [NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS] = - { - .compile_time_default = TRUE, - .name = "EXTENDED_IFA_FLAGS", - .desc = "IPv6 temporary addresses support", - }, - [NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL] = - { - .compile_time_default = TRUE, - .name = "USER_IPV6LL", - .desc = "IFLA_INET6_ADDR_GEN_MODE support", - }, - [NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF] = - { - .compile_time_default = (RTA_MAX >= 20 /* RTA_PREF */), - .name = "RTA_PREF", - .desc = "ability to set router preference for IPv6 routes", - }, - [NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_L3MDEV] = - { - .compile_time_default = (FRA_MAX >= 19 /* FRA_L3MDEV */), - .name = "FRA_L3MDEV", - .desc = "FRA_L3MDEV attribute for policy routing rules", - }, - [NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_UID_RANGE] = - { - .compile_time_default = (FRA_MAX >= 20 /* FRA_UID_RANGE */), - .name = "FRA_UID_RANGE", - .desc = "FRA_UID_RANGE attribute for policy routing rules", - }, - [NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_PROTOCOL] = - { - .compile_time_default = (FRA_MAX >= 21 /* FRA_PROTOCOL */), - .name = "FRA_PROTOCOL", - .desc = "FRA_PROTOCOL attribute for policy routing rules", - }, - [NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_IP_PROTO] = - { - .compile_time_default = (FRA_MAX >= 22 /* FRA_IP_PROTO */), - .name = "FRA_IP_PROTO", - .desc = "FRA_IP_PROTO, FRA_SPORT_RANGE, FRA_DPORT_RANGE attributes for policy routing " - "rules", - }, - [NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_BR_VLAN_STATS_ENABLED] = - { - .compile_time_default = (IFLA_BR_MAX >= 41 /* IFLA_BR_VLAN_STATS_ENABLED */), - .name = "IFLA_BR_VLAN_STATS_ENABLE", - .desc = "IFLA_BR_VLAN_STATS_ENABLE bridge link attribute", - }, -}; - -int -_nm_platform_kernel_support_init(NMPlatformKernelSupportType type, int value) -{ - volatile int *p_state; - gboolean set_default = FALSE; - - nm_assert(_NM_INT_NOT_NEGATIVE(type) && type < G_N_ELEMENTS(_nm_platform_kernel_support_state)); - - p_state = &_nm_platform_kernel_support_state[type]; - - if (value == 0) { - set_default = TRUE; - value = _nm_platform_kernel_support_info[type].compile_time_default ? 1 : -1; - } - - nm_assert(NM_IN_SET(value, -1, 1)); - - if (!g_atomic_int_compare_and_exchange(p_state, 0, value)) { - value = g_atomic_int_get(p_state); - nm_assert(NM_IN_SET(value, -1, 1)); - return value; - } - -#undef NM_THREAD_SAFE_ON_MAIN_THREAD -#define NM_THREAD_SAFE_ON_MAIN_THREAD 0 - - if (set_default) { - nm_log_dbg(LOGD_PLATFORM, - "platform: kernel-support for %s (%s) not detected: assume %ssupported", - _nm_platform_kernel_support_info[type].name, - _nm_platform_kernel_support_info[type].desc, - value >= 0 ? "" : "not "); - } else { - nm_log_dbg(LOGD_PLATFORM, - "platform: kernel-support for %s (%s) detected: %ssupported", - _nm_platform_kernel_support_info[type].name, - _nm_platform_kernel_support_info[type].desc, - value >= 0 ? "" : "not "); - } - -#undef NM_THREAD_SAFE_ON_MAIN_THREAD -#define NM_THREAD_SAFE_ON_MAIN_THREAD 1 - - return value; -} - -/*****************************************************************************/ - -/** - * nm_platform_process_events: - * @self: platform instance - * - * Process pending events or handle pending delayed-actions. - * Effectively, this reads the netlink socket and processes - * new netlink messages. Possibly it will raise change signals. - */ -void -nm_platform_process_events(NMPlatform *self) -{ - _CHECK_SELF_VOID(self, klass); - - if (klass->process_events) - klass->process_events(self); -} - -const NMPlatformLink * -nm_platform_process_events_ensure_link(NMPlatform *self, int ifindex, const char *ifname) -{ - const NMPObject *obj; - gboolean refreshed = FALSE; - - g_return_val_if_fail(NM_IS_PLATFORM(self), NULL); - - if (ifindex <= 0 && !ifname) - return NULL; - - /* we look into the cache, whether a link for given ifindex/ifname - * exits. If not, we poll the netlink socket, maybe the event - * with the link is waiting. - * - * Then we try again to find the object. - * - * If the link is already cached the first time, we avoid polling - * the netlink socket. */ -again: - obj = nmp_cache_lookup_link_full( - nm_platform_get_cache(self), - ifindex, - ifname, - FALSE, /* also invisible. We don't care here whether udev is ready */ - NM_LINK_TYPE_NONE, - NULL, - NULL); - if (obj) - return NMP_OBJECT_CAST_LINK(obj); - if (!refreshed) { - refreshed = TRUE; - nm_platform_process_events(self); - goto again; - } - - return NULL; -} - -/*****************************************************************************/ - -/** - * nm_platform_sysctl_open_netdir: - * @self: platform instance - * @ifindex: the ifindex for which to open /sys/class/net/%s - * @out_ifname: optional output argument of the found ifname. - * - * Wraps nmp_utils_sysctl_open_netdir() by first changing into the right - * network-namespace. - * - * Returns: on success, the open file descriptor to the /sys/class/net/%s - * directory. - */ -int -nm_platform_sysctl_open_netdir(NMPlatform *self, int ifindex, char *out_ifname) -{ - const char *ifname_guess; - _CHECK_SELF_NETNS(self, klass, netns, -1); - - g_return_val_if_fail(ifindex > 0, -1); - - /* we don't have an @ifname_guess argument to make the API nicer. - * But still do a cache-lookup first. Chances are good that we have - * the right ifname cached and save if_indextoname() */ - ifname_guess = nm_platform_link_get_name(self, ifindex); - - return nmp_utils_sysctl_open_netdir(ifindex, ifname_guess, out_ifname); -} - -/** - * nm_platform_sysctl_set: - * @self: platform instance - * @pathid: if @dirfd is present, this must be the full path that is looked up. - * It is required for logging. - * @dirfd: optional file descriptor for parent directory for openat() - * @path: Absolute option path - * @value: Value to write - * - * This function is intended to be used for writing values to sysctl-style - * virtual runtime configuration files. This includes not only /proc/sys - * but also for example /sys/class. - * - * Returns: %TRUE on success. - */ -gboolean -nm_platform_sysctl_set(NMPlatform *self, - const char *pathid, - int dirfd, - const char *path, - const char *value) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(path, FALSE); - g_return_val_if_fail(value, FALSE); - - return klass->sysctl_set(self, pathid, dirfd, path, value); -} - -/** - * nm_platform_sysctl_set_async: - * @self: platform instance - * @pathid: if @dirfd is present, this must be the full path that is looked up - * @dirfd: optional file descriptor for parent directory for openat() - * @path: absolute option path - * @values: NULL-terminated array of strings to be written - * @callback: function called on termination - * @data: data passed to callback function - * @cancellable: to cancel the operation - * - * This function is intended to be used for writing values to sysctl-style - * virtual runtime configuration files. This includes not only /proc/sys - * but also for example /sys/class. The function does not block and returns - * immediately. The callback is always invoked, and asynchronously. The file - * is closed after writing each value and reopened to write the next one so - * that the function can be used safely on all /proc and /sys files, - * independently of how /proc/sys/kernel/sysctl_writes_strict is configured. - */ -void -nm_platform_sysctl_set_async(NMPlatform * self, - const char * pathid, - int dirfd, - const char * path, - const char *const * values, - NMPlatformAsyncCallback callback, - gpointer data, - GCancellable * cancellable) -{ - _CHECK_SELF_VOID(self, klass); - - klass->sysctl_set_async(self, pathid, dirfd, path, values, callback, data, cancellable); -} - -gboolean -nm_platform_sysctl_ip_conf_set_ipv6_hop_limit_safe(NMPlatform *self, const char *iface, int value) -{ - const char *path; - gint64 cur; - char buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE]; - - _CHECK_SELF(self, klass, FALSE); - - /* the hop-limit provided via RA is uint8. */ - if (value > 0xFF) - return FALSE; - - /* don't allow unreasonable small values */ - if (value < 10) - return FALSE; - - path = nm_utils_sysctl_ip_conf_path(AF_INET6, buf, iface, "hop_limit"); - cur = nm_platform_sysctl_get_int_checked(self, - NMP_SYSCTL_PATHID_ABSOLUTE(path), - 10, - 1, - G_MAXINT32, - -1); - - /* only allow increasing the hop-limit to avoid DOS by an attacker - * setting a low hop-limit (CVE-2015-2924, rh#1209902) */ - - if (value < cur) - return FALSE; - if (value != cur) { - char svalue[20]; - - sprintf(svalue, "%d", value); - nm_platform_sysctl_set(self, NMP_SYSCTL_PATHID_ABSOLUTE(path), svalue); - } - - return TRUE; -} - -gboolean -nm_platform_sysctl_ip_neigh_set_ipv6_reachable_time(NMPlatform *self, - const char *iface, - guint value_ms) -{ - char path[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE]; - char str[128]; - guint clamped; - - _CHECK_SELF(self, klass, FALSE); - - if (!value_ms) - return TRUE; - - /* RFC 4861 says the value can't be greater than one hour. - * Also use a reasonable lower threshold. */ - clamped = NM_CLAMP(value_ms, 100, 3600000); - nm_sprintf_buf(path, "/proc/sys/net/ipv6/neigh/%s/base_reachable_time_ms", iface); - nm_sprintf_buf(str, "%u", clamped); - if (!nm_platform_sysctl_set(self, NMP_SYSCTL_PATHID_ABSOLUTE(path), str)) - return FALSE; - - /* Set stale time in the same way as kernel */ - nm_sprintf_buf(path, "/proc/sys/net/ipv6/neigh/%s/gc_stale_time", iface); - nm_sprintf_buf(str, "%u", clamped * 3 / 1000); - - return nm_platform_sysctl_set(self, NMP_SYSCTL_PATHID_ABSOLUTE(path), str); -} - -gboolean -nm_platform_sysctl_ip_neigh_set_ipv6_retrans_time(NMPlatform *self, - const char *iface, - guint value_ms) -{ - char path[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE]; - char str[128]; - - _CHECK_SELF(self, klass, FALSE); - - if (!value_ms) - return TRUE; - - nm_sprintf_buf(path, "/proc/sys/net/ipv6/neigh/%s/retrans_time_ms", iface); - nm_sprintf_buf(str, "%u", NM_CLAMP(value_ms, 10, 3600000)); - - return nm_platform_sysctl_set(self, NMP_SYSCTL_PATHID_ABSOLUTE(path), str); -} - -/** - * nm_platform_sysctl_get: - * @self: platform instance - * @dirfd: if non-negative, used to lookup the path via openat(). - * @pathid: if @dirfd is present, this must be the full path that is looked up. - * It is required for logging. - * @path: Absolute path to sysctl - * - * Returns: (transfer full): Contents of the virtual sysctl file. - * - * If the path does not exist, %NULL is returned and %errno set to %ENOENT. - */ -char * -nm_platform_sysctl_get(NMPlatform *self, const char *pathid, int dirfd, const char *path) -{ - _CHECK_SELF(self, klass, NULL); - - g_return_val_if_fail(path, NULL); - - return klass->sysctl_get(self, pathid, dirfd, path); -} - -/** - * nm_platform_sysctl_get_int32: - * @self: platform instance - * @pathid: if @dirfd is present, this must be the full path that is looked up. - * It is required for logging. - * @dirfd: if non-negative, used to lookup the path via openat(). - * @path: Absolute path to sysctl - * @fallback: default value, if the content of path could not be read - * as decimal integer. - * - * Returns: contents of the sysctl file parsed as s32 integer, or - * @fallback on error. On error, %errno will be set to a non-zero - * value, on success %errno will be set to zero. - */ -gint32 -nm_platform_sysctl_get_int32(NMPlatform *self, - const char *pathid, - int dirfd, - const char *path, - gint32 fallback) -{ - return nm_platform_sysctl_get_int_checked(self, - pathid, - dirfd, - path, - 10, - G_MININT32, - G_MAXINT32, - fallback); -} - -/** - * nm_platform_sysctl_get_int_checked: - * @self: platform instance - * @pathid: if @dirfd is present, this must be the full path that is looked up. - * It is required for logging. - * @dirfd: if non-negative, used to lookup the path via openat(). - * @path: Absolute path to sysctl - * @base: base of numeric conversion - * @min: minimal value that is still valid - * @max: maximal value that is still valid - * @fallback: default value, if the content of path could not be read - * as valid integer. - * - * Returns: contents of the sysctl file parsed as s64 integer, or - * @fallback on error. On error, %errno will be set to a non-zero - * value. On success, %errno will be set to zero. The returned value - * will always be in the range between @min and @max - * (inclusive) or @fallback. - * If the file does not exist, the fallback is returned and %errno - * is set to ENOENT. - */ -gint64 -nm_platform_sysctl_get_int_checked(NMPlatform *self, - const char *pathid, - int dirfd, - const char *path, - guint base, - gint64 min, - gint64 max, - gint64 fallback) -{ - char * value = NULL; - gint32 ret; - int errsv; - - _CHECK_SELF(self, klass, fallback); - - g_return_val_if_fail(path, fallback); - - if (!path) { - errno = EINVAL; - return fallback; - } - - value = nm_platform_sysctl_get(self, pathid, dirfd, path); - if (!value) { - /* nm_platform_sysctl_get() set errno to ENOENT if the file does not exist. - * Propagate/preserve that. */ - if (errno != ENOENT) - errno = EINVAL; - return fallback; - } - - ret = _nm_utils_ascii_str_to_int64(value, base, min, max, fallback); - errsv = errno; - g_free(value); - errno = errsv; - return ret; -} - -/*****************************************************************************/ - -char * -nm_platform_sysctl_ip_conf_get(NMPlatform *self, - int addr_family, - const char *ifname, - const char *property) -{ - char buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE]; - - return nm_platform_sysctl_get( - self, - NMP_SYSCTL_PATHID_ABSOLUTE( - nm_utils_sysctl_ip_conf_path(addr_family, buf, ifname, property))); -} - -gint64 -nm_platform_sysctl_ip_conf_get_int_checked(NMPlatform *self, - int addr_family, - const char *ifname, - const char *property, - guint base, - gint64 min, - gint64 max, - gint64 fallback) -{ - char buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE]; - - return nm_platform_sysctl_get_int_checked( - self, - NMP_SYSCTL_PATHID_ABSOLUTE( - nm_utils_sysctl_ip_conf_path(addr_family, buf, ifname, property)), - base, - min, - max, - fallback); -} - -gboolean -nm_platform_sysctl_ip_conf_set(NMPlatform *self, - int addr_family, - const char *ifname, - const char *property, - const char *value) -{ - char buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE]; - - return nm_platform_sysctl_set( - self, - NMP_SYSCTL_PATHID_ABSOLUTE( - nm_utils_sysctl_ip_conf_path(addr_family, buf, ifname, property)), - value); -} - -gboolean -nm_platform_sysctl_ip_conf_set_int64(NMPlatform *self, - int addr_family, - const char *ifname, - const char *property, - gint64 value) -{ - char buf[NM_UTILS_SYSCTL_IP_CONF_PATH_BUFSIZE]; - char s[64]; - - return nm_platform_sysctl_set( - self, - NMP_SYSCTL_PATHID_ABSOLUTE( - nm_utils_sysctl_ip_conf_path(addr_family, buf, ifname, property)), - nm_sprintf_buf(s, "%" G_GINT64_FORMAT, value)); -} - -int -nm_platform_sysctl_ip_conf_get_rp_filter_ipv4(NMPlatform *self, - const char *ifname, - gboolean consider_all, - gboolean * out_due_to_all) -{ - int val, val_all; - - NM_SET_OUT(out_due_to_all, FALSE); - - if (!ifname) - return -1; - - val = nm_platform_sysctl_ip_conf_get_int_checked(self, - AF_INET, - ifname, - "rp_filter", - 10, - 0, - 2, - -1); - if (val == -1) - return -1; - - /* the effectively used value is the rp_filter sysctl value of MAX(all,ifname). - * Note that this is the numerical MAX(), despite rp_filter "1" being more strict - * than "2". */ - if (val < 2 && consider_all && !nm_streq(ifname, "all")) { - val_all = nm_platform_sysctl_ip_conf_get_int_checked(self, - AF_INET, - "all", - "rp_filter", - 10, - 0, - 2, - val); - if (val_all > val) { - val = val_all; - NM_SET_OUT(out_due_to_all, TRUE); - } - } - - return val; -} - -/*****************************************************************************/ - -static int -_link_get_all_presort(gconstpointer p_a, gconstpointer p_b, gpointer sort_by_name) -{ - const NMPlatformLink *a = NMP_OBJECT_CAST_LINK(*((const NMPObject **) p_a)); - const NMPlatformLink *b = NMP_OBJECT_CAST_LINK(*((const NMPObject **) p_b)); - - /* Loopback always first */ - if (a->ifindex == 1) - return -1; - if (b->ifindex == 1) - return 1; - - if (GPOINTER_TO_INT(sort_by_name)) { - /* Initialized links first */ - if (a->initialized > b->initialized) - return -1; - if (a->initialized < b->initialized) - return 1; - - return strcmp(a->name, b->name); - } else - return a->ifindex - b->ifindex; -} - -/** - * nm_platform_link_get_all: - * @self: platform instance - * @sort_by_name: whether to sort by name or ifindex. - * - * Retrieve a snapshot of configuration for all links at once. The result is - * owned by the caller and should be freed with g_ptr_array_unref(). - */ -GPtrArray * -nm_platform_link_get_all(NMPlatform *self, gboolean sort_by_name) -{ - gs_unref_ptrarray GPtrArray *links = NULL; - GPtrArray * result; - guint i, nresult; - gs_unref_hashtable GHashTable *unseen = NULL; - const NMPlatformLink * item; - NMPLookup lookup; - - _CHECK_SELF(self, klass, NULL); - - nmp_lookup_init_obj_type(&lookup, NMP_OBJECT_TYPE_LINK); - links = nm_dedup_multi_objs_to_ptr_array_head(nm_platform_lookup(self, &lookup), NULL, NULL); - if (!links) - return NULL; - - for (i = 0; i < links->len;) { - if (!nmp_object_is_visible(links->pdata[i])) - g_ptr_array_remove_index_fast(links, i); - else - i++; - } - - if (links->len == 0) - return NULL; - - /* first sort the links by their ifindex or name. Below we will sort - * further by moving children/slaves to the end. */ - g_ptr_array_sort_with_data(links, _link_get_all_presort, GINT_TO_POINTER(sort_by_name)); - - unseen = g_hash_table_new(nm_direct_hash, NULL); - for (i = 0; i < links->len; i++) { - item = NMP_OBJECT_CAST_LINK(links->pdata[i]); - nm_assert(item->ifindex > 0); - if (!g_hash_table_insert(unseen, GINT_TO_POINTER(item->ifindex), NULL)) - nm_assert_not_reached(); - } - -#if NM_MORE_ASSERTS - /* Ensure that link_get_all returns a consistent and valid result. */ - for (i = 0; i < links->len; i++) { - item = NMP_OBJECT_CAST_LINK(links->pdata[i]); - - if (!item->ifindex) - continue; - if (item->master != 0) { - g_warn_if_fail(item->master > 0); - g_warn_if_fail(item->master != item->ifindex); - g_warn_if_fail(g_hash_table_contains(unseen, GINT_TO_POINTER(item->master))); - } - if (item->parent != 0) { - 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(g_hash_table_contains(unseen, GINT_TO_POINTER(item->parent))); - } - } - } -#endif - - /* Re-order the links list such that children/slaves come after all ancestors */ - nm_assert(g_hash_table_size(unseen) == links->len); - nresult = links->len; - result = g_ptr_array_new_full(nresult, (GDestroyNotify) nmp_object_unref); - - while (TRUE) { - gboolean found_something = FALSE; - guint first_idx = G_MAXUINT; - - for (i = 0; i < links->len; i++) { - item = NMP_OBJECT_CAST_LINK(links->pdata[i]); - - if (!item) - continue; - - g_assert(g_hash_table_contains(unseen, GINT_TO_POINTER(item->ifindex))); - - if (item->master > 0 && g_hash_table_contains(unseen, GINT_TO_POINTER(item->master))) - goto skip; - if (item->parent > 0 && g_hash_table_contains(unseen, GINT_TO_POINTER(item->parent))) - goto skip; - - g_hash_table_remove(unseen, GINT_TO_POINTER(item->ifindex)); - g_ptr_array_add(result, links->pdata[i]); - links->pdata[i] = NULL; - found_something = TRUE; - continue; -skip: - if (first_idx == G_MAXUINT) - first_idx = i; - } - - if (found_something) { - if (first_idx == G_MAXUINT) - break; - } else { - nm_assert(first_idx != G_MAXUINT); - /* There is a loop, pop the first (remaining) element from the list. - * This can happen for veth pairs where each peer is parent of the other end. */ - item = NMP_OBJECT_CAST_LINK(links->pdata[first_idx]); - nm_assert(item); - g_hash_table_remove(unseen, GINT_TO_POINTER(item->ifindex)); - g_ptr_array_add(result, links->pdata[first_idx]); - links->pdata[first_idx] = NULL; - } - nm_assert(result->len < nresult); - } - nm_assert(result->len == nresult); - - return result; -} - -/*****************************************************************************/ - -const NMPObject * -nm_platform_link_get_obj(NMPlatform *self, int ifindex, gboolean visible_only) -{ - const NMPObject *obj_cache; - - _CHECK_SELF(self, klass, NULL); - - obj_cache = nmp_cache_lookup_link(nm_platform_get_cache(self), ifindex); - if (!obj_cache || (visible_only && !nmp_object_is_visible(obj_cache))) - return NULL; - return obj_cache; -} - -/*****************************************************************************/ - -/** - * nm_platform_link_get: - * @self: platform instance - * @ifindex: ifindex of the link - * - * Lookup the internal NMPlatformLink object. - * - * Returns: %NULL, if such a link exists or the internal - * platform link object. Do not modify the returned value. - * Also, be aware that any subsequent platform call might - * invalidate/modify the returned instance. - **/ -const NMPlatformLink * -nm_platform_link_get(NMPlatform *self, int ifindex) -{ - return NMP_OBJECT_CAST_LINK(nm_platform_link_get_obj(self, ifindex, TRUE)); -} - -/** - * nm_platform_link_get_by_ifname: - * @self: platform instance - * @ifname: the ifname - * - * Returns: the first #NMPlatformLink instance with the given name. - **/ -const NMPlatformLink * -nm_platform_link_get_by_ifname(NMPlatform *self, const char *ifname) -{ - const NMPObject *obj; - - _CHECK_SELF(self, klass, NULL); - - if (!ifname || !*ifname) - return NULL; - - obj = nmp_cache_lookup_link_full(nm_platform_get_cache(self), - 0, - ifname, - TRUE, - NM_LINK_TYPE_NONE, - NULL, - NULL); - return NMP_OBJECT_CAST_LINK(obj); -} - -struct _nm_platform_link_get_by_address_data { - gconstpointer data; - guint8 len; -}; - -static gboolean -_nm_platform_link_get_by_address_match_link(const NMPObject * obj, - struct _nm_platform_link_get_by_address_data *d) -{ - return obj->link.l_address.len == d->len && !memcmp(obj->link.l_address.data, d->data, d->len); -} - -/** - * nm_platform_link_get_by_address: - * @self: platform instance - * @address: a pointer to the binary hardware address - * @length: the size of @address in bytes - * - * Returns: the first #NMPlatformLink object with a matching - * address. - **/ -const NMPlatformLink * -nm_platform_link_get_by_address(NMPlatform * self, - NMLinkType link_type, - gconstpointer address, - size_t length) -{ - const NMPObject * obj; - struct _nm_platform_link_get_by_address_data d = { - .data = address, - .len = length, - }; - - _CHECK_SELF(self, klass, NULL); - - if (length == 0) - return NULL; - - if (length > NM_UTILS_HWADDR_LEN_MAX) - g_return_val_if_reached(NULL); - if (!address) - g_return_val_if_reached(NULL); - - obj = nmp_cache_lookup_link_full(nm_platform_get_cache(self), - 0, - NULL, - TRUE, - link_type, - (NMPObjectMatchFn) _nm_platform_link_get_by_address_match_link, - &d); - return NMP_OBJECT_CAST_LINK(obj); -} - -static int -_link_add_check_existing(NMPlatform * self, - const char * name, - NMLinkType type, - const NMPlatformLink **out_link) -{ - const NMPlatformLink *pllink; - - pllink = nm_platform_link_get_by_ifname(self, name); - if (pllink) { - gboolean wrong_type; - - wrong_type = type != NM_LINK_TYPE_NONE && pllink->type != type; - _LOG2D("link: skip adding link due to existing interface of type %s%s%s", - nm_link_type_to_string(pllink->type), - wrong_type ? ", expected " : "", - wrong_type ? nm_link_type_to_string(type) : ""); - if (out_link) - *out_link = pllink; - if (wrong_type) - return -NME_PL_WRONG_TYPE; - return -NME_PL_EXISTS; - } - if (out_link) - *out_link = NULL; - return 0; -} - -/** - * nm_platform_link_add: - * @self: platform instance - * @type: Interface type - * @name: Interface name - * @parent: the IFLA_LINK parameter or 0. - * @address: (allow-none): set the mac address of the link - * @address_len: the length of the @address - * @extra_data: depending on @type, additional data. - * @out_link: on success, the link object - * - * Add a software interface. If the interface already exists and is of type - * @type, return -NME_PL_EXISTS and returns the link - * in @out_link. If the interface already exists and is not of type @type, - * return -NME_PL_WRONG_TYPE. - * - * Any link-changed ADDED signal will be emitted directly, before this - * function finishes. - * - * Returns: the negative nm-error on failure. - */ -int -nm_platform_link_add(NMPlatform * self, - NMLinkType type, - const char * name, - int parent, - const void * address, - size_t address_len, - guint32 mtu, - gconstpointer extra_data, - const NMPlatformLink **out_link) -{ - int r; - char addr_buf[NM_UTILS_HWADDR_LEN_MAX * 3]; - char mtu_buf[16]; - char parent_buf[64]; - char buf[512]; - - _CHECK_SELF(self, klass, -NME_BUG); - - g_return_val_if_fail(name, -NME_BUG); - g_return_val_if_fail((address != NULL) ^ (address_len == 0), -NME_BUG); - g_return_val_if_fail(address_len <= NM_UTILS_HWADDR_LEN_MAX, -NME_BUG); - g_return_val_if_fail(parent >= 0, -NME_BUG); - - r = _link_add_check_existing(self, name, type, out_link); - if (r < 0) - return r; - - _LOG2D("link: adding link: " - "%s " /* type */ - "\"%s\"" /* name */ - "%s%s" /* parent */ - "%s%s" /* address */ - "%s%s" /* mtu */ - "%s" /* extra_data */ - "", - nm_link_type_to_string(type), - name, - parent > 0 ? ", parent " : "", - parent > 0 ? nm_sprintf_buf(parent_buf, "%d", parent) : "", - address ? ", address: " : "", - address ? _nm_utils_hwaddr_ntoa(address, address_len, FALSE, addr_buf, sizeof(addr_buf)) - : "", - mtu ? ", mtu: " : "", - mtu ? nm_sprintf_buf(mtu_buf, "%u", mtu) : "", - ({ - char *buf_p = buf; - gsize buf_len = sizeof(buf); - - buf[0] = '\0'; - - switch (type) { - case NM_LINK_TYPE_BRIDGE: - nm_utils_strbuf_append_str(&buf_p, &buf_len, ", "); - nm_platform_lnk_bridge_to_string((const NMPlatformLnkBridge *) extra_data, - buf_p, - buf_len); - break; - case NM_LINK_TYPE_VLAN: - nm_utils_strbuf_append_str(&buf_p, &buf_len, ", "); - nm_platform_lnk_vlan_to_string((const NMPlatformLnkVlan *) extra_data, - buf_p, - buf_len); - break; - case NM_LINK_TYPE_VRF: - nm_utils_strbuf_append_str(&buf_p, &buf_len, ", "); - nm_platform_lnk_vrf_to_string((const NMPlatformLnkVrf *) extra_data, - buf_p, - buf_len); - break; - case NM_LINK_TYPE_VXLAN: - nm_utils_strbuf_append_str(&buf_p, &buf_len, ", "); - nm_platform_lnk_vxlan_to_string((const NMPlatformLnkVxlan *) extra_data, - buf_p, - buf_len); - break; - case NM_LINK_TYPE_VETH: - nm_sprintf_buf(buf, ", veth-peer \"%s\"", (const char *) extra_data); - break; - case NM_LINK_TYPE_GRE: - case NM_LINK_TYPE_GRETAP: - nm_utils_strbuf_append_str(&buf_p, &buf_len, ", "); - nm_platform_lnk_gre_to_string((const NMPlatformLnkGre *) extra_data, - buf_p, - buf_len); - break; - case NM_LINK_TYPE_SIT: - nm_utils_strbuf_append_str(&buf_p, &buf_len, ", "); - nm_platform_lnk_sit_to_string((const NMPlatformLnkSit *) extra_data, - buf_p, - buf_len); - break; - case NM_LINK_TYPE_IP6TNL: - case NM_LINK_TYPE_IP6GRE: - case NM_LINK_TYPE_IP6GRETAP: - nm_utils_strbuf_append_str(&buf_p, &buf_len, ", "); - nm_platform_lnk_ip6tnl_to_string((const NMPlatformLnkIp6Tnl *) extra_data, - buf_p, - buf_len); - break; - case NM_LINK_TYPE_IPIP: - nm_utils_strbuf_append_str(&buf_p, &buf_len, ", "); - nm_platform_lnk_ipip_to_string((const NMPlatformLnkIpIp *) extra_data, - buf_p, - buf_len); - break; - case NM_LINK_TYPE_MACSEC: - nm_utils_strbuf_append_str(&buf_p, &buf_len, ", "); - nm_platform_lnk_macsec_to_string((const NMPlatformLnkMacsec *) extra_data, - buf_p, - buf_len); - break; - case NM_LINK_TYPE_MACVLAN: - case NM_LINK_TYPE_MACVTAP: - nm_utils_strbuf_append_str(&buf_p, &buf_len, ", "); - nm_platform_lnk_macvlan_to_string((const NMPlatformLnkMacvlan *) extra_data, - buf_p, - buf_len); - break; - default: - nm_assert(!extra_data); - break; - } - - buf; - })); - - return klass - ->link_add(self, type, name, parent, address, address_len, mtu, extra_data, out_link); -} - -/** - * nm_platform_link_delete: - * @self: platform instance - * @ifindex: Interface index - */ -gboolean -nm_platform_link_delete(NMPlatform *self, int ifindex) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - - _LOG3D("link: deleting"); - return klass->link_delete(self, ifindex); -} - -/** - * nm_platform_link_set_netns: - * @self: platform instance - * @ifindex: Interface index - * @netns_fd: the file descriptor for the new netns. - * - * Returns: %TRUE on success. - */ -gboolean -nm_platform_link_set_netns(NMPlatform *self, int ifindex, int netns_fd) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - g_return_val_if_fail(netns_fd > 0, FALSE); - - _LOG3D("link: move link to network namespace with fd %d", netns_fd); - return klass->link_set_netns(self, ifindex, netns_fd); -} - -/** - * nm_platform_link_get_index: - * @self: platform instance - * @name: Interface name - * - * Returns: The interface index corresponding to the given interface name - * or 0. Interface name is owned by #NMPlatform, don't free it. - */ -int -nm_platform_link_get_ifindex(NMPlatform *self, const char *name) -{ - const NMPlatformLink *pllink; - - pllink = nm_platform_link_get_by_ifname(self, name); - return pllink ? pllink->ifindex : 0; -} - -const char * -nm_platform_if_indextoname(NMPlatform *self, int ifindex, char out_ifname[static 16 /* IFNAMSIZ */]) -{ - _CHECK_SELF_NETNS(self, klass, netns, FALSE); - - return nmp_utils_if_indextoname(ifindex, out_ifname); -} - -int -nm_platform_if_nametoindex(NMPlatform *self, const char *ifname) -{ - _CHECK_SELF_NETNS(self, klass, netns, FALSE); - - return nmp_utils_if_nametoindex(ifname); -} - -/** - * nm_platform_link_get_name: - * @self: platform instance - * @name: Interface name - * - * Returns: The interface name corresponding to the given interface index - * or %NULL. - */ -const char * -nm_platform_link_get_name(NMPlatform *self, int ifindex) -{ - const NMPlatformLink *pllink; - - pllink = nm_platform_link_get(self, ifindex); - return pllink ? pllink->name : NULL; -} - -/** - * nm_platform_link_get_type: - * @self: platform instance - * @ifindex: Interface index. - * - * Returns: Link type constant as defined in nm-platform.h. On error, - * NM_LINK_TYPE_NONE is returned. - */ -NMLinkType -nm_platform_link_get_type(NMPlatform *self, int ifindex) -{ - const NMPlatformLink *pllink; - - pllink = nm_platform_link_get(self, ifindex); - return pllink ? pllink->type : NM_LINK_TYPE_NONE; -} - -/** - * nm_platform_link_get_type_name: - * @self: platform instance - * @ifindex: Interface index. - * - * Returns: A string describing the type of link. In some cases this - * may be more specific than nm_platform_link_get_type(), but in - * other cases it may not. On error, %NULL is returned. - */ -const char * -nm_platform_link_get_type_name(NMPlatform *self, int ifindex) -{ - const NMPObject *obj; - - obj = nm_platform_link_get_obj(self, ifindex, TRUE); - if (!obj) - return NULL; - - if (obj->link.type != NM_LINK_TYPE_UNKNOWN) { - /* We could detect the @link_type. In this case the function returns - * our internal module names, which differs from rtnl_link_get_type(): - * - NM_LINK_TYPE_INFINIBAND (gives "infiniband", instead of "ipoib") - * - NM_LINK_TYPE_TAP (gives "tap", instead of "tun"). - * Note that this functions is only used by NMDeviceGeneric to - * set type_description. */ - return nm_link_type_to_string(obj->link.type); - } - /* Link type not detected. Fallback to rtnl_link_get_type()/IFLA_INFO_KIND. */ - return obj->link.kind ?: "unknown"; -} - -static gboolean -link_get_udev_property(NMPlatform *self, int ifindex, const char *name, const char **out_value) -{ - struct udev_device *udevice = NULL; - const char * uproperty; - - udevice = nm_platform_link_get_udev_device(self, ifindex); - if (!udevice) - return FALSE; - - uproperty = udev_device_get_property_value(udevice, name); - if (!uproperty) - return FALSE; - - NM_SET_OUT(out_value, uproperty); - return TRUE; -} - -/** - * nm_platform_link_get_unmanaged: - * @self: platform instance - * @ifindex: interface index - * @unmanaged: management status (in case %TRUE is returned) - * - * Returns: %TRUE if platform overrides NM default-unmanaged status, - * %FALSE otherwise (with @unmanaged unmodified). - */ -gboolean -nm_platform_link_get_unmanaged(NMPlatform *self, int ifindex, gboolean *unmanaged) -{ - const char *value; - - if (link_get_udev_property(self, ifindex, "NM_UNMANAGED", &value)) { - NM_SET_OUT(unmanaged, nm_udev_utils_property_as_boolean(value)); - return TRUE; - } - - return FALSE; -} - -/** - * nm_platform_link_is_software: - * @self: platform instance - * @ifindex: Interface index. - * - * Returns: %TRUE if ifindex belongs to a software interface, not backed by - * a physical device. - */ -gboolean -nm_platform_link_is_software(NMPlatform *self, int ifindex) -{ - return nm_link_type_is_software(nm_platform_link_get_type(self, ifindex)); -} - -/** - * nm_platform_link_supports_slaves: - * @self: platform instance - * @ifindex: Interface index. - * - * Returns: %TRUE if ifindex belongs to an interface capable of enslaving - * other interfaces. - */ -gboolean -nm_platform_link_supports_slaves(NMPlatform *self, int ifindex) -{ - return nm_link_type_supports_slaves(nm_platform_link_get_type(self, ifindex)); -} - -/** - * nm_platform_link_refresh: - * @self: platform instance - * @ifindex: Interface index - * - * Reload the cache for ifindex synchronously. - */ -gboolean -nm_platform_link_refresh(NMPlatform *self, int ifindex) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - - if (klass->link_refresh) - return klass->link_refresh(self, ifindex); - - return TRUE; -} - -int -nm_platform_link_get_ifi_flags(NMPlatform *self, int ifindex, guint requested_flags) -{ - const NMPlatformLink *pllink; - - /* include invisible links (only in netlink, not udev). */ - pllink = NMP_OBJECT_CAST_LINK(nm_platform_link_get_obj(self, ifindex, FALSE)); - if (!pllink) - return -ENODEV; - - /* Errors are signaled as negative values. That means, you cannot request - * the most significant bit (2^31) with this API. Assert against that. */ - nm_assert((int) requested_flags >= 0); - nm_assert(requested_flags < (guint) G_MAXINT); - - return (int) (pllink->n_ifi_flags & requested_flags); -} - -/** - * nm_platform_link_is_up: - * @self: platform instance - * @ifindex: Interface index - * - * Check if the interface is up. - */ -gboolean -nm_platform_link_is_up(NMPlatform *self, int ifindex) -{ - return nm_platform_link_get_ifi_flags(self, ifindex, IFF_UP) == IFF_UP; -} - -/** - * nm_platform_link_is_connected: - * @self: platform instance - * @ifindex: Interface index - * - * Check if the interface is connected. - */ -gboolean -nm_platform_link_is_connected(NMPlatform *self, int ifindex) -{ - const NMPlatformLink *pllink; - - pllink = nm_platform_link_get(self, ifindex); - return pllink ? pllink->connected : FALSE; -} - -/** - * nm_platform_link_uses_arp: - * @self: platform instance - * @ifindex: Interface index - * - * Check if the interface is configured to use ARP. - */ -gboolean -nm_platform_link_uses_arp(NMPlatform *self, int ifindex) -{ - int f; - - f = nm_platform_link_get_ifi_flags(self, ifindex, IFF_NOARP); - - if (f < 0) - return FALSE; - if (f == IFF_NOARP) - return FALSE; - return TRUE; -} - -/** - * nm_platform_link_set_ipv6_token: - * @self: platform instance - * @ifindex: Interface index - * @iid: Tokenized interface identifier - * - * Sets then IPv6 tokenized interface identifier. - * - * Returns: %TRUE a tokenized identifier was available - */ -gboolean -nm_platform_link_set_ipv6_token(NMPlatform *self, int ifindex, NMUtilsIPv6IfaceId iid) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex >= 0, FALSE); - - if (klass->link_set_token) - return klass->link_set_token(self, ifindex, iid); - return FALSE; -} - -const char * -nm_platform_link_get_udi(NMPlatform *self, int ifindex) -{ - struct udev_device *device; - - device = nm_platform_link_get_udev_device(self, ifindex); - return device ? udev_device_get_syspath(device) : NULL; -} - -const char * -nm_platform_link_get_path(NMPlatform *self, int ifindex) -{ - const char *value = NULL; - - link_get_udev_property(self, ifindex, "ID_PATH", &value); - - return value; -} - -struct udev_device * -nm_platform_link_get_udev_device(NMPlatform *self, int ifindex) -{ - const NMPObject *obj_cache; - - obj_cache = nm_platform_link_get_obj(self, ifindex, FALSE); - return obj_cache ? obj_cache->_link.udev.device : NULL; -} - -/** - * nm_platform_link_get_user_ip6vll_enabled: - * @self: platform instance - * @ifindex: Interface index - * - * Check whether NM handles IPv6LL address creation for the link. If the - * platform or OS doesn't support changing the IPv6LL address mode, this call - * will fail and return %FALSE. - * - * Returns: %TRUE if NM handles the IPv6LL address for @ifindex - */ -gboolean -nm_platform_link_get_user_ipv6ll_enabled(NMPlatform *self, int ifindex) -{ - 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) == NM_IN6_ADDR_GEN_MODE_NONE; - return FALSE; -} - -/** - * nm_platform_link_set_user_ip6vll_enabled: - * @self: platform instance - * @ifindex: Interface index - * - * Set whether NM handles IPv6LL address creation for the link. If the - * platform or OS doesn't support changing the IPv6LL address mode, this call - * will fail and return %FALSE. - * - * Returns: the negative nm-error on failure. - */ -int -nm_platform_link_set_user_ipv6ll_enabled(NMPlatform *self, int ifindex, gboolean enabled) -{ - _CHECK_SELF(self, klass, -NME_BUG); - - g_return_val_if_fail(ifindex > 0, -NME_BUG); - - return klass->link_set_user_ipv6ll_enabled(self, ifindex, enabled); -} - -/** - * nm_platform_link_set_address: - * @self: platform instance - * @ifindex: Interface index - * @address: The new MAC address - * - * Set interface MAC address. - */ -int -nm_platform_link_set_address(NMPlatform *self, int ifindex, gconstpointer address, size_t length) -{ - gs_free char *mac = NULL; - - _CHECK_SELF(self, klass, -NME_BUG); - - g_return_val_if_fail(ifindex > 0, -NME_BUG); - g_return_val_if_fail(address, -NME_BUG); - g_return_val_if_fail(length > 0, -NME_BUG); - - _LOG3D("link: setting hardware address to %s", (mac = nm_utils_hwaddr_ntoa(address, length))); - return klass->link_set_address(self, ifindex, address, length); -} - -/** - * nm_platform_link_get_address: - * @self: platform instance - * @ifindex: Interface index - * @length: Pointer to a variable to store address length - * - * Returns: the interface hardware address as an array of bytes of - * length @length. - */ -gconstpointer -nm_platform_link_get_address(NMPlatform *self, int ifindex, size_t *length) -{ - const NMPlatformLink *pllink; - - pllink = nm_platform_link_get(self, ifindex); - return nmp_link_address_get(pllink ? &pllink->l_address : NULL, length); -} - -/** - * nm_platform_link_get_permanent_address: - * @self: platform instance - * @ifindex: Interface index - * @buf: buffer of at least %NM_UTILS_HWADDR_LEN_MAX bytes, on success - * the permanent hardware address - * @length: Pointer to a variable to store address length - * - * Returns: %TRUE on success, %FALSE on failure to read the permanent hardware - * address. - */ -gboolean -nm_platform_link_get_permanent_address(NMPlatform *self, int ifindex, guint8 *buf, size_t *length) -{ - _CHECK_SELF(self, klass, FALSE); - - if (length) - *length = 0; - - g_return_val_if_fail(ifindex > 0, FALSE); - g_return_val_if_fail(buf, FALSE); - g_return_val_if_fail(length, FALSE); - - if (klass->link_get_permanent_address) - return klass->link_get_permanent_address(self, ifindex, buf, length); - return FALSE; -} - -gboolean -nm_platform_link_supports_carrier_detect(NMPlatform *self, int ifindex) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex >= 0, FALSE); - - return klass->link_supports_carrier_detect(self, ifindex); -} - -gboolean -nm_platform_link_supports_vlans(NMPlatform *self, int ifindex) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex >= 0, FALSE); - - return klass->link_supports_vlans(self, ifindex); -} - -gboolean -nm_platform_link_supports_sriov(NMPlatform *self, int ifindex) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex >= 0, FALSE); - - return klass->link_supports_sriov(self, ifindex); -} - -/** - * nm_platform_link_set_sriov_params: - * @self: platform instance - * @ifindex: the index of the interface to change - * @num_vfs: the number of VFs to create - * @autoprobe: the new autoprobe-drivers value (pass - * %NM_OPTION_BOOL_DEFAULT to keep current value) - * @callback: called when the operation finishes - * @callback_data: data passed to @callback - * @cancellable: cancellable to abort the operation - * - * Sets SR-IOV parameters asynchronously without - * blocking the main thread. The callback function is - * always invoked, and asynchronously. - */ -void -nm_platform_link_set_sriov_params_async(NMPlatform * self, - int ifindex, - guint num_vfs, - NMOptionBool autoprobe, - NMPlatformAsyncCallback callback, - gpointer callback_data, - GCancellable * cancellable) -{ - _CHECK_SELF_VOID(self, klass); - - g_return_if_fail(ifindex > 0); - - _LOG3D("link: setting %u total VFs and autoprobe %d", num_vfs, (int) autoprobe); - klass->link_set_sriov_params_async(self, - ifindex, - num_vfs, - autoprobe, - callback, - callback_data, - cancellable); -} - -gboolean -nm_platform_link_set_sriov_vfs(NMPlatform *self, int ifindex, const NMPlatformVF *const *vfs) -{ - guint i; - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - - _LOG3D("link: setting VFs"); - for (i = 0; vfs[i]; i++) { - const NMPlatformVF *vf = vfs[i]; - - _LOG3D("link: VF %s", nm_platform_vf_to_string(vf, NULL, 0)); - } - - return klass->link_set_sriov_vfs(self, ifindex, vfs); -} - -gboolean -nm_platform_link_set_bridge_vlans(NMPlatform * self, - int ifindex, - gboolean on_master, - const NMPlatformBridgeVlan *const *vlans) -{ - guint i; - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - - _LOG3D("link: %s bridge VLANs on %s", - vlans ? "setting" : "clearing", - on_master ? "master" : "self"); - if (vlans) { - for (i = 0; vlans[i]; i++) { - const NMPlatformBridgeVlan *vlan = vlans[i]; - - _LOG3D("link: bridge VLAN %s", nm_platform_bridge_vlan_to_string(vlan, NULL, 0)); - } - } - - return klass->link_set_bridge_vlans(self, ifindex, on_master, vlans); -} - -/** - * nm_platform_link_set_up: - * @self: platform instance - * @ifindex: Interface index - * @out_no_firmware: (allow-none): if the failure reason is due to missing firmware. - * - * Bring the interface up. - */ -gboolean -nm_platform_link_set_up(NMPlatform *self, int ifindex, gboolean *out_no_firmware) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - - _LOG3D("link: setting up"); - return klass->link_set_up(self, ifindex, out_no_firmware); -} - -/** - * nm_platform_link_set_down: - * @self: platform instance - * @ifindex: Interface index - * - * Take the interface down. - */ -gboolean -nm_platform_link_set_down(NMPlatform *self, int ifindex) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - - _LOG3D("link: setting down"); - return klass->link_set_down(self, ifindex); -} - -/** - * nm_platform_link_set_arp: - * @self: platform instance - * @ifindex: Interface index - * - * Enable ARP on the interface. - */ -gboolean -nm_platform_link_set_arp(NMPlatform *self, int ifindex) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex >= 0, FALSE); - - _LOG3D("link: setting arp"); - return klass->link_set_arp(self, ifindex); -} - -/** - * nm_platform_link_set_noarp: - * @self: platform instance - * @ifindex: Interface index - * - * Disable ARP on the interface. - */ -gboolean -nm_platform_link_set_noarp(NMPlatform *self, int ifindex) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex >= 0, FALSE); - - _LOG3D("link: setting noarp"); - return klass->link_set_noarp(self, ifindex); -} - -/** - * nm_platform_link_set_mtu: - * @self: platform instance - * @ifindex: Interface index - * @mtu: The new MTU value - * - * Set interface MTU. - */ -int -nm_platform_link_set_mtu(NMPlatform *self, int ifindex, guint32 mtu) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex >= 0, FALSE); - g_return_val_if_fail(mtu > 0, FALSE); - - _LOG3D("link: setting mtu %" G_GUINT32_FORMAT, mtu); - return klass->link_set_mtu(self, ifindex, mtu); -} - -/** - * nm_platform_link_get_mtu: - * @self: platform instance - * @ifindex: Interface index - * - * Returns: MTU value for the interface or 0 on error. - */ -guint32 -nm_platform_link_get_mtu(NMPlatform *self, int ifindex) -{ - const NMPlatformLink *pllink; - - pllink = nm_platform_link_get(self, ifindex); - return pllink ? pllink->mtu : 0; -} - -/** - * nm_platform_link_set_name: - * @self: platform instance - * @ifindex: Interface index - * @name: The new interface name - * - * Set interface name. - */ -gboolean -nm_platform_link_set_name(NMPlatform *self, int ifindex, const char *name) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex >= 0, FALSE); - g_return_val_if_fail(name, FALSE); - - _LOG3D("link: setting name %s", name); - - if (strlen(name) + 1 > IFNAMSIZ) - return FALSE; - - return klass->link_set_name(self, ifindex, name); -} - -/** - * nm_platform_link_get_physical_port_id: - * @self: platform instance - * @ifindex: Interface index - * - * The physical port ID, if present, indicates some unique identifier of - * the parent interface (eg, the physical port of which this link is a child). - * Two links that report the same physical port ID can be assumed to be - * children of the same physical port and may share resources that limit - * their abilities. - * - * Returns: physical port ID for the interface, or %NULL on error - * or if the interface has no physical port ID. - */ -char * -nm_platform_link_get_physical_port_id(NMPlatform *self, int ifindex) -{ - _CHECK_SELF(self, klass, NULL); - - g_return_val_if_fail(ifindex >= 0, NULL); - - if (klass->link_get_physical_port_id) - return klass->link_get_physical_port_id(self, ifindex); - return NULL; -} - -/** - * nm_platform_link_get_dev_id: - * @self: platform instance - * @ifindex: Interface index - * - * In contrast to the physical device ID (which indicates which parent a - * child has) the device ID differentiates sibling devices that may share - * the same MAC address. - * - * Returns: device ID for the interface, or 0 on error or if the - * interface has no device ID. - */ -guint -nm_platform_link_get_dev_id(NMPlatform *self, int ifindex) -{ - _CHECK_SELF(self, klass, 0); - - g_return_val_if_fail(ifindex >= 0, 0); - - if (klass->link_get_dev_id) - return klass->link_get_dev_id(self, ifindex); - return 0; -} - -/** - * nm_platform_link_get_wake_onlan: - * @self: platform instance - * @ifindex: Interface index - * - * Returns: the "Wake-on-LAN" status for @ifindex. - */ -gboolean -nm_platform_link_get_wake_on_lan(NMPlatform *self, int ifindex) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex >= 0, FALSE); - - if (klass->link_get_wake_on_lan) - return klass->link_get_wake_on_lan(self, ifindex); - return FALSE; -} - -/** - * nm_platform_link_get_driver_info: - * @self: platform instance - * @ifindex: Interface index - * @out_driver_name: (transfer full): on success, the driver name if available - * @out_driver_version: (transfer full): on success, the driver version if available - * @out_fw_version: (transfer full): on success, the firmware version if available - * - * Returns: %TRUE on success (though @out_driver_name, @out_driver_version and - * @out_fw_version can be %NULL if no information was available), %FALSE on - * failure. - */ -gboolean -nm_platform_link_get_driver_info(NMPlatform *self, - int ifindex, - char ** out_driver_name, - char ** out_driver_version, - char ** out_fw_version) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex >= 0, FALSE); - - return klass->link_get_driver_info(self, - ifindex, - out_driver_name, - out_driver_version, - out_fw_version); -} - -/** - * nm_platform_link_enslave: - * @self: platform instance - * @master: Interface index of the master - * @ifindex: Interface index of the slave - * - * Enslave @ifindex to @master. - */ -gboolean -nm_platform_link_enslave(NMPlatform *self, int master, int ifindex) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(master > 0, FALSE); - g_return_val_if_fail(ifindex > 0, FALSE); - - _LOG3D("link: enslaving to master '%s'", nm_platform_link_get_name(self, master)); - return klass->link_enslave(self, master, ifindex); -} - -/** - * nm_platform_link_release: - * @self: platform instance - * @master: Interface index of the master - * @ifindex: Interface index of the slave - * - * Release @slave from @master. - */ -gboolean -nm_platform_link_release(NMPlatform *self, int master, int ifindex) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(master > 0, FALSE); - g_return_val_if_fail(ifindex > 0, FALSE); - - if (nm_platform_link_get_master(self, ifindex) != master) - return FALSE; - - _LOG3D("link: releasing from master '%s'", nm_platform_link_get_name(self, master)); - return klass->link_release(self, master, ifindex); -} - -/** - * nm_platform_link_get_master: - * @self: platform instance - * @slave: Interface index of the slave. - * - * Returns: Interface index of the slave's master. - */ -int -nm_platform_link_get_master(NMPlatform *self, int slave) -{ - const NMPlatformLink *pllink; - - pllink = nm_platform_link_get(self, slave); - return pllink ? pllink->master : 0; -} - -/*****************************************************************************/ - -gboolean -nm_platform_link_can_assume(NMPlatform *self, int ifindex) -{ - _CHECK_SELF(self, klass, FALSE); - - if (klass->link_can_assume) - return klass->link_can_assume(self, ifindex); - g_return_val_if_reached(FALSE); -} - -/*****************************************************************************/ - -/** - * 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 safely 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) -{ - const NMPObject *obj; - - obj = nm_platform_link_get_obj(self, ifindex, TRUE); - if (!obj) { - NM_SET_OUT(out_link, NULL); - return NULL; - } - - 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 obj->_link.netlink.lnk; -} - -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 NMPlatformLnkBridge * -nm_platform_link_get_lnk_bridge(NMPlatform *self, int ifindex, const NMPlatformLink **out_link) -{ - return _link_get_lnk(self, ifindex, NM_LINK_TYPE_BRIDGE, out_link); -} - -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 NMPlatformLnkGre * -nm_platform_link_get_lnk_gretap(NMPlatform *self, int ifindex, const NMPlatformLink **out_link) -{ - return _link_get_lnk(self, ifindex, NM_LINK_TYPE_GRETAP, 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 NMPlatformLnkIp6Tnl * -nm_platform_link_get_lnk_ip6gre(NMPlatform *self, int ifindex, const NMPlatformLink **out_link) -{ - return _link_get_lnk(self, ifindex, NM_LINK_TYPE_IP6GRE, out_link); -} - -const NMPlatformLnkIp6Tnl * -nm_platform_link_get_lnk_ip6gretap(NMPlatform *self, int ifindex, const NMPlatformLink **out_link) -{ - return _link_get_lnk(self, ifindex, NM_LINK_TYPE_IP6GRETAP, 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 NMPlatformLnkMacsec * -nm_platform_link_get_lnk_macsec(NMPlatform *self, int ifindex, const NMPlatformLink **out_link) -{ - return _link_get_lnk(self, ifindex, NM_LINK_TYPE_MACSEC, 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 NMPlatformLnkMacvlan * -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 NMPlatformLnkTun * -nm_platform_link_get_lnk_tun(NMPlatform *self, int ifindex, const NMPlatformLink **out_link) -{ - return _link_get_lnk(self, ifindex, NM_LINK_TYPE_TUN, 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 NMPlatformLnkVrf * -nm_platform_link_get_lnk_vrf(NMPlatform *self, int ifindex, const NMPlatformLink **out_link) -{ - return _link_get_lnk(self, ifindex, NM_LINK_TYPE_VRF, 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); -} - -const NMPlatformLnkWireGuard * -nm_platform_link_get_lnk_wireguard(NMPlatform *self, int ifindex, const NMPlatformLink **out_link) -{ - return _link_get_lnk(self, ifindex, NM_LINK_TYPE_WIREGUARD, out_link); -} - -/*****************************************************************************/ - -static NM_UTILS_FLAGS2STR_DEFINE( - _wireguard_change_flags_to_string, - NMPlatformWireGuardChangeFlags, - NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_FLAG_NONE, "none"), - NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_FLAG_REPLACE_PEERS, "replace-peers"), - NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_PRIVATE_KEY, "has-private-key"), - NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_LISTEN_PORT, "has-listen-port"), - NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_FWMARK, "has-fwmark"), ); - -static NM_UTILS_FLAGS2STR_DEFINE( - _wireguard_change_peer_flags_to_string, - NMPlatformWireGuardChangePeerFlags, - NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_NONE, "none"), - NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REMOVE_ME, "remove"), - NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY, "psk"), - NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_KEEPALIVE_INTERVAL, "ka"), - NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ENDPOINT, "ep"), - NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ALLOWEDIPS, "aips"), - NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REPLACE_ALLOWEDIPS, "remove-aips"), ); - -int -nm_platform_link_wireguard_change(NMPlatform * self, - int ifindex, - const NMPlatformLnkWireGuard * lnk_wireguard, - const NMPWireGuardPeer * peers, - const NMPlatformWireGuardChangePeerFlags *peer_flags, - guint peers_len, - NMPlatformWireGuardChangeFlags change_flags) -{ - _CHECK_SELF(self, klass, -NME_BUG); - - nm_assert(klass->link_wireguard_change); - - if (_LOGD_ENABLED()) { - char buf_lnk[256]; - char buf_peers[512]; - char buf_change_flags[100]; - - buf_peers[0] = '\0'; - if (peers_len > 0) { - char *b = buf_peers; - gsize len = sizeof(buf_peers); - guint i; - - nm_utils_strbuf_append_str(&b, &len, " { "); - for (i = 0; i < peers_len; i++) { - nm_utils_strbuf_append_str(&b, &len, " { "); - nm_platform_wireguard_peer_to_string(&peers[i], b, len); - nm_utils_strbuf_seek_end(&b, &len); - if (peer_flags) { - nm_utils_strbuf_append( - &b, - &len, - " (%s)", - _wireguard_change_peer_flags_to_string(peer_flags[i], - buf_change_flags, - sizeof(buf_change_flags))); - } - nm_utils_strbuf_append_str(&b, &len, " } "); - } - nm_utils_strbuf_append_str(&b, &len, "}"); - } - - _LOG3D("link: change wireguard ifindex %d, %s, (%s), %u peers%s", - ifindex, - nm_platform_lnk_wireguard_to_string(lnk_wireguard, buf_lnk, sizeof(buf_lnk)), - _wireguard_change_flags_to_string(change_flags, - buf_change_flags, - sizeof(buf_change_flags)), - peers_len, - buf_peers); - } - - return klass->link_wireguard_change(self, - ifindex, - lnk_wireguard, - peers, - peer_flags, - peers_len, - change_flags); -} - -/*****************************************************************************/ - -/** - * 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 - * @out_fd: (allow-none): if give, return the file descriptor for the - * created device. Note that when creating a non-persistent device, - * this argument is mandatory, otherwise it makes no sense - * to create such an interface. - * The caller is responsible for closing this file descriptor. - * - * Create a TUN or TAP interface. - */ -int -nm_platform_link_tun_add(NMPlatform * self, - const char * name, - const NMPlatformLnkTun *props, - const NMPlatformLink ** out_link, - int * out_fd) -{ - char b[255]; - int r; - - _CHECK_SELF(self, klass, -NME_BUG); - - g_return_val_if_fail(name, -NME_BUG); - g_return_val_if_fail(props, -NME_BUG); - g_return_val_if_fail(NM_IN_SET(props->type, IFF_TUN, IFF_TAP), -NME_BUG); - - /* creating a non-persistent device requires that the caller handles - * the file descriptor. */ - g_return_val_if_fail(props->persist || out_fd, -NME_BUG); - - NM_SET_OUT(out_fd, -1); - - r = _link_add_check_existing(self, name, NM_LINK_TYPE_TUN, out_link); - if (r < 0) - return r; - - _LOG2D("link: adding link %s", nm_platform_lnk_tun_to_string(props, b, sizeof(b))); - - if (!klass->link_tun_add(self, name, props, out_link, out_fd)) - return -NME_UNSPEC; - return 0; -} - -gboolean -nm_platform_link_6lowpan_get_properties(NMPlatform *self, int ifindex, int *out_parent) -{ - const NMPlatformLink *plink; - - plink = nm_platform_link_get(self, ifindex); - if (!plink) - return FALSE; - - if (plink->type != NM_LINK_TYPE_6LOWPAN) - return FALSE; - - if (plink->parent != 0) { - NM_SET_OUT(out_parent, plink->parent); - return TRUE; - } - - /* As of 4.16 kernel does not expose the peer_ifindex as IFA_LINK. - * Find the WPAN device with the same MAC address. */ - if (out_parent) { - const NMPlatformLink *parent_plink; - - parent_plink = nm_platform_link_get_by_address(self, - NM_LINK_TYPE_WPAN, - plink->l_address.data, - plink->l_address.len); - NM_SET_OUT(out_parent, parent_plink ? parent_plink->ifindex : -1); - } - - return TRUE; -} - -/*****************************************************************************/ - -static gboolean -link_set_option(NMPlatform *self, - int ifindex, - const char *category, - const char *option, - const char *value) -{ - nm_auto_close int dirfd = -1; - char ifname_verified[IFNAMSIZ]; - const char * path; - - if (!category || !option) - return FALSE; - - dirfd = nm_platform_sysctl_open_netdir(self, ifindex, ifname_verified); - if (dirfd < 0) - return FALSE; - - path = - nm_sprintf_buf_unsafe_a(strlen(category) + strlen(option) + 2, "%s/%s", category, option); - return nm_platform_sysctl_set(self, - NMP_SYSCTL_PATHID_NETDIR_unsafe(dirfd, ifname_verified, path), - value); -} - -static char * -link_get_option(NMPlatform *self, int ifindex, const char *category, const char *option) -{ - nm_auto_close int dirfd = -1; - char ifname_verified[IFNAMSIZ]; - const char * path; - - if (!category || !option) - return NULL; - - dirfd = nm_platform_sysctl_open_netdir(self, ifindex, ifname_verified); - if (dirfd < 0) - return NULL; - - path = - nm_sprintf_buf_unsafe_a(strlen(category) + strlen(option) + 2, "%s/%s", category, option); - return nm_platform_sysctl_get(self, - NMP_SYSCTL_PATHID_NETDIR_unsafe(dirfd, ifname_verified, path)); -} - -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_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); - - return link_set_option(self, ifindex, master_category(self, ifindex), option, value); -} - -char * -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); - - return link_get_option(self, ifindex, master_category(self, ifindex), option); -} - -gboolean -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); - - return link_set_option(self, ifindex, slave_category(self, ifindex), option, value); -} - -char * -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); - - return link_get_option(self, ifindex, slave_category(self, ifindex), option); -} - -/*****************************************************************************/ - -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) -{ - _CHECK_SELF(self, klass, FALSE); - - nm_assert(klass->link_vlan_change); - - g_return_val_if_fail(!n_ingress_map || ingress_map, FALSE); - g_return_val_if_fail(!n_egress_map || egress_map, 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)"); - } - - _LOG3D("link: change vlan %s", 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_link_vlan_set_ingress_map(NMPlatform *self, int ifindex, int from, int to) -{ - NMVlanQosMapping map = { - .from = from, - .to = to, - }; - - return nm_platform_link_vlan_change(self, ifindex, 0, 0, FALSE, &map, 1, FALSE, NULL, 0); -} - -gboolean -nm_platform_link_vlan_set_egress_map(NMPlatform *self, int ifindex, int from, int to) -{ - NMVlanQosMapping map = { - .from = from, - .to = to, - }; - - return nm_platform_link_vlan_change(self, ifindex, 0, 0, FALSE, NULL, 0, FALSE, &map, 1); -} - -static int -_infiniband_add_add_or_delete(NMPlatform * self, - int ifindex, - int p_key, - gboolean add, - const NMPlatformLink **out_link) -{ - char name[IFNAMSIZ]; - const NMPlatformLink *parent_link; - int r; - - _CHECK_SELF(self, klass, -NME_BUG); - - g_return_val_if_fail(ifindex >= 0, -NME_BUG); - g_return_val_if_fail(p_key >= 0 && p_key <= 0xffff, -NME_BUG); - - /* the special keys 0x0000 and 0x8000 are not allowed. */ - if (NM_IN_SET(p_key, 0, 0x8000)) - return -NME_UNSPEC; - - parent_link = nm_platform_link_get(self, ifindex); - if (!parent_link) - return -NME_PL_NOT_FOUND; - - if (parent_link->type != NM_LINK_TYPE_INFINIBAND) - return -NME_PL_WRONG_TYPE; - - nm_utils_new_infiniband_name(name, parent_link->name, p_key); - - if (add) { - r = _link_add_check_existing(self, name, NM_LINK_TYPE_INFINIBAND, out_link); - if (r < 0) - return r; - - _LOG3D("link: adding infiniband partition %s, key %d", name, p_key); - if (!klass->infiniband_partition_add(self, ifindex, p_key, out_link)) - return -NME_UNSPEC; - } else { - _LOG3D("link: deleting infiniband partition %s, key %d", name, p_key); - - if (!klass->infiniband_partition_delete(self, ifindex, p_key)) - return -NME_UNSPEC; - } - - return 0; -} - -int -nm_platform_link_infiniband_add(NMPlatform * self, - int parent, - int p_key, - const NMPlatformLink **out_link) -{ - return _infiniband_add_add_or_delete(self, parent, p_key, TRUE, out_link); -} - -int -nm_platform_link_infiniband_delete(NMPlatform *self, int parent, int p_key) -{ - return _infiniband_add_add_or_delete(self, parent, p_key, FALSE, NULL); -} - -gboolean -nm_platform_link_infiniband_get_properties(NMPlatform * self, - int ifindex, - int * out_parent, - int * out_p_key, - const char **out_mode) -{ - nm_auto_close int dirfd = -1; - char ifname_verified[IFNAMSIZ]; - const NMPlatformLnkInfiniband *plnk; - const NMPlatformLink * plink; - char * contents; - const char * mode; - int p_key = 0; - - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - - 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. */ - - dirfd = nm_platform_sysctl_open_netdir(self, ifindex, ifname_verified); - if (dirfd < 0) - return FALSE; - - contents = - nm_platform_sysctl_get(self, NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname_verified, "mode")); - if (!contents) - return FALSE; - if (strstr(contents, "datagram")) - mode = "datagram"; - else if (strstr(contents, "connected")) - mode = "connected"; - else - mode = NULL; - g_free(contents); - - p_key = - nm_platform_sysctl_get_int_checked(self, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname_verified, "pkey"), - 16, - 0, - 0xFFFF, - -1); - 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_link_veth_get_properties(NMPlatform *self, int ifindex, int *out_peer_ifindex) -{ - const NMPlatformLink *plink; - int peer_ifindex; - - 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) { - nm_auto_pop_netns NMPNetns *netns = NULL; - - if (!nm_platform_netns_push(self, &netns)) - return FALSE; - peer_ifindex = nmp_utils_ethtool_get_peer_ifindex(plink->ifindex); - if (peer_ifindex <= 0) - return FALSE; - - *out_peer_ifindex = peer_ifindex; - } - return TRUE; -} - -/** - * nm_platform_link_tun_get_properties: - * @self: the #NMPlatform instance - * @ifindex: the ifindex to look up - * @out_properties: (out) (allow-none): return the read properties - * - * Only recent versions of kernel export tun properties via netlink. - * So, if that's the case, then we have the NMPlatformLnkTun instance - * in the platform cache ready to return. Otherwise, this function - * falls back reading sysctl to obtain the tun properties. That - * is racy, because querying sysctl means that the object might - * be already removed from cache (while NM didn't yet process the - * netlink message). - * - * Hence, to lookup the tun properties, you always need to use this - * function, and use it with care knowing that it might obtain its - * data by reading sysctl. Note that we don't want to add this workaround - * to the platform cache itself, because the cache should (mainly) - * contain data from netlink. To access the sysctl side channel, the - * user needs to do explicitly. - * - * Returns: #TRUE, if the properties could be read. */ -gboolean -nm_platform_link_tun_get_properties(NMPlatform *self, int ifindex, NMPlatformLnkTun *out_properties) -{ - const NMPObject *plobj; - const NMPObject *pllnk; - char ifname[IFNAMSIZ]; - gint64 owner; - gint64 group; - gint64 flags; - - /* we consider also invisible links (those that are not yet in udev). */ - plobj = nm_platform_link_get_obj(self, ifindex, FALSE); - if (!plobj) - return FALSE; - - if (NMP_OBJECT_CAST_LINK(plobj)->type != NM_LINK_TYPE_TUN) - return FALSE; - - pllnk = plobj->_link.netlink.lnk; - if (pllnk) { - nm_assert(NMP_OBJECT_GET_TYPE(pllnk) == NMP_OBJECT_TYPE_LNK_TUN); - nm_assert(NMP_OBJECT_GET_CLASS(pllnk)->lnk_link_type == NM_LINK_TYPE_TUN); - - /* recent kernels expose tun properties via netlink and thus we have them - * in the platform cache. */ - NM_SET_OUT(out_properties, pllnk->lnk_tun); - return TRUE; - } - - /* fallback to reading sysctl. */ - { - nm_auto_close int dirfd = -1; - - dirfd = nm_platform_sysctl_open_netdir(self, ifindex, ifname); - if (dirfd < 0) - return FALSE; - - owner = nm_platform_sysctl_get_int_checked(self, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, "owner"), - 10, - -1, - G_MAXUINT32, - -2); - if (owner == -2) - return FALSE; - - group = nm_platform_sysctl_get_int_checked(self, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, "group"), - 10, - -1, - G_MAXUINT32, - -2); - if (group == -2) - return FALSE; - - flags = - nm_platform_sysctl_get_int_checked(self, - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, "tun_flags"), - 16, - 0, - G_MAXINT64, - -1); - if (flags == -1) - return FALSE; - } - - if (out_properties) { - memset(out_properties, 0, sizeof(*out_properties)); - if (owner != -1) { - out_properties->owner_valid = TRUE; - out_properties->owner = owner; - } - if (group != -1) { - out_properties->group_valid = TRUE; - out_properties->group = group; - } - out_properties->type = (flags & TUN_TYPE_MASK); - out_properties->pi = !(flags & IFF_NO_PI); - out_properties->vnet_hdr = !!(flags & IFF_VNET_HDR); - out_properties->multi_queue = !!(flags & NM_IFF_MULTI_QUEUE); - out_properties->persist = !!(flags & IFF_PERSIST); - } - return TRUE; -} - -gboolean -nm_platform_wifi_get_capabilities(NMPlatform *self, int ifindex, NMDeviceWifiCapabilities *caps) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - - return klass->wifi_get_capabilities(self, ifindex, caps); -} - -guint32 -nm_platform_wifi_get_frequency(NMPlatform *self, int ifindex) -{ - _CHECK_SELF(self, klass, 0); - - g_return_val_if_fail(ifindex > 0, 0); - - return klass->wifi_get_frequency(self, ifindex); -} - -gboolean -nm_platform_wifi_get_station(NMPlatform * self, - int ifindex, - NMEtherAddr *out_bssid, - int * out_quality, - guint32 * out_rate) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - - return klass->wifi_get_station(self, ifindex, out_bssid, out_quality, out_rate); -} - -NM80211Mode -nm_platform_wifi_get_mode(NMPlatform *self, int ifindex) -{ - _CHECK_SELF(self, klass, NM_802_11_MODE_UNKNOWN); - - g_return_val_if_fail(ifindex > 0, NM_802_11_MODE_UNKNOWN); - - return klass->wifi_get_mode(self, ifindex); -} - -void -nm_platform_wifi_set_mode(NMPlatform *self, int ifindex, NM80211Mode mode) -{ - _CHECK_SELF_VOID(self, klass); - - g_return_if_fail(ifindex > 0); - - 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) -{ - _CHECK_SELF(self, klass, 0); - - g_return_val_if_fail(ifindex > 0, 0); - g_return_val_if_fail(freqs != NULL, 0); - - return klass->wifi_find_frequency(self, ifindex, freqs); -} - -void -nm_platform_wifi_indicate_addressing_running(NMPlatform *self, int ifindex, gboolean running) -{ - _CHECK_SELF_VOID(self, klass); - - g_return_if_fail(ifindex > 0); - - klass->wifi_indicate_addressing_running(self, ifindex, running); -} - -NMSettingWirelessWakeOnWLan -nm_platform_wifi_get_wake_on_wlan(NMPlatform *self, int ifindex) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - - return klass->wifi_get_wake_on_wlan(self, ifindex); -} - -gboolean -nm_platform_wifi_set_wake_on_wlan(NMPlatform *self, int ifindex, NMSettingWirelessWakeOnWLan wowl) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - - return klass->wifi_set_wake_on_wlan(self, ifindex, wowl); -} - -guint32 -nm_platform_mesh_get_channel(NMPlatform *self, int ifindex) -{ - _CHECK_SELF(self, klass, 0); - - g_return_val_if_fail(ifindex > 0, 0); - - return klass->mesh_get_channel(self, ifindex); -} - -gboolean -nm_platform_mesh_set_channel(NMPlatform *self, int ifindex, guint32 channel) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - - return klass->mesh_set_channel(self, ifindex, channel); -} - -gboolean -nm_platform_mesh_set_ssid(NMPlatform *self, int ifindex, const guint8 *ssid, gsize len) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - g_return_val_if_fail(ssid != NULL, FALSE); - - return klass->mesh_set_ssid(self, ifindex, ssid, len); -} - -guint16 -nm_platform_wpan_get_pan_id(NMPlatform *self, int ifindex) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - - return klass->wpan_get_pan_id(self, ifindex); -} - -gboolean -nm_platform_wpan_set_pan_id(NMPlatform *self, int ifindex, guint16 pan_id) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - - return klass->wpan_set_pan_id(self, ifindex, pan_id); -} - -guint16 -nm_platform_wpan_get_short_addr(NMPlatform *self, int ifindex) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - - return klass->wpan_get_short_addr(self, ifindex); -} - -gboolean -nm_platform_wpan_set_short_addr(NMPlatform *self, int ifindex, guint16 short_addr) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - - return klass->wpan_set_short_addr(self, ifindex, short_addr); -} - -gboolean -nm_platform_wpan_set_channel(NMPlatform *self, int ifindex, guint8 page, guint8 channel) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - - return klass->wpan_set_channel(self, ifindex, page, channel); -} - -#define TO_STRING_DEV_BUF_SIZE (5 + 15 + 1) -static const char * -_to_string_dev(NMPlatform *self, int ifindex, char *buf, size_t size) -{ - g_assert(buf && size >= TO_STRING_DEV_BUF_SIZE); - - if (ifindex) { - const char *name = ifindex > 0 && self ? nm_platform_link_get_name(self, ifindex) : NULL; - char * buf2; - - strcpy(buf, " dev "); - buf2 = buf + 5; - size -= 5; - - if (name) - g_strlcpy(buf2, name, size); - else - g_snprintf(buf2, size, "%d", ifindex); - } else - buf[0] = 0; - - return buf; -} - -#define TO_STRING_IFA_FLAGS_BUF_SIZE 256 - -static const char * -_to_string_ifa_flags(guint32 ifa_flags, char *buf, gsize size) -{ -#define S_FLAGS_PREFIX " flags " - nm_assert(buf && size >= TO_STRING_IFA_FLAGS_BUF_SIZE && size > NM_STRLEN(S_FLAGS_PREFIX)); - - if (!ifa_flags) - buf[0] = '\0'; - else { - nm_platform_addr_flags2str(ifa_flags, - &buf[NM_STRLEN(S_FLAGS_PREFIX)], - size - NM_STRLEN(S_FLAGS_PREFIX)); - if (buf[NM_STRLEN(S_FLAGS_PREFIX)] == '\0') - buf[0] = '\0'; - else - memcpy(buf, S_FLAGS_PREFIX, NM_STRLEN(S_FLAGS_PREFIX)); - } - return buf; -} - -/*****************************************************************************/ - -gboolean -nm_platform_ethtool_set_wake_on_lan(NMPlatform * self, - int ifindex, - _NMSettingWiredWakeOnLan wol, - const char * wol_password) -{ - _CHECK_SELF_NETNS(self, klass, netns, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - - return nmp_utils_ethtool_set_wake_on_lan(ifindex, wol, wol_password); -} - -gboolean -nm_platform_ethtool_set_link_settings(NMPlatform * self, - int ifindex, - gboolean autoneg, - guint32 speed, - NMPlatformLinkDuplexType duplex) -{ - _CHECK_SELF_NETNS(self, klass, netns, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - - return nmp_utils_ethtool_set_link_settings(ifindex, autoneg, speed, duplex); -} - -gboolean -nm_platform_ethtool_get_link_settings(NMPlatform * self, - int ifindex, - gboolean * out_autoneg, - guint32 * out_speed, - NMPlatformLinkDuplexType *out_duplex) -{ - _CHECK_SELF_NETNS(self, klass, netns, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - - return nmp_utils_ethtool_get_link_settings(ifindex, out_autoneg, out_speed, out_duplex); -} - -/*****************************************************************************/ - -NMEthtoolFeatureStates * -nm_platform_ethtool_get_link_features(NMPlatform *self, int ifindex) -{ - _CHECK_SELF_NETNS(self, klass, netns, NULL); - - g_return_val_if_fail(ifindex > 0, NULL); - - return nmp_utils_ethtool_get_features(ifindex); -} - -gboolean -nm_platform_ethtool_set_features( - NMPlatform * self, - int ifindex, - const NMEthtoolFeatureStates *features, - const NMOptionBool *requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */, - gboolean do_set /* or reset */) -{ - _CHECK_SELF_NETNS(self, klass, netns, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - - return nmp_utils_ethtool_set_features(ifindex, features, requested, do_set); -} - -gboolean -nm_platform_ethtool_get_link_coalesce(NMPlatform * self, - int ifindex, - NMEthtoolCoalesceState *coalesce) -{ - _CHECK_SELF_NETNS(self, klass, netns, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - g_return_val_if_fail(coalesce, FALSE); - - return nmp_utils_ethtool_get_coalesce(ifindex, coalesce); -} - -gboolean -nm_platform_ethtool_set_coalesce(NMPlatform * self, - int ifindex, - const NMEthtoolCoalesceState *coalesce) -{ - _CHECK_SELF_NETNS(self, klass, netns, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - - return nmp_utils_ethtool_set_coalesce(ifindex, coalesce); -} - -gboolean -nm_platform_ethtool_get_link_ring(NMPlatform *self, int ifindex, NMEthtoolRingState *ring) -{ - _CHECK_SELF_NETNS(self, klass, netns, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - g_return_val_if_fail(ring, FALSE); - - return nmp_utils_ethtool_get_ring(ifindex, ring); -} - -gboolean -nm_platform_ethtool_set_ring(NMPlatform *self, int ifindex, const NMEthtoolRingState *ring) -{ - _CHECK_SELF_NETNS(self, klass, netns, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - - return nmp_utils_ethtool_set_ring(ifindex, ring); -} - -/*****************************************************************************/ - -const NMDedupMultiHeadEntry * -nm_platform_lookup_all(NMPlatform *self, NMPCacheIdType cache_id_type, const NMPObject *obj) -{ - return nmp_cache_lookup_all(nm_platform_get_cache(self), cache_id_type, obj); -} - -const NMDedupMultiEntry * -nm_platform_lookup_entry(NMPlatform *self, NMPCacheIdType cache_id_type, const NMPObject *obj) -{ - return nmp_cache_lookup_entry_with_idx_type(nm_platform_get_cache(self), cache_id_type, obj); -} - -const NMDedupMultiHeadEntry * -nm_platform_lookup(NMPlatform *self, const NMPLookup *lookup) -{ - return nmp_cache_lookup(nm_platform_get_cache(self), lookup); -} - -gboolean -nm_platform_lookup_predicate_routes_main(const NMPObject *obj, gpointer user_data) -{ - nm_assert( - NM_IN_SET(NMP_OBJECT_GET_TYPE(obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); - return nm_platform_route_table_is_main( - nm_platform_ip_route_get_effective_table(&obj->ip_route)); -} - -gboolean -nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel(const NMPObject *obj, - gpointer user_data) -{ - nm_assert( - NM_IN_SET(NMP_OBJECT_GET_TYPE(obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); - return nm_platform_route_table_is_main(nm_platform_ip_route_get_effective_table(&obj->ip_route)) - && obj->ip_route.rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL; -} - -/** - * nm_platform_lookup_clone: - * @self: - * @lookup: - * @predicate: if given, only objects for which @predicate returns %TRUE are included - * in the result. - * @user_data: user data for @predicate - * - * Returns the result of lookup in a GPtrArray. The result array contains - * references objects from the cache, its destroy function will unref them. - * - * The user must unref the GPtrArray, which will also unref the NMPObject - * elements. - * - * The elements in the array *must* not be modified. - * - * Returns: the result of the lookup. - */ -GPtrArray * -nm_platform_lookup_clone(NMPlatform * self, - const NMPLookup * lookup, - NMPObjectPredicateFunc predicate, - gpointer user_data) -{ - return nm_dedup_multi_objs_to_ptr_array_head(nm_platform_lookup(self, lookup), - (NMDedupMultiFcnSelectPredicate) predicate, - user_data); -} - -void -nm_platform_ip4_address_set_addr(NMPlatformIP4Address *addr, in_addr_t address, guint8 plen) -{ - nm_assert(plen <= 32); - - 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; -} - -gboolean -nm_platform_ip6_address_match(const NMPlatformIP6Address *addr, NMPlatformMatchFlags match_flag) -{ - nm_assert(!NM_FLAGS_ANY( - match_flag, - ~(NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY | NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY))); - nm_assert(NM_FLAGS_ANY(match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY)); - nm_assert(NM_FLAGS_ANY(match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY)); - - if (IN6_IS_ADDR_LINKLOCAL(&addr->address)) { - if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL)) - return FALSE; - } else { - if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL)) - return FALSE; - } - - if (NM_FLAGS_HAS(addr->n_ifa_flags, IFA_F_DADFAILED)) { - if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED)) - return FALSE; - } else if (NM_FLAGS_HAS(addr->n_ifa_flags, IFA_F_TENTATIVE) - && !NM_FLAGS_HAS(addr->n_ifa_flags, IFA_F_OPTIMISTIC)) { - if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE)) - return FALSE; - } else { - if (!NM_FLAGS_HAS(match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) - return FALSE; - } - - return TRUE; -} - -gboolean -nm_platform_ip4_address_add(NMPlatform *self, - int ifindex, - in_addr_t address, - guint8 plen, - in_addr_t peer_address, - in_addr_t broadcast_address, - guint32 lifetime, - guint32 preferred, - guint32 flags, - const char *label) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - g_return_val_if_fail(plen <= 32, FALSE); - g_return_val_if_fail(lifetime > 0, FALSE); - g_return_val_if_fail(preferred <= lifetime, FALSE); - g_return_val_if_fail(!label || strlen(label) < sizeof(((NMPlatformIP4Address *) NULL)->label), - FALSE); - - if (_LOGD_ENABLED()) { - NMPlatformIP4Address addr; - - addr = (NMPlatformIP4Address){ - .ifindex = ifindex, - .address = address, - .peer_address = peer_address, - .plen = plen, - .timestamp = 0, /* set it at zero, which to_string will treat as *now* */ - .lifetime = lifetime, - .preferred = preferred, - .n_ifa_flags = flags, - .broadcast_address = broadcast_address, - .use_ip4_broadcast_address = TRUE, - }; - if (label) - g_strlcpy(addr.label, label, sizeof(addr.label)); - - _LOG3D("address: adding or updating IPv4 address: %s", - nm_platform_ip4_address_to_string(&addr, NULL, 0)); - } - return klass->ip4_address_add(self, - ifindex, - address, - plen, - peer_address, - broadcast_address, - lifetime, - preferred, - flags, - label); -} - -gboolean -nm_platform_ip6_address_add(NMPlatform * self, - int ifindex, - struct in6_addr address, - guint8 plen, - struct in6_addr peer_address, - guint32 lifetime, - guint32 preferred, - guint32 flags) -{ - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - g_return_val_if_fail(plen <= 128, FALSE); - g_return_val_if_fail(lifetime > 0, FALSE); - g_return_val_if_fail(preferred <= lifetime, FALSE); - - if (_LOGD_ENABLED()) { - NMPlatformIP6Address addr = {0}; - - addr.ifindex = ifindex; - addr.address = address; - addr.peer_address = peer_address; - addr.plen = plen; - addr.timestamp = 0; /* set it to zero, which to_string will treat as *now* */ - addr.lifetime = lifetime; - addr.preferred = preferred; - addr.n_ifa_flags = flags; - - _LOG3D("address: adding or updating IPv6 address: %s", - nm_platform_ip6_address_to_string(&addr, NULL, 0)); - } - 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, - guint8 plen, - in_addr_t peer_address) -{ - char str_dev[TO_STRING_DEV_BUF_SIZE]; - char b1[NM_UTILS_INET_ADDRSTRLEN]; - char b2[NM_UTILS_INET_ADDRSTRLEN]; - char str_peer[INET_ADDRSTRLEN + 50]; - - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - g_return_val_if_fail(plen <= 32, FALSE); - - _LOG3D("address: deleting IPv4 address %s/%d, %s%s", - _nm_utils_inet4_ntop(address, b1), - plen, - peer_address != address - ? nm_sprintf_buf(str_peer, "peer %s, ", _nm_utils_inet4_ntop(peer_address, b2)) - : "", - _to_string_dev(self, ifindex, str_dev, sizeof(str_dev))); - return klass->ip4_address_delete(self, ifindex, address, plen, peer_address); -} - -gboolean -nm_platform_ip6_address_delete(NMPlatform *self, int ifindex, struct in6_addr address, guint8 plen) -{ - char str_dev[TO_STRING_DEV_BUF_SIZE]; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(ifindex > 0, FALSE); - g_return_val_if_fail(plen <= 128, FALSE); - - _LOG3D("address: deleting IPv6 address %s/%d, %s", - _nm_utils_inet6_ntop(&address, sbuf), - plen, - _to_string_dev(self, ifindex, str_dev, sizeof(str_dev))); - return klass->ip6_address_delete(self, ifindex, address, plen); -} - -const NMPlatformIP4Address * -nm_platform_ip4_address_get(NMPlatform *self, - int ifindex, - in_addr_t address, - guint8 plen, - in_addr_t peer_address) -{ - NMPObject obj_id; - const NMPObject *obj; - - _CHECK_SELF(self, klass, NULL); - - g_return_val_if_fail(plen <= 32, NULL); - - nmp_object_stackinit_id_ip4_address(&obj_id, ifindex, address, plen, peer_address); - obj = nmp_cache_lookup_obj(nm_platform_get_cache(self), &obj_id); - nm_assert(!obj || nmp_object_is_visible(obj)); - return NMP_OBJECT_CAST_IP4_ADDRESS(obj); -} - -const NMPlatformIP6Address * -nm_platform_ip6_address_get(NMPlatform *self, int ifindex, const struct in6_addr *address) -{ - NMPObject obj_id; - const NMPObject *obj; - - _CHECK_SELF(self, klass, NULL); - - nm_assert(address); - - nmp_object_stackinit_id_ip6_address(&obj_id, ifindex, address); - obj = nmp_cache_lookup_obj(nm_platform_get_cache(self), &obj_id); - nm_assert(!obj || nmp_object_is_visible(obj)); - return NMP_OBJECT_CAST_IP6_ADDRESS(obj); -} - -static gboolean -_addr_array_clean_expired(int addr_family, - int ifindex, - GPtrArray * array, - guint32 now, - GHashTable **idx) -{ - guint i; - gboolean any_addrs = FALSE; - - nm_assert_addr_family(addr_family); - nm_assert(ifindex > 0); - nm_assert(now > 0); - - if (!array) - return FALSE; - - /* remove all addresses that are already expired. */ - for (i = 0; i < array->len; i++) { - const NMPlatformIPAddress *a = NMP_OBJECT_CAST_IP_ADDRESS(array->pdata[i]); - -#if NM_MORE_ASSERTS > 10 - nm_assert(a); - nm_assert(a->ifindex == ifindex); - { - const NMPObject *o = NMP_OBJECT_UP_CAST(a); - guint j; - - nm_assert(NMP_OBJECT_GET_CLASS(o)->addr_family == addr_family); - for (j = i + 1; j < array->len; j++) { - const NMPObject *o2 = array->pdata[j]; - - nm_assert(NMP_OBJECT_GET_TYPE(o) == NMP_OBJECT_GET_TYPE(o2)); - nm_assert(!nmp_object_id_equal(o, o2)); - } - } -#endif - - if (!NM_IS_IPv4(addr_family) && NM_FLAGS_HAS(a->n_ifa_flags, IFA_F_TEMPORARY)) { - /* temporary addresses are never added explicitly by NetworkManager but - * kernel adds them via mngtempaddr flag. - * - * We drop them from this list. */ - goto clear_and_next; - } - - if (!nm_utils_lifetime_get(a->timestamp, a->lifetime, a->preferred, now, NULL)) - goto clear_and_next; - - if (idx) { - if (G_UNLIKELY(!*idx)) { - *idx = g_hash_table_new((GHashFunc) nmp_object_id_hash, - (GEqualFunc) nmp_object_id_equal); - } - if (!g_hash_table_add(*idx, (gpointer) NMP_OBJECT_UP_CAST(a))) - nm_assert_not_reached(); - } - any_addrs = TRUE; - continue; - -clear_and_next: - nmp_object_unref(g_steal_pointer(&array->pdata[i])); - } - - return any_addrs; -} - -static gboolean -ip4_addr_subnets_is_plain_address(const GPtrArray *addresses, gconstpointer needle) -{ - return needle >= (gconstpointer) &addresses->pdata[0] - && needle < (gconstpointer) &addresses->pdata[addresses->len]; -} - -static const NMPObject ** -ip4_addr_subnets_addr_list_get(const GPtrArray *addr_list, guint idx) -{ - nm_assert(addr_list); - nm_assert(addr_list->len > 1); - nm_assert(idx < addr_list->len); - nm_assert(addr_list->pdata[idx]); - nm_assert(!(*((gpointer *) addr_list->pdata[idx])) - || NMP_OBJECT_CAST_IP4_ADDRESS(*((gpointer *) addr_list->pdata[idx]))); - nm_assert(idx == 0 || ip4_addr_subnets_addr_list_get(addr_list, idx - 1)); - return addr_list->pdata[idx]; -} - -static void -ip4_addr_subnets_destroy_index(GHashTable *subnets, const GPtrArray *addresses) -{ - GHashTableIter iter; - gpointer p; - - if (!subnets) - return; - - g_hash_table_iter_init(&iter, subnets); - while (g_hash_table_iter_next(&iter, NULL, &p)) { - if (!ip4_addr_subnets_is_plain_address(addresses, p)) - g_ptr_array_free((GPtrArray *) p, TRUE); - } - - g_hash_table_unref(subnets); -} - -static GHashTable * -ip4_addr_subnets_build_index(const GPtrArray *addresses, - gboolean consider_flags, - gboolean full_index) -{ - GHashTable *subnets; - guint i; - - nm_assert(addresses && addresses->len); - - subnets = g_hash_table_new(nm_direct_hash, NULL); - - /* Build a hash table of all addresses per subnet */ - for (i = 0; i < addresses->len; i++) { - const NMPlatformIP4Address *address; - gpointer p_address; - GPtrArray * addr_list; - guint32 net; - int position; - gpointer p; - - if (!addresses->pdata[i]) - continue; - - p_address = &addresses->pdata[i]; - address = NMP_OBJECT_CAST_IP4_ADDRESS(addresses->pdata[i]); - - net = address->address & _nm_utils_ip4_prefix_to_netmask(address->plen); - if (!g_hash_table_lookup_extended(subnets, GUINT_TO_POINTER(net), NULL, &p)) { - g_hash_table_insert(subnets, GUINT_TO_POINTER(net), p_address); - continue; - } - nm_assert(p); - - if (full_index) { - if (ip4_addr_subnets_is_plain_address(addresses, p)) { - addr_list = g_ptr_array_new(); - g_hash_table_insert(subnets, GUINT_TO_POINTER(net), addr_list); - g_ptr_array_add(addr_list, p); - } else - addr_list = p; - - if (!consider_flags || NM_FLAGS_HAS(address->n_ifa_flags, IFA_F_SECONDARY)) - position = -1; /* append */ - else - position = 0; /* prepend */ - g_ptr_array_insert(addr_list, position, p_address); - } else { - /* we only care about the primary. No need to track the secondaries - * as a GPtrArray. */ - nm_assert(ip4_addr_subnets_is_plain_address(addresses, p)); - if (consider_flags && !NM_FLAGS_HAS(address->n_ifa_flags, IFA_F_SECONDARY)) { - g_hash_table_insert(subnets, GUINT_TO_POINTER(net), p_address); - } - } - } - - return subnets; -} - -/** - * ip4_addr_subnets_is_secondary: - * @address: an address - * @subnets: the hash table mapping subnets to addresses - * @addresses: array of addresses in the hash table - * @out_addr_list: array of addresses belonging to the same subnet - * - * Checks whether @address is secondary and returns in @out_addr_list the list of addresses - * belonging to the same subnet, if it contains other elements. - * - * Returns: %TRUE if the address is secondary, %FALSE otherwise - */ -static gboolean -ip4_addr_subnets_is_secondary(const NMPObject * address, - GHashTable * subnets, - const GPtrArray * addresses, - const GPtrArray **out_addr_list) -{ - const NMPlatformIP4Address *a; - const GPtrArray * addr_list; - gconstpointer p; - guint32 net; - const NMPObject ** o; - - a = NMP_OBJECT_CAST_IP4_ADDRESS(address); - - net = a->address & _nm_utils_ip4_prefix_to_netmask(a->plen); - p = g_hash_table_lookup(subnets, GUINT_TO_POINTER(net)); - nm_assert(p); - if (!ip4_addr_subnets_is_plain_address(addresses, p)) { - addr_list = p; - nm_assert(addr_list->len > 1); - NM_SET_OUT(out_addr_list, addr_list); - o = ip4_addr_subnets_addr_list_get(addr_list, 0); - nm_assert(o && *o); - if (*o != address) - return TRUE; - } else { - NM_SET_OUT(out_addr_list, NULL); - return address != *((gconstpointer *) p); - } - return FALSE; -} - -typedef enum { - IP6_ADDR_SCOPE_LOOPBACK, - IP6_ADDR_SCOPE_LINKLOCAL, - IP6_ADDR_SCOPE_SITELOCAL, - IP6_ADDR_SCOPE_OTHER, -} IP6AddrScope; - -static IP6AddrScope -ip6_address_scope(const NMPlatformIP6Address *a) -{ - if (IN6_IS_ADDR_LOOPBACK(&a->address)) - return IP6_ADDR_SCOPE_LOOPBACK; - if (IN6_IS_ADDR_LINKLOCAL(&a->address)) - return IP6_ADDR_SCOPE_LINKLOCAL; - if (IN6_IS_ADDR_SITELOCAL(&a->address)) - return IP6_ADDR_SCOPE_SITELOCAL; - return IP6_ADDR_SCOPE_OTHER; -} - -static int -ip6_address_scope_cmp(gconstpointer p_a, gconstpointer p_b, gpointer increasing) -{ - const NMPlatformIP6Address *a; - const NMPlatformIP6Address *b; - - if (!increasing) - NM_SWAP(&p_a, &p_b); - - a = NMP_OBJECT_CAST_IP6_ADDRESS(*(const NMPObject *const *) p_a); - b = NMP_OBJECT_CAST_IP6_ADDRESS(*(const NMPObject *const *) p_b); - - NM_CMP_DIRECT(ip6_address_scope(a), ip6_address_scope(b)); - return 0; -} - -/** - * nm_platform_ip_address_sync: - * @self: platform instance - * @addr_family: the address family AF_INET or AF_INET6. - * @ifindex: Interface index - * @known_addresses: List of addresses. The list will be modified and only - * addresses that were successfully added will be kept in the list. - * That means, expired addresses and addresses that could not be added - * will be dropped. - * Hence, the input argument @known_addresses is also an output argument - * telling which addresses were successfully added. - * Addresses are removed by unrefing the instance via nmp_object_unref() - * and leaving a NULL tombstone. - * @addresses_prune: (allow-none): the list of addresses to delete. - * If platform has such an address configured, it will be deleted - * at the beginning of the sync. Note that the array will be modified - * by the function. - * Note that the addresses must be properly sorted, by their priority. - * Create this list with nm_platform_ip_address_get_prune_list() which - * gets the sorting right. - * - * A convenience function to synchronize addresses for a specific interface - * with the least possible disturbance. It simply removes addresses that are - * not listed and adds addresses that are. - * - * Returns: %TRUE on success. - */ -gboolean -nm_platform_ip_address_sync(NMPlatform *self, - int addr_family, - int ifindex, - GPtrArray * known_addresses, - GPtrArray * addresses_prune) -{ - const gint32 now = nm_utils_get_monotonic_timestamp_sec(); - const int IS_IPv4 = NM_IS_IPv4(addr_family); - gs_unref_hashtable GHashTable *known_addresses_idx = NULL; - GPtrArray * plat_addresses; - GHashTable * known_subnets = NULL; - guint32 ifa_flags; - guint i_plat; - guint i_know; - guint i; - guint j; - - _CHECK_SELF(self, klass, FALSE); - - /* The order we want to enforce is only among addresses with the same - * scope, as the kernel keeps addresses sorted by scope. Therefore, - * apply the same sorting to known addresses, so that we don't try to - * unnecessary change the order of addresses with different scopes. */ - if (!IS_IPv4) { - if (known_addresses) - g_ptr_array_sort_with_data(known_addresses, - ip6_address_scope_cmp, - GINT_TO_POINTER(TRUE)); - } - - if (!_addr_array_clean_expired(addr_family, - ifindex, - known_addresses, - now, - &known_addresses_idx)) - known_addresses = NULL; - - /* @plat_addresses must be sorted in decreasing priority order (highest priority addresses first), contrary to - * @known_addresses which is in increasing priority order (lowest priority addresses first). */ - plat_addresses = addresses_prune; - - if (nm_g_ptr_array_len(plat_addresses) > 0) { - /* Delete unknown addresses */ - if (IS_IPv4) { - GHashTable *plat_subnets; - - plat_subnets = ip4_addr_subnets_build_index(plat_addresses, TRUE, TRUE); - - for (i = 0; i < plat_addresses->len; i++) { - const NMPObject * plat_obj; - const NMPlatformIP4Address *plat_address; - const GPtrArray * addr_list; - - plat_obj = plat_addresses->pdata[i]; - if (!plat_obj) { - /* Already deleted */ - continue; - } - - plat_address = NMP_OBJECT_CAST_IP4_ADDRESS(plat_obj); - - if (known_addresses) { - const NMPObject *o; - - o = g_hash_table_lookup(known_addresses_idx, plat_obj); - if (o) { - gboolean secondary; - - if (!known_subnets) - known_subnets = - ip4_addr_subnets_build_index(known_addresses, FALSE, FALSE); - - secondary = - ip4_addr_subnets_is_secondary(o, known_subnets, known_addresses, NULL); - if (secondary == NM_FLAGS_HAS(plat_address->n_ifa_flags, IFA_F_SECONDARY)) { - /* if we have an existing known-address, with matching secondary role, - * do not delete the platform-address. */ - continue; - } - } - } - - nm_platform_ip4_address_delete(self, - ifindex, - plat_address->address, - plat_address->plen, - plat_address->peer_address); - - if (!ip4_addr_subnets_is_secondary(plat_obj, - plat_subnets, - plat_addresses, - &addr_list) - && addr_list) { - /* If we just deleted a primary addresses and there were - * secondary ones the kernel can do two things, depending on - * version and sysctl setting: delete also secondary addresses - * or promote a secondary to primary. Ensure that secondary - * addresses are deleted, so that we can start with a clean - * slate and add addresses in the right order. */ - for (j = 1; j < addr_list->len; j++) { - const NMPObject **o; - - o = ip4_addr_subnets_addr_list_get(addr_list, j); - nm_assert(o); - - if (*o) { - const NMPlatformIP4Address *a; - - a = NMP_OBJECT_CAST_IP4_ADDRESS(*o); - nm_platform_ip4_address_delete(self, - ifindex, - a->address, - a->plen, - a->peer_address); - nmp_object_unref(*o); - *o = NULL; - } - } - } - } - ip4_addr_subnets_destroy_index(plat_subnets, plat_addresses); - } else { - guint known_addresses_len; - IP6AddrScope cur_scope; - gboolean delete_remaining_addrs; - - g_ptr_array_sort_with_data(plat_addresses, - ip6_address_scope_cmp, - GINT_TO_POINTER(FALSE)); - - known_addresses_len = known_addresses ? known_addresses->len : 0; - - /* First, compare every address whether it is still a "known address", that is, whether - * to keep it or to delete it. - * - * If we don't find a matching valid address in @known_addresses, we will delete - * plat_addr. - * - * Certain addresses, like temporary addresses, are ignored by this function - * if not run with full_sync. These addresses are usually not managed by NetworkManager - * directly, or at least, they are not managed via nm_platform_ip6_address_sync(). - * Only in full_sync mode, we really want to get rid of them (usually, when we take - * the interface down). - * - * Note that we mark handled addresses by setting it to %NULL in @plat_addresses array. */ - for (i_plat = 0; i_plat < plat_addresses->len; i_plat++) { - const NMPObject * plat_obj = plat_addresses->pdata[i_plat]; - const NMPObject * know_obj; - const NMPlatformIP6Address *plat_addr = NMP_OBJECT_CAST_IP6_ADDRESS(plat_obj); - - if (known_addresses_idx) { - know_obj = g_hash_table_lookup(known_addresses_idx, plat_obj); - if (know_obj - && plat_addr->plen == NMP_OBJECT_CAST_IP6_ADDRESS(know_obj)->plen) { - /* technically, plen is not part of the ID for IPv6 addresses and thus - * @plat_addr is essentially the same address as @know_addr (regrading - * its identity, not its other attributes). - * However, we cannot modify an existing addresses' plen without - * removing and readding it. Thus, only keep plat_addr, if the plen - * matches. - * - * keep this one, and continue */ - continue; - } - } - - nm_platform_ip6_address_delete(self, ifindex, plat_addr->address, plat_addr->plen); - nmp_object_unref(g_steal_pointer(&plat_addresses->pdata[i_plat])); - } - - /* Next, we must preserve the priority of the routes. That is, source address - * selection will choose addresses in the order as they are reported by kernel. - * Note that the order in @plat_addresses of the remaining matches is highest - * priority first. - * We need to compare this to the order of addresses with same scope in - * @known_addresses (which has lowest priority first). - * - * If we find a first discrepancy, we need to delete all remaining addresses - * with same scope from that point on, because below we must re-add all the - * addresses in the right order to get their priority right. */ - cur_scope = IP6_ADDR_SCOPE_LOOPBACK; - delete_remaining_addrs = FALSE; - i_plat = plat_addresses->len; - i_know = 0; - while (i_plat > 0) { - const NMPlatformIP6Address *plat_addr = - NMP_OBJECT_CAST_IP6_ADDRESS(plat_addresses->pdata[--i_plat]); - IP6AddrScope plat_scope; - - if (!plat_addr) - continue; - - plat_scope = ip6_address_scope(plat_addr); - if (cur_scope != plat_scope) { - nm_assert(cur_scope < plat_scope); - delete_remaining_addrs = FALSE; - cur_scope = plat_scope; - } - - if (!delete_remaining_addrs) { - delete_remaining_addrs = TRUE; - for (; i_know < known_addresses_len; i_know++) { - const NMPlatformIP6Address *know_addr = - NMP_OBJECT_CAST_IP6_ADDRESS(known_addresses->pdata[i_know]); - IP6AddrScope know_scope; - - if (!know_addr) - continue; - - know_scope = ip6_address_scope(know_addr); - if (know_scope < plat_scope) - continue; - - if (IN6_ARE_ADDR_EQUAL(&plat_addr->address, &know_addr->address)) { - /* we have a match. Mark address as handled. */ - i_know++; - delete_remaining_addrs = FALSE; - goto next_plat; - } - - /* plat_address has no match. Now delete_remaining_addrs is TRUE and we will - * delete all the remaining addresses with cur_scope. */ - break; - } - } - - nm_platform_ip6_address_delete(self, ifindex, plat_addr->address, plat_addr->plen); -next_plat:; - } - } - } - - if (!known_addresses) - return TRUE; - - if (IS_IPv4) - ip4_addr_subnets_destroy_index(known_subnets, known_addresses); - - ifa_flags = nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS) - ? IFA_F_NOPREFIXROUTE - : 0; - - /* Add missing addresses. New addresses are added by kernel with top - * priority. - */ - for (i_know = 0; i_know < known_addresses->len; i_know++) { - const NMPlatformIPXAddress *known_address; - const NMPObject * o; - guint32 lifetime; - guint32 preferred; - - o = known_addresses->pdata[i_know]; - if (!o) - continue; - - nm_assert(NMP_OBJECT_GET_TYPE(o) == NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4)); - - known_address = NMP_OBJECT_CAST_IPX_ADDRESS(o); - - lifetime = nm_utils_lifetime_get(known_address->ax.timestamp, - known_address->ax.lifetime, - known_address->ax.preferred, - now, - &preferred); - nm_assert(lifetime > 0); - - if (IS_IPv4) { - if (!nm_platform_ip4_address_add( - self, - ifindex, - known_address->a4.address, - known_address->a4.plen, - known_address->a4.peer_address, - nm_platform_ip4_broadcast_address_from_addr(&known_address->a4), - lifetime, - preferred, - ifa_flags, - known_address->a4.label)) { - /* ignore error, for unclear reasons. */ - } - } else { - if (!nm_platform_ip6_address_add(self, - ifindex, - known_address->a6.address, - known_address->a6.plen, - known_address->a6.peer_address, - lifetime, - preferred, - ifa_flags | known_address->a6.n_ifa_flags)) - return FALSE; - } - } - - return TRUE; -} - -gboolean -nm_platform_ip_address_flush(NMPlatform *self, int addr_family, int ifindex) -{ - gboolean success = TRUE; - - _CHECK_SELF(self, klass, FALSE); - - nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6)); - - if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET)) - success &= nm_platform_ip4_address_sync(self, ifindex, NULL); - if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET6)) - success &= nm_platform_ip6_address_sync(self, ifindex, NULL, TRUE); - return success; -} - -/*****************************************************************************/ - -static gboolean -_err_inval_due_to_ipv6_tentative_pref_src(NMPlatform *self, const NMPObject *obj) -{ - const NMPlatformIP6Route * r; - const NMPlatformIP6Address *a; - - nm_assert(NM_IS_PLATFORM(self)); - nm_assert(NMP_OBJECT_IS_VALID(obj)); - - /* trying to add an IPv6 route with pref-src fails, if the address is - * still tentative (rh#1452684). We need to hack around that. - * - * Detect it, by guessing whether that's the case. */ - - if (NMP_OBJECT_GET_TYPE(obj) != NMP_OBJECT_TYPE_IP6_ROUTE) - return FALSE; - - r = NMP_OBJECT_CAST_IP6_ROUTE(obj); - - /* we only allow this workaround for routes added manually by the user. */ - if (r->rt_source != NM_IP_CONFIG_SOURCE_USER) - return FALSE; - - if (IN6_IS_ADDR_UNSPECIFIED(&r->pref_src)) - return FALSE; - - a = nm_platform_ip6_address_get(self, r->ifindex, &r->pref_src); - if (!a) - return FALSE; - if (!NM_FLAGS_HAS(a->n_ifa_flags, IFA_F_TENTATIVE) - || NM_FLAGS_HAS(a->n_ifa_flags, IFA_F_DADFAILED)) - return FALSE; - - return TRUE; -} - -GPtrArray * -nm_platform_ip_address_get_prune_list(NMPlatform *self, - int addr_family, - int ifindex, - gboolean exclude_ipv6_temporary_addrs) -{ - const int IS_IPv4 = NM_IS_IPv4(addr_family); - const NMDedupMultiHeadEntry *head_entry; - NMPLookup lookup; - GPtrArray * result; - CList * iter; - - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP_ADDRESS(NM_IS_IPv4(addr_family)), ifindex); - - head_entry = nm_platform_lookup(self, &lookup); - - if (!head_entry) - return NULL; - - result = g_ptr_array_new_full(head_entry->len, (GDestroyNotify) nmp_object_unref); - - c_list_for_each (iter, &head_entry->lst_entries_head) { - const NMPObject *obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj; - - if (!IS_IPv4) { - if (exclude_ipv6_temporary_addrs - && NM_FLAGS_HAS(NMP_OBJECT_CAST_IP_ADDRESS(obj)->n_ifa_flags, IFA_F_TEMPORARY)) - continue; - } - - g_ptr_array_add(result, (gpointer) nmp_object_ref(obj)); - } - - if (result->len == 0) { - g_ptr_array_unref(result); - return NULL; - } - return result; -} - -GPtrArray * -nm_platform_ip_route_get_prune_list(NMPlatform * self, - int addr_family, - int ifindex, - NMIPRouteTableSyncMode route_table_sync) -{ - NMPLookup lookup; - GPtrArray * routes_prune; - const NMDedupMultiHeadEntry *head_entry; - CList * iter; - - nm_assert(NM_IS_PLATFORM(self)); - nm_assert(NM_IN_SET(addr_family, AF_INET, AF_INET6)); - nm_assert(NM_IN_SET(route_table_sync, - NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN, - NM_IP_ROUTE_TABLE_SYNC_MODE_FULL, - NM_IP_ROUTE_TABLE_SYNC_MODE_ALL)); - - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP_ROUTE(NM_IS_IPv4(addr_family)), ifindex); - head_entry = nm_platform_lookup(self, &lookup); - if (!head_entry) - return NULL; - - routes_prune = g_ptr_array_new_full(head_entry->len, (GDestroyNotify) nm_dedup_multi_obj_unref); - - c_list_for_each (iter, &head_entry->lst_entries_head) { - const NMPObject *obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj; - - if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_FULL) { - if (nm_platform_ip_route_get_effective_table(NMP_OBJECT_CAST_IP_ROUTE(obj)) - == RT_TABLE_LOCAL) - continue; - } else if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN) { - if (!nm_platform_route_table_is_main( - nm_platform_ip_route_get_effective_table(NMP_OBJECT_CAST_IP_ROUTE(obj)))) - continue; - } else - nm_assert(route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_ALL); - - g_ptr_array_add(routes_prune, (gpointer) nmp_object_ref(obj)); - } - - if (routes_prune->len == 0) { - g_ptr_array_unref(routes_prune); - return NULL; - } - return routes_prune; -} - -/** - * nm_platform_ip_route_sync: - * @self: the #NMPlatform instance. - * @addr_family: AF_INET or AF_INET6. - * @ifindex: the @ifindex for which the routes are to be added. - * @routes: (allow-none): a list of routes to configure. Must contain - * NMPObject instances of routes, according to @addr_family. - * @routes_prune: (allow-none): the list of routes to delete. - * If platform has such a route configured, it will be deleted - * at the end of the operation. Note that if @routes contains - * the same route, then it will not be deleted. @routes overrules - * @routes_prune list. - * @out_temporary_not_available: (allow-none) (out): routes that could - * currently not be synced. The caller shall keep them and try later again. - * - * Returns: %TRUE on success. - */ -gboolean -nm_platform_ip_route_sync(NMPlatform *self, - int addr_family, - int ifindex, - GPtrArray * routes, - GPtrArray * routes_prune, - GPtrArray **out_temporary_not_available) -{ - const int IS_IPv4 = NM_IS_IPv4(addr_family); - const NMPlatformVTableRoute *vt; - gs_unref_hashtable GHashTable *routes_idx = NULL; - const NMPObject * conf_o; - const NMDedupMultiEntry * plat_entry; - guint i; - int i_type; - gboolean success = TRUE; - char sbuf1[sizeof(_nm_utils_to_string_buffer)]; - char sbuf2[sizeof(_nm_utils_to_string_buffer)]; - - nm_assert(NM_IS_PLATFORM(self)); - nm_assert(ifindex > 0); - - vt = &nm_platform_vtable_route.vx[IS_IPv4]; - - for (i_type = 0; routes && i_type < 2; i_type++) { - for (i = 0; i < routes->len; i++) { - int r, r2; - gboolean gateway_route_added = FALSE; - - conf_o = routes->pdata[i]; - -#define VTABLE_IS_DEVICE_ROUTE(vt, o) \ - (vt->is_ip4 ? (NMP_OBJECT_CAST_IP4_ROUTE(o)->gateway == 0) \ - : IN6_IS_ADDR_UNSPECIFIED(&NMP_OBJECT_CAST_IP6_ROUTE(o)->gateway)) - - if ((i_type == 0 && !VTABLE_IS_DEVICE_ROUTE(vt, conf_o)) - || (i_type == 1 && VTABLE_IS_DEVICE_ROUTE(vt, conf_o))) { - /* we add routes in two runs over @i_type. - * - * First device routes, then gateway routes. */ - continue; - } - - if (!routes_idx) { - routes_idx = g_hash_table_new((GHashFunc) nmp_object_id_hash, - (GEqualFunc) nmp_object_id_equal); - } - if (!g_hash_table_insert(routes_idx, (gpointer) conf_o, (gpointer) conf_o)) { - _LOG3D("route-sync: skip adding duplicate route %s", - nmp_object_to_string(conf_o, - NMP_OBJECT_TO_STRING_PUBLIC, - sbuf1, - sizeof(sbuf1))); - continue; - } - - if (!IS_IPv4 - && nm_platform_ip6_route_get_effective_metric(NMP_OBJECT_CAST_IP6_ROUTE(conf_o)) - == 0) { - /* User space cannot add routes with metric 0. However, kernel can, and we might track such - * routes in @route as they are present external. Skip them silently. */ - continue; - } - - plat_entry = nm_platform_lookup_entry(self, NMP_CACHE_ID_TYPE_OBJECT_TYPE, conf_o); - if (plat_entry) { - const NMPObject *plat_o; - - plat_o = plat_entry->obj; - - if (vt->route_cmp(NMP_OBJECT_CAST_IPX_ROUTE(conf_o), - NMP_OBJECT_CAST_IPX_ROUTE(plat_o), - NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) - == 0) - continue; - - /* we need to replace the existing route with a (slightly) different - * one. Delete it first. */ - if (!nm_platform_object_delete(self, plat_o)) { - /* ignore error. */ - } - } - -sync_route_add: - r = nm_platform_ip_route_add(self, - NMP_NLM_FLAG_APPEND - | NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE, - conf_o); - if (r < 0) { - if (r == -EEXIST) { - /* Don't fail for EEXIST. It's not clear that the existing route - * is identical to the one that we were about to add. However, - * above we should have deleted conflicting (non-identical) routes. */ - if (_LOGD_ENABLED()) { - plat_entry = - nm_platform_lookup_entry(self, NMP_CACHE_ID_TYPE_OBJECT_TYPE, conf_o); - if (!plat_entry) { - _LOG3D("route-sync: adding route %s failed with EEXIST, however we " - "cannot find such a route", - nmp_object_to_string(conf_o, - NMP_OBJECT_TO_STRING_PUBLIC, - sbuf1, - sizeof(sbuf1))); - } else if (vt->route_cmp(NMP_OBJECT_CAST_IPX_ROUTE(conf_o), - NMP_OBJECT_CAST_IPX_ROUTE(plat_entry->obj), - NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) - != 0) { - _LOG3D("route-sync: adding route %s failed due to existing " - "(different!) route %s", - nmp_object_to_string(conf_o, - NMP_OBJECT_TO_STRING_PUBLIC, - sbuf1, - sizeof(sbuf1)), - nmp_object_to_string(plat_entry->obj, - NMP_OBJECT_TO_STRING_PUBLIC, - sbuf2, - sizeof(sbuf2))); - } - } - } else if (NMP_OBJECT_CAST_IP_ROUTE(conf_o)->rt_source < NM_IP_CONFIG_SOURCE_USER) { - _LOG3D("route-sync: ignore failure to add IPv%c route: %s: %s", - vt->is_ip4 ? '4' : '6', - nmp_object_to_string(conf_o, - NMP_OBJECT_TO_STRING_PUBLIC, - sbuf1, - sizeof(sbuf1)), - nm_strerror(r)); - } else if (r == -EINVAL && out_temporary_not_available - && _err_inval_due_to_ipv6_tentative_pref_src(self, conf_o)) { - _LOG3D("route-sync: ignore failure to add IPv6 route with tentative IPv6 " - "pref-src: %s: %s", - nmp_object_to_string(conf_o, - NMP_OBJECT_TO_STRING_PUBLIC, - sbuf1, - sizeof(sbuf1)), - nm_strerror(r)); - if (!*out_temporary_not_available) - *out_temporary_not_available = - g_ptr_array_new_full(0, (GDestroyNotify) nmp_object_unref); - g_ptr_array_add(*out_temporary_not_available, - (gpointer) nmp_object_ref(conf_o)); - } else if (!gateway_route_added - && ((r == -ENETUNREACH && vt->is_ip4 - && !!NMP_OBJECT_CAST_IP4_ROUTE(conf_o)->gateway) - || (r == -EHOSTUNREACH && !vt->is_ip4 - && !IN6_IS_ADDR_UNSPECIFIED( - &NMP_OBJECT_CAST_IP6_ROUTE(conf_o)->gateway)))) { - NMPObject oo; - - if (vt->is_ip4) { - const NMPlatformIP4Route *rt = NMP_OBJECT_CAST_IP4_ROUTE(conf_o); - - nmp_object_stackinit( - &oo, - NMP_OBJECT_TYPE_IP4_ROUTE, - &((NMPlatformIP4Route){ - .ifindex = rt->ifindex, - .network = rt->gateway, - .plen = 32, - .metric = nm_platform_ip4_route_get_effective_metric(rt), - .rt_source = rt->rt_source, - .table_coerced = nm_platform_ip_route_get_effective_table( - NM_PLATFORM_IP_ROUTE_CAST(rt)), - })); - } else { - const NMPlatformIP6Route *rt = NMP_OBJECT_CAST_IP6_ROUTE(conf_o); - - nmp_object_stackinit( - &oo, - NMP_OBJECT_TYPE_IP6_ROUTE, - &((NMPlatformIP6Route){ - .ifindex = rt->ifindex, - .network = rt->gateway, - .plen = 128, - .metric = nm_platform_ip6_route_get_effective_metric(rt), - .rt_source = rt->rt_source, - .table_coerced = nm_platform_ip_route_get_effective_table( - NM_PLATFORM_IP_ROUTE_CAST(rt)), - })); - } - - _LOG3D("route-sync: failure to add IPv%c route: %s: %s; try adding direct " - "route to gateway %s", - vt->is_ip4 ? '4' : '6', - nmp_object_to_string(conf_o, - NMP_OBJECT_TO_STRING_PUBLIC, - sbuf1, - sizeof(sbuf1)), - nm_strerror(r), - nmp_object_to_string(&oo, - NMP_OBJECT_TO_STRING_PUBLIC, - sbuf2, - sizeof(sbuf2))); - - r2 = nm_platform_ip_route_add(self, - NMP_NLM_FLAG_APPEND - | NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE, - &oo); - - if (r2 < 0) { - _LOG3D("route-sync: failure to add gateway IPv%c route: %s: %s", - vt->is_ip4 ? '4' : '6', - nmp_object_to_string(conf_o, - NMP_OBJECT_TO_STRING_PUBLIC, - sbuf1, - sizeof(sbuf1)), - nm_strerror(r2)); - } - - gateway_route_added = TRUE; - goto sync_route_add; - } else { - _LOG3W("route-sync: failure to add IPv%c route: %s: %s", - vt->is_ip4 ? '4' : '6', - nmp_object_to_string(conf_o, - NMP_OBJECT_TO_STRING_PUBLIC, - sbuf1, - sizeof(sbuf1)), - nm_strerror(r)); - success = FALSE; - } - } - } - } - - if (routes_prune) { - for (i = 0; i < routes_prune->len; i++) { - const NMPObject *prune_o; - - prune_o = routes_prune->pdata[i]; - - nm_assert((NM_IS_IPv4(addr_family) - && NMP_OBJECT_GET_TYPE(prune_o) == NMP_OBJECT_TYPE_IP4_ROUTE) - || (!NM_IS_IPv4(addr_family) - && NMP_OBJECT_GET_TYPE(prune_o) == NMP_OBJECT_TYPE_IP6_ROUTE)); - - if (routes_idx && g_hash_table_lookup(routes_idx, prune_o)) - continue; - - if (!nm_platform_lookup_entry(self, NMP_CACHE_ID_TYPE_OBJECT_TYPE, prune_o)) - continue; - - if (!nm_platform_object_delete(self, prune_o)) { - /* ignore error... */ - } - } - } - - return success; -} - -gboolean -nm_platform_ip_route_flush(NMPlatform *self, int addr_family, int ifindex) -{ - gboolean success = TRUE; - - _CHECK_SELF(self, klass, FALSE); - - nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6)); - - if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET)) { - gs_unref_ptrarray GPtrArray *routes_prune = NULL; - - routes_prune = nm_platform_ip_route_get_prune_list(self, - AF_INET, - ifindex, - NM_IP_ROUTE_TABLE_SYNC_MODE_ALL); - success &= nm_platform_ip_route_sync(self, AF_INET, ifindex, NULL, routes_prune, NULL); - } - if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET6)) { - gs_unref_ptrarray GPtrArray *routes_prune = NULL; - - routes_prune = nm_platform_ip_route_get_prune_list(self, - AF_INET6, - ifindex, - NM_IP_ROUTE_TABLE_SYNC_MODE_ALL); - success &= nm_platform_ip_route_sync(self, AF_INET6, ifindex, NULL, routes_prune, NULL); - } - return success; -} - -/*****************************************************************************/ - -static guint8 -_ip_route_scope_inv_get_normalized(const NMPlatformIP4Route *route) -{ - /* in kernel, you cannot set scope to RT_SCOPE_NOWHERE (255). - * That means, in NM, we treat RT_SCOPE_NOWHERE as unset, and detect - * it based on the presence of the gateway. In other words, when adding - * a route with scope RT_SCOPE_NOWHERE (in NetworkManager) to kernel, - * the resulting scope will be either "link" or "universe" (depending - * on the gateway). - * - * Note that internally, we track @scope_inv is the inverse of scope, - * so that the default equals zero (~(RT_SCOPE_NOWHERE)). - **/ - if (route->scope_inv == 0) { - if (route->type_coerced == nm_platform_route_type_coerce(RTN_LOCAL)) - return nm_platform_route_scope_inv(RT_SCOPE_HOST); - else { - return nm_platform_route_scope_inv(!route->gateway ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE); - } - } - return route->scope_inv; -} - -static guint8 -_route_pref_normalize(guint8 pref) -{ - /* for kernel (and ICMPv6) pref can only have one of 3 values. Normalize. */ - return NM_IN_SET(pref, NM_ICMPV6_ROUTER_PREF_LOW, NM_ICMPV6_ROUTER_PREF_HIGH) - ? pref - : NM_ICMPV6_ROUTER_PREF_MEDIUM; -} - -/** - * nm_platform_ip_route_normalize: - * @addr_family: AF_INET or AF_INET6 - * @route: an NMPlatformIP4Route or NMPlatformIP6Route instance, depending on @addr_family. - * - * Adding a route to kernel via nm_platform_ip_route_add() will normalize/coerce some - * properties of the route. This function modifies (normalizes) the route like it - * would be done by adding the route in kernel. - * - * Note that this function is related to NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY - * in that if two routes compare semantically equal, after normalizing they also shall - * compare equal with NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL. - */ -void -nm_platform_ip_route_normalize(int addr_family, NMPlatformIPRoute *route) -{ - NMPlatformIP4Route *r4; - NMPlatformIP6Route *r6; - - route->table_coerced = - nm_platform_route_table_coerce(nm_platform_ip_route_get_effective_table(route)); - route->table_any = FALSE; - - route->rt_source = nmp_utils_ip_config_source_round_trip_rtprot(route->rt_source); - - switch (addr_family) { - case AF_INET: - r4 = (NMPlatformIP4Route *) route; - route->metric = nm_platform_ip4_route_get_effective_metric(r4); - route->metric_any = FALSE; - r4->network = nm_utils_ip4_address_clear_host_address(r4->network, r4->plen); - r4->scope_inv = _ip_route_scope_inv_get_normalized(r4); - break; - case AF_INET6: - r6 = (NMPlatformIP6Route *) route; - route->metric = nm_platform_ip6_route_get_effective_metric(r6); - route->metric_any = FALSE; - nm_utils_ip6_address_clear_host_address(&r6->network, &r6->network, r6->plen); - nm_utils_ip6_address_clear_host_address(&r6->src, &r6->src, r6->src_plen); - break; - default: - nm_assert_not_reached(); - break; - } -} - -static int -_ip_route_add(NMPlatform *self, NMPNlmFlags flags, int addr_family, gconstpointer route) -{ - char sbuf[sizeof(_nm_utils_to_string_buffer)]; - int ifindex; - - _CHECK_SELF(self, klass, FALSE); - - nm_assert(route); - nm_assert(NM_IN_SET(addr_family, AF_INET, AF_INET6)); - - ifindex = ((const NMPlatformIPRoute *) route)->ifindex; - _LOG3D("route: %-10s IPv%c route: %s", - _nmp_nlm_flag_to_string(flags & NMP_NLM_FLAG_FMASK), - nm_utils_addr_family_to_char(addr_family), - NM_IS_IPv4(addr_family) ? nm_platform_ip4_route_to_string(route, sbuf, sizeof(sbuf)) - : nm_platform_ip6_route_to_string(route, sbuf, sizeof(sbuf))); - - return klass->ip_route_add(self, flags, addr_family, route); -} - -int -nm_platform_ip_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPObject *route) -{ - int addr_family; - - switch (NMP_OBJECT_GET_TYPE(route)) { - case NMP_OBJECT_TYPE_IP4_ROUTE: - addr_family = AF_INET; - break; - case NMP_OBJECT_TYPE_IP6_ROUTE: - addr_family = AF_INET6; - break; - default: - g_return_val_if_reached(FALSE); - } - - return _ip_route_add(self, flags, addr_family, NMP_OBJECT_CAST_IP_ROUTE(route)); -} - -int -nm_platform_ip4_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP4Route *route) -{ - return _ip_route_add(self, flags, AF_INET, route); -} - -int -nm_platform_ip6_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP6Route *route) -{ - return _ip_route_add(self, flags, AF_INET6, route); -} - -gboolean -nm_platform_object_delete(NMPlatform *self, const NMPObject *obj) -{ - int ifindex; - - _CHECK_SELF(self, klass, FALSE); - - switch (NMP_OBJECT_GET_TYPE(obj)) { - case NMP_OBJECT_TYPE_ROUTING_RULE: - _LOGD("%s: delete %s", - NMP_OBJECT_GET_CLASS(obj)->obj_type_name, - nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - break; - case NMP_OBJECT_TYPE_IP4_ROUTE: - case NMP_OBJECT_TYPE_IP6_ROUTE: - case NMP_OBJECT_TYPE_QDISC: - case NMP_OBJECT_TYPE_TFILTER: - ifindex = NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj)->ifindex; - _LOG3D("%s: delete %s", - NMP_OBJECT_GET_CLASS(obj)->obj_type_name, - nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - break; - default: - g_return_val_if_reached(FALSE); - } - - return klass->object_delete(self, obj); -} - -/*****************************************************************************/ - -int -nm_platform_ip_route_get(NMPlatform * self, - int addr_family, - gconstpointer address /* in_addr_t or struct in6_addr */, - int oif_ifindex, - NMPObject ** out_route) -{ - nm_auto_nmpobj NMPObject *route = NULL; - int result; - char buf[NM_UTILS_INET_ADDRSTRLEN]; - char buf_oif[64]; - - _CHECK_SELF(self, klass, FALSE); - - g_return_val_if_fail(address, -NME_BUG); - g_return_val_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6), -NME_BUG); - - _LOGT("route: get IPv%c route for: %s%s", - nm_utils_addr_family_to_char(addr_family), - inet_ntop(addr_family, address, buf, sizeof(buf)), - oif_ifindex > 0 ? nm_sprintf_buf(buf_oif, " oif %d", oif_ifindex) : ""); - - if (!klass->ip_route_get) - result = -NME_PL_OPNOTSUPP; - else { - result = klass->ip_route_get(self, addr_family, address, oif_ifindex, &route); - } - - if (result < 0) { - nm_assert(!route); - _LOGW("route: get IPv%c route for: %s failed with %s", - nm_utils_addr_family_to_char(addr_family), - inet_ntop(addr_family, address, buf, sizeof(buf)), - nm_strerror(result)); - } else { - nm_assert(NM_IN_SET(NMP_OBJECT_GET_TYPE(route), - NMP_OBJECT_TYPE_IP4_ROUTE, - NMP_OBJECT_TYPE_IP6_ROUTE)); - nm_assert(!NMP_OBJECT_IS_STACKINIT(route)); - nm_assert(route->parent._ref_count == 1); - _LOGD("route: get IPv%c route for: %s succeeded: %s", - nm_utils_addr_family_to_char(addr_family), - inet_ntop(addr_family, address, buf, sizeof(buf)), - nmp_object_to_string(route, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - NM_SET_OUT(out_route, g_steal_pointer(&route)); - } - return result; -} - -/*****************************************************************************/ - -#define IP4_DEV_ROUTE_BLACKLIST_TIMEOUT_MS ((int) 1500) -#define IP4_DEV_ROUTE_BLACKLIST_GC_TIMEOUT_S \ - ((int) (((IP4_DEV_ROUTE_BLACKLIST_TIMEOUT_MS + 999) * 3) / 1000)) - -static gint64 -_ip4_dev_route_blacklist_timeout_ms_get(gint64 timeout_msec) -{ - return timeout_msec >> 1; -} - -static gint64 -_ip4_dev_route_blacklist_timeout_ms_marked(gint64 timeout_msec) -{ - return !!(timeout_msec & ((gint64) 1)); -} - -static gboolean -_ip4_dev_route_blacklist_check_cb(gpointer user_data) -{ - NMPlatform * self = user_data; - NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self); - GHashTableIter iter; - const NMPObject * p_obj; - gint64 * p_timeout_ms; - gint64 now_ms; - - priv->ip4_dev_route_blacklist_check_id = 0; - -again: - if (!priv->ip4_dev_route_blacklist_hash) - goto out; - - now_ms = nm_utils_get_monotonic_timestamp_msec(); - - g_hash_table_iter_init(&iter, priv->ip4_dev_route_blacklist_hash); - while (g_hash_table_iter_next(&iter, (gpointer *) &p_obj, (gpointer *) &p_timeout_ms)) { - if (!_ip4_dev_route_blacklist_timeout_ms_marked(*p_timeout_ms)) - continue; - - /* unmark because we checked it. */ - *p_timeout_ms = *p_timeout_ms & ~((gint64) 1); - - if (now_ms > _ip4_dev_route_blacklist_timeout_ms_get(*p_timeout_ms)) - continue; - - if (!nm_platform_lookup_entry(self, NMP_CACHE_ID_TYPE_OBJECT_TYPE, p_obj)) - continue; - - _LOGT("ip4-dev-route: delete %s", - nmp_object_to_string(p_obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - nm_platform_object_delete(self, p_obj); - goto again; - } - -out: - return G_SOURCE_REMOVE; -} - -static void -_ip4_dev_route_blacklist_check_schedule(NMPlatform *self) -{ - NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self); - - if (!priv->ip4_dev_route_blacklist_check_id) { - priv->ip4_dev_route_blacklist_check_id = - g_idle_add_full(G_PRIORITY_HIGH, _ip4_dev_route_blacklist_check_cb, self, NULL); - } -} - -static void -_ip4_dev_route_blacklist_notify_route(NMPlatform *self, const NMPObject *obj) -{ - NMPlatformPrivate *priv; - const NMPObject * p_obj; - gint64 * p_timeout_ms; - gint64 now_ms; - - nm_assert(NM_IS_PLATFORM(self)); - nm_assert(NMP_OBJECT_GET_TYPE(obj) == NMP_OBJECT_TYPE_IP4_ROUTE); - - priv = NM_PLATFORM_GET_PRIVATE(self); - - nm_assert(priv->ip4_dev_route_blacklist_gc_timeout_id); - - if (!g_hash_table_lookup_extended(priv->ip4_dev_route_blacklist_hash, - obj, - (gpointer *) &p_obj, - (gpointer *) &p_timeout_ms)) - return; - - now_ms = nm_utils_get_monotonic_timestamp_msec(); - if (now_ms > _ip4_dev_route_blacklist_timeout_ms_get(*p_timeout_ms)) { - /* already expired. Wait for gc. */ - return; - } - - if (_ip4_dev_route_blacklist_timeout_ms_marked(*p_timeout_ms)) { - nm_assert(priv->ip4_dev_route_blacklist_check_id); - return; - } - - /* We cannot delete it right away because we are in the process of receiving netlink messages. - * It may be possible to do so, but complicated and error prone. - * - * Instead, we mark the entry and schedule an idle action (with high priority). */ - *p_timeout_ms = (*p_timeout_ms) | ((gint64) 1); - _ip4_dev_route_blacklist_check_schedule(self); -} - -static gboolean -_ip4_dev_route_blacklist_gc_timeout_handle(gpointer user_data) -{ - NMPlatform * self = user_data; - NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self); - GHashTableIter iter; - const NMPObject * p_obj; - gint64 * p_timeout_ms; - gint64 now_ms; - - nm_assert(priv->ip4_dev_route_blacklist_gc_timeout_id); - - now_ms = nm_utils_get_monotonic_timestamp_msec(); - - g_hash_table_iter_init(&iter, priv->ip4_dev_route_blacklist_hash); - while (g_hash_table_iter_next(&iter, (gpointer *) &p_obj, (gpointer *) &p_timeout_ms)) { - if (now_ms > _ip4_dev_route_blacklist_timeout_ms_get(*p_timeout_ms)) { - _LOGT("ip4-dev-route: cleanup %s", - nmp_object_to_string(p_obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - g_hash_table_iter_remove(&iter); - } - } - - _ip4_dev_route_blacklist_schedule(self); - return G_SOURCE_CONTINUE; -} - -static void -_ip4_dev_route_blacklist_schedule(NMPlatform *self) -{ - NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self); - - if (!priv->ip4_dev_route_blacklist_hash - || g_hash_table_size(priv->ip4_dev_route_blacklist_hash) == 0) { - nm_clear_pointer(&priv->ip4_dev_route_blacklist_hash, g_hash_table_unref); - nm_clear_g_source(&priv->ip4_dev_route_blacklist_gc_timeout_id); - } else { - if (!priv->ip4_dev_route_blacklist_gc_timeout_id) { - /* this timeout is only to garbage collect the expired entries from priv->ip4_dev_route_blacklist_hash. - * It can run infrequently, and it doesn't hurt if expired entries linger around a bit - * longer then necessary. */ - priv->ip4_dev_route_blacklist_gc_timeout_id = - g_timeout_add_seconds(IP4_DEV_ROUTE_BLACKLIST_GC_TIMEOUT_S, - _ip4_dev_route_blacklist_gc_timeout_handle, - self); - } - } -} - -/** - * nm_platform_ip4_dev_route_blacklist_set: - * @self: - * @ifindex: - * @ip4_dev_route_blacklist: - * - * When adding an IP address, kernel automatically adds a device route. - * This can be suppressed via the IFA_F_NOPREFIXROUTE address flag. For proper - * IPv6 support, we require kernel support for IFA_F_NOPREFIXROUTE and always - * add the device route manually. - * - * For IPv4, this flag is rather new and we don't rely on it yet. We want to use - * it (but currently still don't). So, for IPv4, kernel possibly adds a device - * route, however it has a wrong metric of zero. We add our own device route (with - * proper metric), but need to delete the route that kernel adds. - * - * The problem is, that kernel does not immediately add the route, when adding - * the address. It only shows up some time later. So, we register here a list - * of blacklisted routes, and when they show up within a time out, we assume it's - * the kernel generated one, and we delete it. - * - * Eventually, we want to get rid of this and use IFA_F_NOPREFIXROUTE for IPv4 - * routes as well. - */ -void -nm_platform_ip4_dev_route_blacklist_set(NMPlatform *self, - int ifindex, - GPtrArray * ip4_dev_route_blacklist) -{ - NMPlatformPrivate *priv; - GHashTableIter iter; - const NMPObject * p_obj; - guint i; - gint64 timeout_msec; - gint64 timeout_msec_val; - gint64 * p_timeout_ms; - gboolean needs_check = FALSE; - - nm_assert(NM_IS_PLATFORM(self)); - nm_assert(ifindex > 0); - - /* TODO: the blacklist should be maintained by NML3Cfg. */ - - priv = NM_PLATFORM_GET_PRIVATE(self); - - /* first, expire all for current ifindex... */ - if (priv->ip4_dev_route_blacklist_hash) { - g_hash_table_iter_init(&iter, priv->ip4_dev_route_blacklist_hash); - while (g_hash_table_iter_next(&iter, (gpointer *) &p_obj, (gpointer *) &p_timeout_ms)) { - if (NMP_OBJECT_CAST_IP4_ROUTE(p_obj)->ifindex == ifindex) { - /* we could g_hash_table_iter_remove(&iter) the current entry. - * Instead, just expire it and let _ip4_dev_route_blacklist_gc_timeout_handle() - * handle it. - * - * The assumption is, that ip4_dev_route_blacklist contains the very same entry - * again, with a new timeout. So, we can un-expire it below. */ - *p_timeout_ms = 0; - } - } - } - - if (ip4_dev_route_blacklist && ip4_dev_route_blacklist->len > 0) { - if (!priv->ip4_dev_route_blacklist_hash) { - priv->ip4_dev_route_blacklist_hash = - g_hash_table_new_full((GHashFunc) nmp_object_id_hash, - (GEqualFunc) nmp_object_id_equal, - (GDestroyNotify) nmp_object_unref, - nm_g_slice_free_fcn_gint64); - } - - timeout_msec = nm_utils_get_monotonic_timestamp_msec() + IP4_DEV_ROUTE_BLACKLIST_TIMEOUT_MS; - timeout_msec_val = (timeout_msec << 1) | ((gint64) 1); - for (i = 0; i < ip4_dev_route_blacklist->len; i++) { - const NMPObject *o; - - needs_check = TRUE; - o = ip4_dev_route_blacklist->pdata[i]; - if (g_hash_table_lookup_extended(priv->ip4_dev_route_blacklist_hash, - o, - (gpointer *) &p_obj, - (gpointer *) &p_timeout_ms)) { - if (nmp_object_equal(p_obj, o)) { - /* un-expire and reuse the entry. */ - _LOGT("ip4-dev-route: register %s (update)", - nmp_object_to_string(p_obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - *p_timeout_ms = timeout_msec_val; - continue; - } - } - - _LOGT("ip4-dev-route: register %s", - nmp_object_to_string(o, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - p_timeout_ms = g_slice_new(gint64); - *p_timeout_ms = timeout_msec_val; - g_hash_table_replace(priv->ip4_dev_route_blacklist_hash, - (gpointer) nmp_object_ref(o), - p_timeout_ms); - } - } - - _ip4_dev_route_blacklist_schedule(self); - - if (needs_check) - _ip4_dev_route_blacklist_check_schedule(self); -} - -/*****************************************************************************/ - -int -nm_platform_routing_rule_add(NMPlatform * self, - NMPNlmFlags flags, - const NMPlatformRoutingRule *routing_rule) -{ - _CHECK_SELF(self, klass, -NME_BUG); - - g_return_val_if_fail(routing_rule, -NME_BUG); - - _LOGD("routing-rule: adding or updating: %s", - nm_platform_routing_rule_to_string(routing_rule, NULL, 0)); - return klass->routing_rule_add(self, flags, routing_rule); -} - -/*****************************************************************************/ - -int -nm_platform_qdisc_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformQdisc *qdisc) -{ - int ifindex = qdisc->ifindex; - _CHECK_SELF(self, klass, -NME_BUG); - - /* Note: @qdisc must not be copied or kept alive because the lifetime of qdisc.kind - * is undefined. */ - - _LOG3D("adding or updating a qdisc: %s", nm_platform_qdisc_to_string(qdisc, NULL, 0)); - return klass->qdisc_add(self, flags, qdisc); -} - -/** - * nm_platform_qdisc_sync: - * @self: the #NMPlatform instance - * @ifindex: the ifindex where to configure the qdiscs. - * @known_qdiscs: the list of qdiscs (#NMPObject). - * - * The function promises not to take any reference to the qdisc - * instances from @known_qdiscs, nor to keep them around after - * the function returns. This is important, because it allows the - * caller to pass NMPlatformQdisc instances which "kind" string - * have a limited lifetime. - * - * Returns: %TRUE on success. - */ -gboolean -nm_platform_qdisc_sync(NMPlatform *self, int ifindex, GPtrArray *known_qdiscs) -{ - gs_unref_ptrarray GPtrArray *plat_qdiscs = NULL; - NMPLookup lookup; - guint i; - gboolean success = TRUE; - gs_unref_hashtable GHashTable *known_qdiscs_idx = NULL; - - nm_assert(NM_IS_PLATFORM(self)); - nm_assert(ifindex > 0); - - known_qdiscs_idx = - g_hash_table_new((GHashFunc) nmp_object_id_hash, (GEqualFunc) nmp_object_id_equal); - if (known_qdiscs) { - for (i = 0; i < known_qdiscs->len; i++) { - const NMPObject *q = g_ptr_array_index(known_qdiscs, i); - - if (!g_hash_table_insert(known_qdiscs_idx, (gpointer) q, (gpointer) q)) { - _LOGW("duplicate qdisc %s", nm_platform_qdisc_to_string(&q->qdisc, NULL, 0)); - return FALSE; - } - } - } - - plat_qdiscs = - nm_platform_lookup_clone(self, - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_QDISC, ifindex), - NULL, - NULL); - if (plat_qdiscs) { - for (i = 0; i < plat_qdiscs->len; i++) { - const NMPObject *p = g_ptr_array_index(plat_qdiscs, i); - const NMPObject *k; - - /* look up known qdisc with same parent */ - k = g_hash_table_lookup(known_qdiscs_idx, p); - - if (k) { - const NMPlatformQdisc *qdisc_k = NMP_OBJECT_CAST_QDISC(k); - const NMPlatformQdisc *qdisc_p = NMP_OBJECT_CAST_QDISC(p); - - /* check other fields */ - if (nm_platform_qdisc_cmp_full(qdisc_k, qdisc_p, FALSE) != 0 - || (qdisc_k->handle != qdisc_p->handle && qdisc_k != 0)) { - k = NULL; - } - } - - if (k) { - g_hash_table_remove(known_qdiscs_idx, k); - } else { - /* can't delete qdisc with zero handle */ - if (TC_H_MAJ(p->qdisc.handle) != 0) { - success &= nm_platform_object_delete(self, p); - } - } - } - } - - if (known_qdiscs) { - for (i = 0; i < known_qdiscs->len; i++) { - const NMPObject *q = g_ptr_array_index(known_qdiscs, i); - - if (g_hash_table_contains(known_qdiscs_idx, q)) { - success &= - (nm_platform_qdisc_add(self, NMP_NLM_FLAG_ADD, NMP_OBJECT_CAST_QDISC(q)) >= 0); - } - } - } - - return success; -} - -/*****************************************************************************/ - -int -nm_platform_tfilter_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformTfilter *tfilter) -{ - int ifindex = tfilter->ifindex; - _CHECK_SELF(self, klass, -NME_BUG); - - /* Note: @tfilter must not be copied or kept alive because the lifetime of tfilter.kind - * and tfilter.action.kind is undefined. */ - - _LOG3D("adding or updating a tfilter: %s", nm_platform_tfilter_to_string(tfilter, NULL, 0)); - return klass->tfilter_add(self, flags, tfilter); -} - -/** - * nm_platform_qdisc_sync: - * @self: the #NMPlatform instance - * @ifindex: the ifindex where to configure the qdiscs. - * @known_tfilters: the list of tfilters (#NMPObject). - * - * The function promises not to take any reference to the tfilter - * instances from @known_tfilters, nor to keep them around after - * the function returns. This is important, because it allows the - * caller to pass NMPlatformTfilter instances which "kind" string - * have a limited lifetime. - * - * Returns: %TRUE on success. - */ -gboolean -nm_platform_tfilter_sync(NMPlatform *self, int ifindex, GPtrArray *known_tfilters) -{ - gs_unref_ptrarray GPtrArray *plat_tfilters = NULL; - NMPLookup lookup; - guint i; - gboolean success = TRUE; - gs_unref_hashtable GHashTable *known_tfilters_idx = NULL; - - nm_assert(NM_IS_PLATFORM(self)); - nm_assert(ifindex > 0); - - known_tfilters_idx = - g_hash_table_new((GHashFunc) nmp_object_id_hash, (GEqualFunc) nmp_object_id_equal); - - if (known_tfilters) { - for (i = 0; i < known_tfilters->len; i++) { - const NMPObject *q = g_ptr_array_index(known_tfilters, i); - - g_hash_table_insert(known_tfilters_idx, (gpointer) q, (gpointer) q); - } - } - - plat_tfilters = - nm_platform_lookup_clone(self, - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_TFILTER, ifindex), - NULL, - NULL); - - if (plat_tfilters) { - for (i = 0; i < plat_tfilters->len; i++) { - const NMPObject *q = g_ptr_array_index(plat_tfilters, i); - - if (!g_hash_table_lookup(known_tfilters_idx, q)) - success &= nm_platform_object_delete(self, q); - } - } - - if (known_tfilters) { - for (i = 0; i < known_tfilters->len; i++) { - const NMPObject *q = g_ptr_array_index(known_tfilters, i); - - success &= - (nm_platform_tfilter_add(self, NMP_NLM_FLAG_ADD, NMP_OBJECT_CAST_TFILTER(q)) >= 0); - } - } - - return success; -} - -/*****************************************************************************/ - -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 * -_lifetime_to_string(guint32 timestamp, guint32 lifetime, gint32 now, char *buf, size_t buf_size) -{ - if (lifetime == NM_PLATFORM_LIFETIME_PERMANENT) - return "forever"; - - g_snprintf(buf, - buf_size, - "%usec", - nm_utils_lifetime_rebase_relative_time_on_now(timestamp, lifetime, now)); - return buf; -} - -static const char * -_lifetime_summary_to_string(gint32 now, - guint32 timestamp, - guint32 preferred, - guint32 lifetime, - char * buf, - size_t buf_size) -{ - g_snprintf(buf, - buf_size, - " lifetime %d-%u[%u,%u]", - (signed) now, - (unsigned) timestamp, - (unsigned) preferred, - (unsigned) lifetime); - return buf; -} - -/** - * 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, char *buf, gsize len) -{ - char master[20]; - char parent[20]; - char str_flags[1 + NM_PLATFORM_LINK_FLAGS2STR_MAX_LEN + 1]; - char str_highlighted_flags[50]; - char * s; - gsize l; - char str_addrmode[30]; - char str_address[NM_UTILS_HWADDR_LEN_MAX * 3]; - char str_broadcast[NM_UTILS_HWADDR_LEN_MAX * 3]; - char str_inet6_token[NM_UTILS_INET_ADDRSTRLEN]; - const char *str_link_type; - - if (!nm_utils_to_string_buffer_init_null(link, &buf, &len)) - return buf; - - s = str_highlighted_flags; - l = sizeof(str_highlighted_flags); - if (NM_FLAGS_HAS(link->n_ifi_flags, IFF_NOARP)) - nm_utils_strbuf_append_str(&s, &l, "NOARP,"); - if (NM_FLAGS_HAS(link->n_ifi_flags, IFF_UP)) - nm_utils_strbuf_append_str(&s, &l, "UP"); - else - nm_utils_strbuf_append_str(&s, &l, "DOWN"); - if (link->connected) - nm_utils_strbuf_append_str(&s, &l, ",LOWER_UP"); - nm_assert(s > str_highlighted_flags && l > 0); - - if (link->n_ifi_flags) { - str_flags[0] = ';'; - nm_platform_link_flags2str(link->n_ifi_flags, &str_flags[1], sizeof(str_flags) - 1); - } else - str_flags[0] = '\0'; - - if (link->master) - g_snprintf(master, sizeof(master), " master %d", link->master); - else - master[0] = 0; - - if (link->parent > 0) - g_snprintf(parent, sizeof(parent), "@%d", link->parent); - else if (link->parent == NM_PLATFORM_LINK_OTHER_NETNS) - g_strlcpy(parent, "@other-netns", sizeof(parent)); - else - parent[0] = 0; - - _nmp_link_address_to_string(&link->l_address, str_address); - _nmp_link_address_to_string(&link->l_broadcast, str_broadcast); - - str_link_type = nm_link_type_to_string(link->type); - - g_snprintf( - buf, - len, - "%d: " /* ifindex */ - "%s" /* name */ - "%s" /* parent */ - " <%s%s>" /* flags */ - " mtu %d" - "%s" /* master */ - " arp %u" /* arptype */ - " %s" /* link->type */ - "%s%s" /* kind */ - "%s" /* is-in-udev */ - "%s%s" /* addr-gen-mode */ - "%s%s" /* l_address */ - "%s%s" /* l_broadcast */ - "%s%s" /* inet6_token */ - "%s%s" /* driver */ - " rx:%" G_GUINT64_FORMAT ",%" G_GUINT64_FORMAT " tx:%" G_GUINT64_FORMAT - ",%" G_GUINT64_FORMAT, - link->ifindex, - link->name, - parent, - str_highlighted_flags, - str_flags, - link->mtu, - master, - link->arptype, - 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", - link->inet6_addr_gen_mode_inv ? " addrgenmode " : "", - link->inet6_addr_gen_mode_inv ? nm_platform_link_inet6_addrgenmode2str( - _nm_platform_uint8_inv(link->inet6_addr_gen_mode_inv), - str_addrmode, - sizeof(str_addrmode)) - : "", - str_address[0] ? " addr " : "", - str_address[0] ? str_address : "", - str_broadcast[0] ? " brd " : "", - str_broadcast[0] ? str_broadcast : "", - link->inet6_token.id ? " inet6token " : "", - link->inet6_token.id - ? nm_utils_inet6_interface_identifier_to_token(link->inet6_token, str_inet6_token) - : "", - link->driver ? " driver " : "", - link->driver ?: "", - link->rx_packets, - link->rx_bytes, - link->tx_packets, - link->tx_bytes); - return buf; -} - -const NMPlatformLnkBridge nm_platform_lnk_bridge_default = { - .forward_delay = NM_BRIDGE_FORWARD_DELAY_DEF_SYS, - .hello_time = NM_BRIDGE_HELLO_TIME_DEF_SYS, - .max_age = NM_BRIDGE_MAX_AGE_DEF_SYS, - .ageing_time = NM_BRIDGE_AGEING_TIME_DEF_SYS, - .stp_state = FALSE, - .priority = NM_BRIDGE_PRIORITY_DEF, - .vlan_protocol = 0x8100, - .vlan_stats_enabled = NM_BRIDGE_VLAN_STATS_ENABLED_DEF, - .group_fwd_mask = 0, - .group_addr = NM_ETHER_ADDR_INIT(NM_BRIDGE_GROUP_ADDRESS_DEF_BIN), - .mcast_snooping = NM_BRIDGE_MULTICAST_SNOOPING_DEF, - .mcast_router = 1, - .mcast_query_use_ifaddr = NM_BRIDGE_MULTICAST_QUERY_USE_IFADDR_DEF, - .mcast_querier = NM_BRIDGE_MULTICAST_QUERIER_DEF, - .mcast_hash_max = NM_BRIDGE_MULTICAST_HASH_MAX_DEF, - .mcast_last_member_count = NM_BRIDGE_MULTICAST_LAST_MEMBER_COUNT_DEF, - .mcast_startup_query_count = NM_BRIDGE_MULTICAST_STARTUP_QUERY_COUNT_DEF, - .mcast_last_member_interval = NM_BRIDGE_MULTICAST_LAST_MEMBER_INTERVAL_DEF, - .mcast_membership_interval = NM_BRIDGE_MULTICAST_MEMBERSHIP_INTERVAL_DEF, - .mcast_querier_interval = NM_BRIDGE_MULTICAST_QUERIER_INTERVAL_DEF, - .mcast_query_interval = NM_BRIDGE_MULTICAST_QUERY_INTERVAL_DEF, - .mcast_query_response_interval = NM_BRIDGE_MULTICAST_QUERY_RESPONSE_INTERVAL_DEF, - .mcast_startup_query_interval = NM_BRIDGE_MULTICAST_STARTUP_QUERY_INTERVAL_DEF, -}; - -const char * -nm_platform_lnk_bridge_to_string(const NMPlatformLnkBridge *lnk, char *buf, gsize len) -{ - if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len)) - return buf; - - g_snprintf(buf, - len, - "forward_delay %u" - " hello_time %u" - " max_age %u" - " ageing_time %u" - " stp_state %d" - " priority %u" - " vlan_protocol %u" - " vlan_stats_enabled %d" - " group_fwd_mask %#x" - " group_address " NM_ETHER_ADDR_FORMAT_STR " mcast_snooping %d" - " mcast_router %u" - " mcast_query_use_ifaddr %d" - " mcast_querier %d" - " mcast_hash_max %u" - " mcast_last_member_count %u" - " mcast_startup_query_count %u" - " mcast_last_member_interval %" G_GUINT64_FORMAT - " mcast_membership_interval %" G_GUINT64_FORMAT - " mcast_querier_interval %" G_GUINT64_FORMAT - " mcast_query_interval %" G_GUINT64_FORMAT - " mcast_query_response_interval %" G_GUINT64_FORMAT - " mcast_startup_query_interval %" G_GUINT64_FORMAT "", - lnk->forward_delay, - lnk->hello_time, - lnk->max_age, - lnk->ageing_time, - (int) lnk->stp_state, - lnk->priority, - lnk->vlan_protocol, - (int) lnk->vlan_stats_enabled, - lnk->group_fwd_mask, - NM_ETHER_ADDR_FORMAT_VAL(&lnk->group_addr), - (int) lnk->mcast_snooping, - lnk->mcast_router, - (int) lnk->mcast_query_use_ifaddr, - (int) lnk->mcast_querier, - lnk->mcast_hash_max, - lnk->mcast_last_member_count, - lnk->mcast_startup_query_count, - lnk->mcast_last_member_interval, - lnk->mcast_membership_interval, - lnk->mcast_querier_interval, - lnk->mcast_query_interval, - lnk->mcast_query_response_interval, - lnk->mcast_startup_query_interval); - 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" /* is_tap */ - "%s" /* remote */ - "%s" /* local */ - "%s" /* parent_ifindex */ - "%s" /* ttl */ - "%s" /* tos */ - "%s" /* path_mtu_discovery */ - "%s" /* iflags */ - "%s" /* oflags */ - "%s" /* ikey */ - "%s" /* okey */ - "", - lnk->is_tap ? "tap" : "", - 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]; - char *str_type; - - if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len)) - return buf; - - if (lnk->is_gre) - str_type = lnk->is_tap ? "ip6gretap" : "ip6gre"; - else - str_type = "ip6tnl"; - - g_snprintf( - buf, - len, - "%s" /* type */ - "%s" /* remote */ - "%s" /* local */ - "%s" /* parent_ifindex */ - "%s" /* ttl */ - "%s" /* tclass */ - "%s" /* encap limit */ - "%s" /* flow label */ - "%s" /* proto */ - " flags 0x%x" - "", - str_type, - 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), - (guint) lnk->flags); - 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_macsec_to_string(const NMPlatformLnkMacsec *lnk, char *buf, gsize len) -{ - if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len)) - return buf; - - g_snprintf(buf, - len, - "macsec " - "sci %016llx " - "protect %s " - "cipher %016llx " - "icvlen %u " - "encodingsa %u " - "validate %u " - "encrypt %s " - "send_sci %s " - "end_station %s " - "scb %s " - "replay %s", - (unsigned long long) lnk->sci, - lnk->protect ? "on" : "off", - (unsigned long long) lnk->cipher_suite, - lnk->icv_length, - lnk->encoding_sa, - lnk->validation, - lnk->encrypt ? "on" : "off", - lnk->include_sci ? "on" : "off", - lnk->es ? "on" : "off", - lnk->scb ? "on" : "off", - lnk->replay_protect ? "on" : "off"); - 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, - "%s mode %u %s", - lnk->tap ? "macvtap" : "macvlan", - 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_tun_to_string(const NMPlatformLnkTun *lnk, char *buf, gsize len) -{ - char str_owner[50]; - char str_group[50]; - char str_type[50]; - const char *type; - - if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len)) - return buf; - - if (lnk->type == IFF_TUN) - type = "tun"; - else if (lnk->type == IFF_TAP) - type = "tap"; - else - type = nm_sprintf_buf(str_type, "tun type %u", (guint) lnk->type); - - g_snprintf(buf, - len, - "%s" /* type */ - "%s" /* pi */ - "%s" /* vnet_hdr */ - "%s" /* multi_queue */ - "%s" /* persist */ - "%s" /* owner */ - "%s" /* group */ - "", - type, - lnk->pi ? " pi" : "", - lnk->vnet_hdr ? " vnet_hdr" : "", - lnk->multi_queue ? " multi_queue" : "", - lnk->persist ? " persist" : "", - lnk->owner_valid ? nm_sprintf_buf(str_owner, " owner %u", (guint) lnk->owner) : "", - lnk->group_valid ? nm_sprintf_buf(str_group, " group %u", (guint) lnk->group) : ""); - 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_vrf_to_string(const NMPlatformLnkVrf *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, "table %u", lnk->table); - 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]; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - 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, sbuf)); - } - 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, sbuf)); - } - - if (lnk->local == 0) - str_local[0] = '\0'; - else { - g_snprintf(str_local, - sizeof(str_local), - " local %s", - _nm_utils_inet4_ntop(lnk->local, sbuf)); - } - 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, sbuf)); - } - - 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; -} - -const char * -nm_platform_wireguard_peer_to_string(const NMPWireGuardPeer *peer, char *buf, gsize len) -{ - char * buf0 = buf; - gs_free char *public_key_b64 = NULL; - char s_sockaddr[NM_UTILS_INET_ADDRSTRLEN + 100]; - char s_endpoint[20 + sizeof(s_sockaddr)]; - char s_addr[NM_UTILS_INET_ADDRSTRLEN]; - char s_keepalive[100]; - guint i; - - nm_utils_to_string_buffer_init(&buf, &len); - - public_key_b64 = g_base64_encode(peer->public_key, sizeof(peer->public_key)); - - if (peer->endpoint.sa.sa_family != AF_UNSPEC) { - nm_sprintf_buf( - s_endpoint, - " endpoint %s", - nm_sock_addr_union_to_string(&peer->endpoint, s_sockaddr, sizeof(s_sockaddr))); - } else - s_endpoint[0] = '\0'; - - nm_utils_strbuf_append( - &buf, - &len, - "public-key %s" - "%s" /* preshared-key */ - "%s" /* endpoint */ - " rx %" G_GUINT64_FORMAT " tx %" G_GUINT64_FORMAT "%s" /* persistent-keepalive */ - "%s", /* allowed-ips */ - public_key_b64, - nm_utils_memeqzero_secret(peer->preshared_key, sizeof(peer->preshared_key)) - ? "" - : " preshared-key (hidden)", - s_endpoint, - peer->rx_bytes, - peer->tx_bytes, - peer->persistent_keepalive_interval > 0 - ? nm_sprintf_buf(s_keepalive, - " keepalive %u", - (guint) peer->persistent_keepalive_interval) - : "", - peer->allowed_ips_len > 0 ? " allowed-ips" : ""); - - for (i = 0; i < peer->allowed_ips_len; i++) { - const NMPWireGuardAllowedIP *allowed_ip = &peer->allowed_ips[i]; - - nm_utils_strbuf_append(&buf, - &len, - " %s/%u", - nm_utils_inet_ntop(allowed_ip->family, &allowed_ip->addr, s_addr), - allowed_ip->mask); - } - - return buf0; -} - -const char * -nm_platform_lnk_wireguard_to_string(const NMPlatformLnkWireGuard *lnk, char *buf, gsize len) -{ - gs_free char *public_b64 = NULL; - - if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len)) - return buf; - - if (!nm_utils_memeqzero(lnk->public_key, sizeof(lnk->public_key))) - public_b64 = g_base64_encode(lnk->public_key, sizeof(lnk->public_key)); - - g_snprintf(buf, - len, - "wireguard" - "%s%s" /* public-key */ - "%s" /* private-key */ - " listen-port %u" - " fwmark 0x%x", - public_b64 ? " public-key " : "", - public_b64 ?: "", - nm_utils_memeqzero_secret(lnk->private_key, sizeof(lnk->private_key)) - ? "" - : " private-key (hidden)", - lnk->listen_port, - lnk->fwmark); - - 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. - */ -const char * -nm_platform_ip4_address_to_string(const NMPlatformIP4Address *address, char *buf, gsize len) -{ - char s_flags[TO_STRING_IFA_FLAGS_BUF_SIZE]; - char s_address[INET_ADDRSTRLEN]; - char s_peer[INET_ADDRSTRLEN]; - char str_dev[TO_STRING_DEV_BUF_SIZE]; - char str_label[32]; - char str_lft[30], str_pref[30], str_time[50], s_source[50]; - char * str_peer = NULL; - const char *str_lft_p, *str_pref_p, *str_time_p; - gint32 now = nm_utils_get_monotonic_timestamp_sec(); - in_addr_t broadcast_address; - char str_broadcast[INET_ADDRSTRLEN]; - - 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 != address->address) { - inet_ntop(AF_INET, &address->peer_address, s_peer, sizeof(s_peer)); - str_peer = g_strconcat(" ptp ", s_peer, NULL); - } - - _to_string_dev(NULL, address->ifindex, str_dev, sizeof(str_dev)); - - if (*address->label) - g_snprintf(str_label, sizeof(str_label), " label %s", address->label); - else - str_label[0] = 0; - - str_lft_p = _lifetime_to_string(address->timestamp, - address->lifetime ?: NM_PLATFORM_LIFETIME_PERMANENT, - now, - str_lft, - sizeof(str_lft)), - str_pref_p = - (address->lifetime == address->preferred) - ? str_lft_p - : (_lifetime_to_string(address->timestamp, - address->lifetime ? MIN(address->preferred, address->lifetime) - : NM_PLATFORM_LIFETIME_PERMANENT, - now, - str_pref, - sizeof(str_pref))); - str_time_p = _lifetime_summary_to_string(now, - address->timestamp, - address->preferred, - address->lifetime, - str_time, - sizeof(str_time)); - - broadcast_address = nm_platform_ip4_broadcast_address_from_addr(address); - - g_snprintf( - buf, - len, - "%s/%d" - "%s%s" /* broadcast */ - " lft %s" - " pref %s" - "%s" /* time */ - "%s" /* peer */ - "%s" /* dev */ - "%s" /* flags */ - "%s" /* label */ - " src %s" - "%s" /* external */ - "%s" /* ip4acd_not_ready */ - "", - s_address, - address->plen, - broadcast_address != 0u || address->use_ip4_broadcast_address - ? (address->use_ip4_broadcast_address ? " brd " : " brd* ") - : "", - broadcast_address != 0u || address->use_ip4_broadcast_address - ? _nm_utils_inet4_ntop(broadcast_address, str_broadcast) - : "", - str_lft_p, - str_pref_p, - str_time_p, - str_peer ?: "", - str_dev, - _to_string_ifa_flags(address->n_ifa_flags, s_flags, sizeof(s_flags)), - str_label, - nmp_utils_ip_config_source_to_string(address->addr_source, s_source, sizeof(s_source)), - address->external ? " ext" : "", - address->ip4acd_not_ready ? " ip4acd-not-ready" : ""); - g_free(str_peer); - return buf; -} - -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_ENUM2STR(NM_IN6_ADDR_GEN_MODE_RANDOM, "random"), ); - -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_PERMANENT, "permanent"), - NM_UTILS_FLAGS2STR(IFA_F_MANAGETEMPADDR, "mngtmpaddr"), - NM_UTILS_FLAGS2STR(IFA_F_NOPREFIXROUTE, "noprefixroute"), - NM_UTILS_FLAGS2STR(IFA_F_TENTATIVE, "tentative"), ); - -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. - */ -const char * -nm_platform_ip6_address_to_string(const NMPlatformIP6Address *address, char *buf, gsize len) -{ - char s_flags[TO_STRING_IFA_FLAGS_BUF_SIZE]; - char s_address[INET6_ADDRSTRLEN]; - char s_peer[INET6_ADDRSTRLEN]; - char str_lft[30], str_pref[30], str_time[50], s_source[50]; - char str_dev[TO_STRING_DEV_BUF_SIZE]; - char * str_peer = NULL; - const char *str_lft_p, *str_pref_p, *str_time_p; - gint32 now = nm_utils_get_monotonic_timestamp_sec(); - - if (!nm_utils_to_string_buffer_init_null(address, &buf, &len)) - return buf; - - inet_ntop(AF_INET6, &address->address, s_address, sizeof(s_address)); - - if (!IN6_IS_ADDR_UNSPECIFIED(&address->peer_address)) { - inet_ntop(AF_INET6, &address->peer_address, s_peer, sizeof(s_peer)); - str_peer = g_strconcat(" ptp ", s_peer, NULL); - } - - _to_string_dev(NULL, address->ifindex, str_dev, sizeof(str_dev)); - - str_lft_p = _lifetime_to_string(address->timestamp, - address->lifetime ?: NM_PLATFORM_LIFETIME_PERMANENT, - now, - str_lft, - sizeof(str_lft)), - str_pref_p = - (address->lifetime == address->preferred) - ? str_lft_p - : (_lifetime_to_string(address->timestamp, - address->lifetime ? MIN(address->preferred, address->lifetime) - : NM_PLATFORM_LIFETIME_PERMANENT, - now, - str_pref, - sizeof(str_pref))); - str_time_p = _lifetime_summary_to_string(now, - address->timestamp, - address->preferred, - address->lifetime, - str_time, - sizeof(str_time)); - - g_snprintf( - buf, - len, - "%s/%d lft %s pref %s%s%s%s%s src %s%s", - s_address, - address->plen, - str_lft_p, - str_pref_p, - str_time_p, - str_peer ?: "", - str_dev, - _to_string_ifa_flags(address->n_ifa_flags, s_flags, sizeof(s_flags)), - nmp_utils_ip_config_source_to_string(address->addr_source, s_source, sizeof(s_source)), - address->external ? " ext" : ""); - g_free(str_peer); - return buf; -} - -static NM_UTILS_FLAGS2STR_DEFINE(_rtm_flags_to_string, - unsigned, - NM_UTILS_FLAGS2STR(RTNH_F_DEAD, "dead"), - NM_UTILS_FLAGS2STR(RTNH_F_PERVASIVE, "pervasive"), - NM_UTILS_FLAGS2STR(RTNH_F_ONLINK, "onlink"), - NM_UTILS_FLAGS2STR(8 /*RTNH_F_OFFLOAD*/, "offload"), - NM_UTILS_FLAGS2STR(16 /*RTNH_F_LINKDOWN*/, "linkdown"), - NM_UTILS_FLAGS2STR(32 /*RTNH_F_UNRESOLVED*/, "unresolved"), - - NM_UTILS_FLAGS2STR(RTM_F_NOTIFY, "notify"), - NM_UTILS_FLAGS2STR(RTM_F_CLONED, "cloned"), - NM_UTILS_FLAGS2STR(RTM_F_EQUALIZE, "equalize"), - NM_UTILS_FLAGS2STR(RTM_F_PREFIX, "prefix"), - NM_UTILS_FLAGS2STR(0x1000 /*RTM_F_LOOKUP_TABLE*/, "lookup-table"), - NM_UTILS_FLAGS2STR(0x2000 /*RTM_F_FIB_MATCH*/, "fib-match"), ); - -#define _RTM_FLAGS_TO_STRING_MAXLEN 200 - -static const char * -_rtm_flags_to_string_full(char *buf, gsize buf_size, unsigned rtm_flags) -{ - const char *buf0 = buf; - - nm_assert(buf_size >= _RTM_FLAGS_TO_STRING_MAXLEN); - - if (!rtm_flags) - return ""; - - nm_utils_strbuf_append_str(&buf, &buf_size, " rtm_flags "); - _rtm_flags_to_string(rtm_flags, buf, buf_size); - nm_assert(strlen(buf) < buf_size); - return buf0; -} - -/** - * 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. - */ -const char * -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_table[30]; - char str_scope[30], s_source[50]; - char str_tos[32], str_window[32], str_cwnd[32], str_initcwnd[32], str_initrwnd[32], str_mtu[32]; - char str_rtm_flags[_RTM_FLAGS_TO_STRING_MAXLEN]; - char str_type[30]; - char str_metric[30]; - - 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( - buf, - len, - "type %s " /* type */ - "%s" /* table */ - "%s/%d" - " via %s" - "%s" - " metric %s" - " mss %" G_GUINT32_FORMAT " rt-src %s" /* protocol */ - "%s" /* rtm_flags */ - "%s%s" /* scope */ - "%s%s" /* pref-src */ - "%s" /* tos */ - "%s" /* window */ - "%s" /* cwnd */ - "%s" /* initcwnd */ - "%s" /* initrwnd */ - "%s" /* mtu */ - "", - nm_utils_route_type2str(nm_platform_route_type_uncoerce(route->type_coerced), - str_type, - sizeof(str_type)), - route->table_any - ? "table ?? " - : (route->table_coerced - ? nm_sprintf_buf(str_table, - "table %u ", - nm_platform_route_table_uncoerce(route->table_coerced, FALSE)) - : ""), - s_network, - route->plen, - s_gateway, - str_dev, - route->metric_any - ? (route->metric ? nm_sprintf_buf(str_metric, "??+%u", route->metric) : "??") - : nm_sprintf_buf(str_metric, "%u", route->metric), - route->mss, - nmp_utils_ip_config_source_to_string(route->rt_source, s_source, sizeof(s_source)), - _rtm_flags_to_string_full(str_rtm_flags, sizeof(str_rtm_flags), route->r_rtm_flags), - route->scope_inv ? " 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)) : "", - route->tos ? nm_sprintf_buf(str_tos, " tos 0x%x", (unsigned) route->tos) : "", - route->window || route->lock_window ? nm_sprintf_buf(str_window, - " window %s%" G_GUINT32_FORMAT, - route->lock_window ? "lock " : "", - route->window) - : "", - route->cwnd || route->lock_cwnd ? nm_sprintf_buf(str_cwnd, - " cwnd %s%" G_GUINT32_FORMAT, - route->lock_cwnd ? "lock " : "", - route->cwnd) - : "", - route->initcwnd || route->lock_initcwnd - ? nm_sprintf_buf(str_initcwnd, - " initcwnd %s%" G_GUINT32_FORMAT, - route->lock_initcwnd ? "lock " : "", - route->initcwnd) - : "", - route->initrwnd || route->lock_initrwnd - ? nm_sprintf_buf(str_initrwnd, - " initrwnd %s%" G_GUINT32_FORMAT, - route->lock_initrwnd ? "lock " : "", - route->initrwnd) - : "", - route->mtu || route->lock_mtu ? nm_sprintf_buf(str_mtu, - " mtu %s%" G_GUINT32_FORMAT, - route->lock_mtu ? "lock " : "", - route->mtu) - : ""); - 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. - */ -const char * -nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsize len) -{ - char s_network[INET6_ADDRSTRLEN]; - char s_gateway[INET6_ADDRSTRLEN]; - char s_pref_src[INET6_ADDRSTRLEN]; - char s_src_all[INET6_ADDRSTRLEN + 40]; - char s_src[INET6_ADDRSTRLEN]; - char str_type[30]; - char str_table[30]; - char str_pref[40]; - char str_pref2[30]; - char str_dev[TO_STRING_DEV_BUF_SIZE]; - char s_source[50]; - char str_window[32]; - char str_cwnd[32]; - char str_initcwnd[32]; - char str_initrwnd[32]; - char str_mtu[32]; - char str_rtm_flags[_RTM_FLAGS_TO_STRING_MAXLEN]; - char str_metric[30]; - - 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)); - - if (IN6_IS_ADDR_UNSPECIFIED(&route->pref_src)) - s_pref_src[0] = 0; - else - inet_ntop(AF_INET6, &route->pref_src, s_pref_src, sizeof(s_pref_src)); - - _to_string_dev(NULL, route->ifindex, str_dev, sizeof(str_dev)); - - g_snprintf( - buf, - len, - "type %s " /* type */ - "%s" /* table */ - "%s/%d" - " via %s" - "%s" - " metric %s" - " mss %" G_GUINT32_FORMAT " rt-src %s" /* protocol */ - "%s" /* source */ - "%s" /* rtm_flags */ - "%s%s" /* pref-src */ - "%s" /* window */ - "%s" /* cwnd */ - "%s" /* initcwnd */ - "%s" /* initrwnd */ - "%s" /* mtu */ - "%s" /* pref */ - "", - nm_utils_route_type2str(nm_platform_route_type_uncoerce(route->type_coerced), - str_type, - sizeof(str_type)), - route->table_any - ? "table ?? " - : (route->table_coerced - ? nm_sprintf_buf(str_table, - "table %u ", - nm_platform_route_table_uncoerce(route->table_coerced, FALSE)) - : ""), - s_network, - route->plen, - s_gateway, - str_dev, - route->metric_any - ? (route->metric ? nm_sprintf_buf(str_metric, "??+%u", route->metric) : "??") - : nm_sprintf_buf(str_metric, "%u", route->metric), - route->mss, - nmp_utils_ip_config_source_to_string(route->rt_source, s_source, sizeof(s_source)), - route->src_plen || !IN6_IS_ADDR_UNSPECIFIED(&route->src) - ? nm_sprintf_buf(s_src_all, - " src %s/%u", - _nm_utils_inet6_ntop(&route->src, s_src), - (unsigned) route->src_plen) - : "", - _rtm_flags_to_string_full(str_rtm_flags, sizeof(str_rtm_flags), route->r_rtm_flags), - s_pref_src[0] ? " pref-src " : "", - s_pref_src[0] ? s_pref_src : "", - route->window || route->lock_window ? nm_sprintf_buf(str_window, - " window %s%" G_GUINT32_FORMAT, - route->lock_window ? "lock " : "", - route->window) - : "", - route->cwnd || route->lock_cwnd ? nm_sprintf_buf(str_cwnd, - " cwnd %s%" G_GUINT32_FORMAT, - route->lock_cwnd ? "lock " : "", - route->cwnd) - : "", - route->initcwnd || route->lock_initcwnd - ? nm_sprintf_buf(str_initcwnd, - " initcwnd %s%" G_GUINT32_FORMAT, - route->lock_initcwnd ? "lock " : "", - route->initcwnd) - : "", - route->initrwnd || route->lock_initrwnd - ? nm_sprintf_buf(str_initrwnd, - " initrwnd %s%" G_GUINT32_FORMAT, - route->lock_initrwnd ? "lock " : "", - route->initrwnd) - : "", - route->mtu || route->lock_mtu ? nm_sprintf_buf(str_mtu, - " mtu %s%" G_GUINT32_FORMAT, - route->lock_mtu ? "lock " : "", - route->mtu) - : "", - route->rt_pref ? nm_sprintf_buf( - str_pref, - " pref %s", - nm_icmpv6_router_pref_to_string(route->rt_pref, str_pref2, sizeof(str_pref2))) - : ""); - - return buf; -} - -static void -_routing_rule_addr_to_string(char ** buf, - gsize * len, - int addr_family, - const NMIPAddr *addr, - guint8 plen, - gboolean is_src) -{ - char s_addr[NM_UTILS_INET_ADDRSTRLEN]; - gboolean is_zero; - gsize addr_size; - - nm_assert_addr_family(addr_family); - nm_assert(addr); - - addr_size = nm_utils_addr_family_to_size(addr_family); - - is_zero = nm_utils_memeqzero(addr, addr_size); - - if (plen == 0 && is_zero) { - if (is_src) - nm_utils_strbuf_append_str(buf, len, " from all"); - else - nm_utils_strbuf_append_str(buf, len, ""); - return; - } - - nm_utils_strbuf_append_str(buf, len, is_src ? " from " : " to "); - - nm_utils_strbuf_append_str(buf, len, nm_utils_inet_ntop(addr_family, addr, s_addr)); - - if (plen != (addr_size * 8)) - nm_utils_strbuf_append(buf, len, "/%u", plen); -} - -static void -_routing_rule_port_range_to_string(char ** buf, - gsize * len, - const NMFibRulePortRange *port_range, - const char * name) -{ - if (port_range->start == 0 && port_range->end == 0) - nm_utils_strbuf_append_str(buf, len, ""); - else { - nm_utils_strbuf_append(buf, len, " %s %u", name, port_range->start); - if (port_range->start != port_range->end) - nm_utils_strbuf_append(buf, len, "-%u", port_range->end); - } -} - -const char * -nm_platform_routing_rule_to_string(const NMPlatformRoutingRule *routing_rule, char *buf, gsize len) -{ - const char *buf0; - guint32 rr_flags; - - if (!nm_utils_to_string_buffer_init_null(routing_rule, &buf, &len)) - return buf; - - if (!NM_IN_SET(routing_rule->addr_family, AF_INET, AF_INET6)) { - /* invalid addr-family. The other fields are undefined. */ - if (routing_rule->addr_family == AF_UNSPEC) - g_snprintf(buf, len, "[routing-rule]"); - else - g_snprintf(buf, len, "[routing-rule family:%u]", routing_rule->addr_family); - return buf; - } - - buf0 = buf; - - rr_flags = routing_rule->flags; - - rr_flags = NM_FLAGS_UNSET(rr_flags, FIB_RULE_INVERT); - nm_utils_strbuf_append(&buf, - &len, - "[%c] " /* addr-family */ - "%u:" /* priority */ - "%s", /* not/FIB_RULE_INVERT */ - nm_utils_addr_family_to_char(routing_rule->addr_family), - routing_rule->priority, - (NM_FLAGS_HAS(routing_rule->flags, FIB_RULE_INVERT) ? " not" : "")); - - _routing_rule_addr_to_string(&buf, - &len, - routing_rule->addr_family, - &routing_rule->src, - routing_rule->src_len, - TRUE); - - _routing_rule_addr_to_string(&buf, - &len, - routing_rule->addr_family, - &routing_rule->dst, - routing_rule->dst_len, - FALSE); - - if (routing_rule->tos) - nm_utils_strbuf_append(&buf, &len, " tos 0x%02x", routing_rule->tos); - - if (routing_rule->fwmark != 0 || routing_rule->fwmask != 0) { - nm_utils_strbuf_append(&buf, &len, " fwmark %#x", (unsigned) routing_rule->fwmark); - if (routing_rule->fwmark != 0xFFFFFFFFu) - nm_utils_strbuf_append(&buf, &len, "/%#x", (unsigned) routing_rule->fwmask); - } - - if (routing_rule->iifname[0]) { - nm_utils_strbuf_append(&buf, &len, " iif %s", routing_rule->iifname); - rr_flags = NM_FLAGS_UNSET(rr_flags, FIB_RULE_IIF_DETACHED); - if (NM_FLAGS_HAS(routing_rule->flags, FIB_RULE_IIF_DETACHED)) - nm_utils_strbuf_append_str(&buf, &len, " [detached]"); - } - - if (routing_rule->oifname[0]) { - nm_utils_strbuf_append(&buf, &len, " oif %s", routing_rule->oifname); - rr_flags = NM_FLAGS_UNSET(rr_flags, FIB_RULE_OIF_DETACHED); - if (NM_FLAGS_HAS(routing_rule->flags, FIB_RULE_OIF_DETACHED)) - nm_utils_strbuf_append_str(&buf, &len, " [detached]"); - } - - if (routing_rule->l3mdev != 0) { - if (routing_rule->l3mdev == 1) - nm_utils_strbuf_append_str(&buf, &len, " lookup [l3mdev-table]"); - else { - nm_utils_strbuf_append(&buf, - &len, - " lookup [l3mdev-table/%u]", - (unsigned) routing_rule->l3mdev); - } - } - - if (routing_rule->uid_range_has || routing_rule->uid_range.start - || routing_rule->uid_range.end) { - nm_utils_strbuf_append(&buf, - &len, - " uidrange %u-%u%s", - routing_rule->uid_range.start, - routing_rule->uid_range.end, - routing_rule->uid_range_has ? "" : "(?)"); - } - - if (routing_rule->ip_proto != 0) { - /* we don't call getprotobynumber(), just print the numeric value. - * This differs from what ip-rule prints. */ - nm_utils_strbuf_append(&buf, &len, " ipproto %u", routing_rule->ip_proto); - } - - _routing_rule_port_range_to_string(&buf, &len, &routing_rule->sport_range, "sport"); - - _routing_rule_port_range_to_string(&buf, &len, &routing_rule->dport_range, "dport"); - - if (routing_rule->tun_id != 0) { - nm_utils_strbuf_append(&buf, &len, " tun_id %" G_GUINT64_FORMAT, routing_rule->tun_id); - } - - if (routing_rule->table != 0) { - nm_utils_strbuf_append(&buf, &len, " lookup %u", routing_rule->table); - } - - if (routing_rule->suppress_prefixlen_inverse != 0) { - nm_utils_strbuf_append(&buf, - &len, - " suppress_prefixlen %d", - (int) (~routing_rule->suppress_prefixlen_inverse)); - } - - if (routing_rule->suppress_ifgroup_inverse != 0) { - nm_utils_strbuf_append(&buf, - &len, - " suppress_ifgroup %d", - (int) (~routing_rule->suppress_ifgroup_inverse)); - } - - if (routing_rule->flow) { - /* FRA_FLOW is only for IPv4, but we want to print the value for all address-families, - * to see when it is set. In practice, this should not be set except for IPv4. - * - * We don't follow the style how ip-rule prints flow/realms. It's confusing. Just - * print the value hex. */ - nm_utils_strbuf_append(&buf, &len, " realms 0x%08x", routing_rule->flow); - } - - if (routing_rule->action == RTN_NAT) { - G_STATIC_ASSERT_EXPR(RTN_NAT == 10); - - /* NAT is deprecated for many years. We don't support RTA_GATEWAY/FRA_UNUSED2 - * for the gateway, and so do recent kernels ignore that parameter. */ - nm_utils_strbuf_append_str(&buf, &len, " masquerade"); - } else if (routing_rule->action == FR_ACT_GOTO) { - if (routing_rule->goto_target != 0) - nm_utils_strbuf_append(&buf, &len, " goto %u", routing_rule->goto_target); - else - nm_utils_strbuf_append_str(&buf, &len, " goto none"); - rr_flags = NM_FLAGS_UNSET(rr_flags, FIB_RULE_UNRESOLVED); - if (NM_FLAGS_HAS(routing_rule->flags, FIB_RULE_UNRESOLVED)) - nm_utils_strbuf_append_str(&buf, &len, " unresolved"); - } else if (routing_rule->action != FR_ACT_TO_TBL) { - const char *ss; - char ss_buf[60]; - -#define _V(v1, v2) ((sizeof(char[(((int) (v1)) == ((int) (v2))) ? 1 : -1]) * 0) + (v1)) - switch (routing_rule->action) { - case _V(FR_ACT_UNSPEC, RTN_UNSPEC): - ss = "none"; - break; - case _V(FR_ACT_TO_TBL, RTN_UNICAST): - ss = "unicast"; - break; - case _V(FR_ACT_GOTO, RTN_LOCAL): - ss = "local"; - break; - case _V(FR_ACT_NOP, RTN_BROADCAST): - ss = "nop"; - break; - case _V(FR_ACT_RES3, RTN_ANYCAST): - ss = "anycast"; - break; - case _V(FR_ACT_RES4, RTN_MULTICAST): - ss = "multicast"; - break; - case _V(FR_ACT_BLACKHOLE, RTN_BLACKHOLE): - ss = "blackhole"; - break; - case _V(FR_ACT_UNREACHABLE, RTN_UNREACHABLE): - ss = "unreachable"; - break; - case _V(FR_ACT_PROHIBIT, RTN_PROHIBIT): - ss = "prohibit"; - break; - case RTN_THROW: - ss = "throw"; - break; - case RTN_NAT: - ss = "nat"; - break; - case RTN_XRESOLVE: - ss = "xresolve"; - break; - default: - ss = nm_sprintf_buf(ss_buf, "action-%u", routing_rule->action); - break; - } -#undef _V - nm_utils_strbuf_append(&buf, &len, " %s", ss); - } - - if (routing_rule->protocol != RTPROT_UNSPEC) - nm_utils_strbuf_append(&buf, &len, " protocol %u", routing_rule->protocol); - - if (routing_rule->goto_target != 0 && routing_rule->action != FR_ACT_GOTO) { - /* a trailing target is set for an unexpected action. Print it. */ - nm_utils_strbuf_append(&buf, &len, " goto-target %u", routing_rule->goto_target); - } - - if (rr_flags != 0) { - /* we have some flags we didn't print about yet. */ - nm_utils_strbuf_append(&buf, &len, " remaining-flags %x", rr_flags); - } - - return buf0; -} - -const char * -nm_platform_qdisc_to_string(const NMPlatformQdisc *qdisc, char *buf, gsize len) -{ - char str_dev[TO_STRING_DEV_BUF_SIZE]; - const char *buf0; - - if (!nm_utils_to_string_buffer_init_null(qdisc, &buf, &len)) - return buf; - - buf0 = buf; - - nm_utils_strbuf_append(&buf, - &len, - "%s%s family %u handle %x parent %x info %x", - qdisc->kind, - _to_string_dev(NULL, qdisc->ifindex, str_dev, sizeof(str_dev)), - qdisc->addr_family, - qdisc->handle, - qdisc->parent, - qdisc->info); - - if (nm_streq0(qdisc->kind, "fq_codel")) { - if (qdisc->fq_codel.limit) - nm_utils_strbuf_append(&buf, &len, " limit %u", qdisc->fq_codel.limit); - if (qdisc->fq_codel.flows) - nm_utils_strbuf_append(&buf, &len, " flows %u", qdisc->fq_codel.flows); - if (qdisc->fq_codel.target) - nm_utils_strbuf_append(&buf, &len, " target %u", qdisc->fq_codel.target); - if (qdisc->fq_codel.interval) - nm_utils_strbuf_append(&buf, &len, " interval %u", qdisc->fq_codel.interval); - if (qdisc->fq_codel.quantum) - nm_utils_strbuf_append(&buf, &len, " quantum %u", qdisc->fq_codel.quantum); - if (qdisc->fq_codel.ce_threshold != NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED) - nm_utils_strbuf_append(&buf, &len, " ce_threshold %u", qdisc->fq_codel.ce_threshold); - if (qdisc->fq_codel.memory_limit != NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET) - nm_utils_strbuf_append(&buf, &len, " memory_limit %u", qdisc->fq_codel.memory_limit); - if (qdisc->fq_codel.ecn) - nm_utils_strbuf_append(&buf, &len, " ecn"); - } else if (nm_streq0(qdisc->kind, "sfq")) { - if (qdisc->sfq.quantum) - nm_utils_strbuf_append(&buf, &len, " quantum %u", qdisc->sfq.quantum); - if (qdisc->sfq.perturb_period) - nm_utils_strbuf_append(&buf, &len, " perturb %d", qdisc->sfq.perturb_period); - if (qdisc->sfq.limit) - nm_utils_strbuf_append(&buf, &len, " limit %u", (guint) qdisc->sfq.limit); - if (qdisc->sfq.divisor) - nm_utils_strbuf_append(&buf, &len, " divisor %u", qdisc->sfq.divisor); - if (qdisc->sfq.flows) - nm_utils_strbuf_append(&buf, &len, " flows %u", qdisc->sfq.flows); - if (qdisc->sfq.depth) - nm_utils_strbuf_append(&buf, &len, " depth %u", qdisc->sfq.depth); - } else if (nm_streq0(qdisc->kind, "tbf")) { - nm_utils_strbuf_append(&buf, &len, " rate %" G_GUINT64_FORMAT, qdisc->tbf.rate); - nm_utils_strbuf_append(&buf, &len, " burst %u", qdisc->tbf.burst); - if (qdisc->tbf.limit) - nm_utils_strbuf_append(&buf, &len, " limit %u", qdisc->tbf.limit); - if (qdisc->tbf.latency) - nm_utils_strbuf_append(&buf, &len, " latency %uns", qdisc->tbf.latency); - } - - return buf0; -} - -void -nm_platform_qdisc_hash_update(const NMPlatformQdisc *obj, NMHashState *h) -{ - nm_hash_update_str0(h, obj->kind); - nm_hash_update_vals(h, obj->ifindex, obj->addr_family, obj->handle, obj->parent, obj->info); - if (nm_streq0(obj->kind, "fq_codel")) { - nm_hash_update_vals(h, - obj->fq_codel.limit, - obj->fq_codel.flows, - obj->fq_codel.target, - obj->fq_codel.interval, - obj->fq_codel.quantum, - obj->fq_codel.ce_threshold, - obj->fq_codel.memory_limit, - NM_HASH_COMBINE_BOOLS(guint8, obj->fq_codel.ecn)); - } else if (nm_streq0(obj->kind, "sfq")) { - nm_hash_update_vals(h, - obj->sfq.quantum, - obj->sfq.perturb_period, - obj->sfq.limit, - obj->sfq.divisor, - obj->sfq.flows, - obj->sfq.depth); - } else if (nm_streq0(obj->kind, "tbf")) { - nm_hash_update_vals(h, obj->tbf.rate, obj->tbf.burst, obj->tbf.limit, obj->tbf.latency); - } -} - -int -nm_platform_qdisc_cmp_full(const NMPlatformQdisc *a, - const NMPlatformQdisc *b, - gboolean compare_handle) -{ - NM_CMP_SELF(a, b); - NM_CMP_FIELD(a, b, ifindex); - NM_CMP_FIELD(a, b, parent); - NM_CMP_FIELD_STR_INTERNED(a, b, kind); - NM_CMP_FIELD(a, b, addr_family); - if (compare_handle) - NM_CMP_FIELD(a, b, handle); - NM_CMP_FIELD(a, b, info); - - if (nm_streq0(a->kind, "fq_codel")) { - NM_CMP_FIELD(a, b, fq_codel.limit); - NM_CMP_FIELD(a, b, fq_codel.flows); - NM_CMP_FIELD(a, b, fq_codel.target); - NM_CMP_FIELD(a, b, fq_codel.interval); - NM_CMP_FIELD(a, b, fq_codel.quantum); - NM_CMP_FIELD(a, b, fq_codel.ce_threshold); - NM_CMP_FIELD(a, b, fq_codel.memory_limit); - NM_CMP_FIELD_UNSAFE(a, b, fq_codel.ecn); - } else if (nm_streq0(a->kind, "sfq")) { - NM_CMP_FIELD(a, b, sfq.quantum); - NM_CMP_FIELD(a, b, sfq.perturb_period); - NM_CMP_FIELD(a, b, sfq.limit); - NM_CMP_FIELD(a, b, sfq.flows); - NM_CMP_FIELD(a, b, sfq.divisor); - NM_CMP_FIELD(a, b, sfq.depth); - } else if (nm_streq0(a->kind, "tbf")) { - NM_CMP_FIELD(a, b, tbf.rate); - NM_CMP_FIELD(a, b, tbf.burst); - NM_CMP_FIELD(a, b, tbf.limit); - NM_CMP_FIELD(a, b, tbf.latency); - } - - return 0; -} - -int -nm_platform_qdisc_cmp(const NMPlatformQdisc *a, const NMPlatformQdisc *b) -{ - return nm_platform_qdisc_cmp_full(a, b, TRUE); -} - -const char * -nm_platform_tfilter_to_string(const NMPlatformTfilter *tfilter, char *buf, gsize len) -{ - char str_dev[TO_STRING_DEV_BUF_SIZE]; - char act_buf[300]; - char *p; - gsize l; - - if (!nm_utils_to_string_buffer_init_null(tfilter, &buf, &len)) - return buf; - - if (tfilter->action.kind) { - p = act_buf; - l = sizeof(act_buf); - - nm_utils_strbuf_append(&p, &l, " \"%s\"", tfilter->action.kind); - if (nm_streq(tfilter->action.kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) { - gs_free char *t = NULL; - - nm_utils_strbuf_append( - &p, - &l, - " (\"%s\")", - nm_utils_str_utf8safe_escape(tfilter->action.kind, - NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL - | NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII, - &t)); - } else if (nm_streq(tfilter->action.kind, NM_PLATFORM_ACTION_KIND_MIRRED)) { - nm_utils_strbuf_append(&p, - &l, - "%s%s%s%s dev %d", - tfilter->action.mirred.ingress ? " ingress" : "", - tfilter->action.mirred.egress ? " egress" : "", - tfilter->action.mirred.mirror ? " mirror" : "", - tfilter->action.mirred.redirect ? " redirect" : "", - tfilter->action.mirred.ifindex); - } - } else - act_buf[0] = '\0'; - - g_snprintf(buf, - len, - "%s%s family %u handle %x parent %x info %x%s", - tfilter->kind, - _to_string_dev(NULL, tfilter->ifindex, str_dev, sizeof(str_dev)), - tfilter->addr_family, - tfilter->handle, - tfilter->parent, - tfilter->info, - act_buf); - - return buf; -} - -void -nm_platform_tfilter_hash_update(const NMPlatformTfilter *obj, NMHashState *h) -{ - nm_hash_update_str0(h, obj->kind); - nm_hash_update_vals(h, obj->ifindex, obj->addr_family, obj->handle, obj->parent, obj->info); - if (obj->action.kind) { - nm_hash_update_str(h, obj->action.kind); - if (nm_streq(obj->action.kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) { - nm_hash_update_strarr(h, obj->action.simple.sdata); - } else if (nm_streq(obj->action.kind, NM_PLATFORM_ACTION_KIND_MIRRED)) { - nm_hash_update_vals(h, - obj->action.mirred.ifindex, - NM_HASH_COMBINE_BOOLS(guint8, - obj->action.mirred.ingress, - obj->action.mirred.egress, - obj->action.mirred.mirror, - obj->action.mirred.redirect)); - } - } -} - -int -nm_platform_tfilter_cmp(const NMPlatformTfilter *a, const NMPlatformTfilter *b) -{ - NM_CMP_SELF(a, b); - NM_CMP_FIELD(a, b, ifindex); - NM_CMP_FIELD(a, b, parent); - NM_CMP_FIELD_STR_INTERNED(a, b, kind); - NM_CMP_FIELD(a, b, addr_family); - NM_CMP_FIELD(a, b, handle); - NM_CMP_FIELD(a, b, info); - - NM_CMP_FIELD_STR_INTERNED(a, b, action.kind); - if (a->action.kind) { - if (nm_streq(a->action.kind, NM_PLATFORM_ACTION_KIND_SIMPLE)) { - NM_CMP_FIELD_STR(a, b, action.simple.sdata); - } else if (nm_streq(a->action.kind, NM_PLATFORM_ACTION_KIND_MIRRED)) { - NM_CMP_FIELD(a, b, action.mirred.ifindex); - NM_CMP_FIELD_UNSAFE(a, b, action.mirred.ingress); - NM_CMP_FIELD_UNSAFE(a, b, action.mirred.egress); - NM_CMP_FIELD_UNSAFE(a, b, action.mirred.mirror); - NM_CMP_FIELD_UNSAFE(a, b, action.mirred.redirect); - } - } - - return 0; -} - -const char * -nm_platform_vf_to_string(const NMPlatformVF *vf, char *buf, gsize len) -{ - char str_mac[128], mac[128]; - char str_spoof_check[64]; - char str_trust[64]; - char str_min_tx_rate[64]; - char str_max_tx_rate[64]; - nm_auto_free_gstring GString *gstr_vlans = NULL; - guint i; - - if (!nm_utils_to_string_buffer_init_null(vf, &buf, &len)) - return buf; - - if (vf->mac.len) { - _nm_utils_hwaddr_ntoa(vf->mac.data, vf->mac.len, TRUE, mac, sizeof(mac)); - nm_sprintf_buf(str_mac, " mac %s", mac); - } else - str_mac[0] = '\0'; - - if (vf->num_vlans) { - gstr_vlans = g_string_new(""); - for (i = 0; i < vf->num_vlans; i++) { - g_string_append_printf(gstr_vlans, " vlan %u", (unsigned) vf->vlans[i].id); - if (vf->vlans[i].qos) - g_string_append_printf(gstr_vlans, " qos %u", (unsigned) vf->vlans[i].qos); - if (vf->vlans[i].proto_ad) - g_string_append(gstr_vlans, " proto 802.1ad"); - } - } - - g_snprintf(buf, - len, - "%u" /* index */ - "%s" /* MAC */ - "%s" /* spoof check */ - "%s" /* trust */ - "%s" /* min tx rate */ - "%s" /* max tx rate */ - "%s", /* VLANs */ - vf->index, - str_mac, - vf->spoofchk >= 0 ? nm_sprintf_buf(str_spoof_check, " spoofchk %d", vf->spoofchk) - : "", - vf->trust >= 0 ? nm_sprintf_buf(str_trust, " trust %d", vf->trust) : "", - vf->min_tx_rate - ? nm_sprintf_buf(str_min_tx_rate, " min_tx_rate %u", (unsigned) vf->min_tx_rate) - : "", - vf->max_tx_rate - ? nm_sprintf_buf(str_max_tx_rate, " max_tx_rate %u", (unsigned) vf->max_tx_rate) - : "", - gstr_vlans ? gstr_vlans->str : ""); - - return buf; -} - -const char * -nm_platform_bridge_vlan_to_string(const NMPlatformBridgeVlan *vlan, char *buf, gsize len) -{ - char str_vid_end[64]; - - if (!nm_utils_to_string_buffer_init_null(vlan, &buf, &len)) - return buf; - - g_snprintf(buf, - len, - "%u" - "%s" - "%s" - "%s", - vlan->vid_start, - vlan->vid_start != vlan->vid_end ? nm_sprintf_buf(str_vid_end, "-%u", vlan->vid_end) - : "", - vlan->pvid ? " PVID" : "", - vlan->untagged ? " untagged" : ""); - - return buf; -} - -void -nm_platform_link_hash_update(const NMPlatformLink *obj, NMHashState *h) -{ - nm_hash_update_vals(h, - obj->ifindex, - obj->master, - obj->parent, - obj->n_ifi_flags, - obj->mtu, - obj->type, - obj->arptype, - obj->inet6_addr_gen_mode_inv, - obj->inet6_token, - obj->rx_packets, - obj->rx_bytes, - obj->tx_packets, - obj->tx_bytes, - NM_HASH_COMBINE_BOOLS(guint8, obj->connected, obj->initialized)); - nm_hash_update_strarr(h, obj->name); - nm_hash_update_str0(h, obj->kind); - nm_hash_update_str0(h, obj->driver); - /* nm_hash_update_mem() also hashes the length obj->addr.len */ - nm_hash_update_mem(h, - obj->l_address.data, - NM_MIN(obj->l_address.len, sizeof(obj->l_address.data))); - nm_hash_update_mem(h, - obj->l_broadcast.data, - NM_MIN(obj->l_broadcast.len, sizeof(obj->l_broadcast.data))); -} - -int -nm_platform_link_cmp(const NMPlatformLink *a, const NMPlatformLink *b) -{ - NM_CMP_SELF(a, b); - NM_CMP_FIELD(a, b, ifindex); - NM_CMP_FIELD(a, b, type); - NM_CMP_FIELD_STR(a, b, name); - NM_CMP_FIELD(a, b, master); - NM_CMP_FIELD(a, b, parent); - NM_CMP_FIELD(a, b, n_ifi_flags); - NM_CMP_FIELD_UNSAFE(a, b, connected); - NM_CMP_FIELD(a, b, mtu); - NM_CMP_FIELD_BOOL(a, b, initialized); - NM_CMP_FIELD(a, b, arptype); - NM_CMP_FIELD(a, b, l_address.len); - NM_CMP_FIELD(a, b, l_broadcast.len); - NM_CMP_FIELD(a, b, inet6_addr_gen_mode_inv); - NM_CMP_FIELD_STR_INTERNED(a, b, kind); - NM_CMP_FIELD_STR_INTERNED(a, b, driver); - if (a->l_address.len) - NM_CMP_FIELD_MEMCMP_LEN(a, b, l_address.data, a->l_address.len); - if (a->l_broadcast.len) - NM_CMP_FIELD_MEMCMP_LEN(a, b, l_broadcast.data, a->l_broadcast.len); - NM_CMP_FIELD_MEMCMP(a, b, inet6_token); - NM_CMP_FIELD(a, b, rx_packets); - NM_CMP_FIELD(a, b, rx_bytes); - NM_CMP_FIELD(a, b, tx_packets); - NM_CMP_FIELD(a, b, tx_bytes); - return 0; -} - -void -nm_platform_lnk_bridge_hash_update(const NMPlatformLnkBridge *obj, NMHashState *h) -{ - nm_hash_update_vals(h, - obj->forward_delay, - obj->hello_time, - obj->max_age, - obj->ageing_time, - obj->priority, - obj->vlan_protocol, - obj->group_fwd_mask, - obj->group_addr, - obj->mcast_hash_max, - obj->mcast_last_member_count, - obj->mcast_startup_query_count, - obj->mcast_last_member_interval, - obj->mcast_membership_interval, - obj->mcast_querier_interval, - obj->mcast_query_interval, - obj->mcast_router, - obj->mcast_query_response_interval, - obj->mcast_startup_query_interval, - NM_HASH_COMBINE_BOOLS(guint8, - obj->stp_state, - obj->mcast_querier, - obj->mcast_query_use_ifaddr, - obj->mcast_snooping, - obj->vlan_stats_enabled)); -} - -int -nm_platform_lnk_bridge_cmp(const NMPlatformLnkBridge *a, const NMPlatformLnkBridge *b) -{ - NM_CMP_SELF(a, b); - NM_CMP_FIELD(a, b, forward_delay); - NM_CMP_FIELD(a, b, hello_time); - NM_CMP_FIELD(a, b, max_age); - NM_CMP_FIELD(a, b, ageing_time); - NM_CMP_FIELD_BOOL(a, b, stp_state); - NM_CMP_FIELD(a, b, priority); - NM_CMP_FIELD(a, b, vlan_protocol); - NM_CMP_FIELD_BOOL(a, b, vlan_stats_enabled); - NM_CMP_FIELD(a, b, group_fwd_mask); - NM_CMP_FIELD_MEMCMP(a, b, group_addr); - NM_CMP_FIELD_BOOL(a, b, mcast_snooping); - NM_CMP_FIELD(a, b, mcast_router); - NM_CMP_FIELD_BOOL(a, b, mcast_query_use_ifaddr); - NM_CMP_FIELD_BOOL(a, b, mcast_querier); - NM_CMP_FIELD(a, b, mcast_hash_max); - NM_CMP_FIELD(a, b, mcast_last_member_count); - NM_CMP_FIELD(a, b, mcast_startup_query_count); - NM_CMP_FIELD(a, b, mcast_last_member_interval); - NM_CMP_FIELD(a, b, mcast_membership_interval); - NM_CMP_FIELD(a, b, mcast_querier_interval); - NM_CMP_FIELD(a, b, mcast_query_interval); - NM_CMP_FIELD(a, b, mcast_query_response_interval); - NM_CMP_FIELD(a, b, mcast_startup_query_interval); - - return 0; -} - -void -nm_platform_lnk_gre_hash_update(const NMPlatformLnkGre *obj, NMHashState *h) -{ - nm_hash_update_vals(h, - obj->local, - obj->remote, - obj->parent_ifindex, - obj->input_flags, - obj->output_flags, - obj->input_key, - obj->output_key, - obj->ttl, - obj->tos, - (bool) obj->path_mtu_discovery, - (bool) obj->is_tap); -} - -int -nm_platform_lnk_gre_cmp(const NMPlatformLnkGre *a, const NMPlatformLnkGre *b) -{ - NM_CMP_SELF(a, b); - NM_CMP_FIELD(a, b, parent_ifindex); - NM_CMP_FIELD(a, b, input_flags); - NM_CMP_FIELD(a, b, output_flags); - NM_CMP_FIELD(a, b, input_key); - NM_CMP_FIELD(a, b, output_key); - NM_CMP_FIELD(a, b, local); - NM_CMP_FIELD(a, b, remote); - NM_CMP_FIELD(a, b, ttl); - NM_CMP_FIELD(a, b, tos); - NM_CMP_FIELD_BOOL(a, b, path_mtu_discovery); - NM_CMP_FIELD_BOOL(a, b, is_tap); - return 0; -} - -void -nm_platform_lnk_infiniband_hash_update(const NMPlatformLnkInfiniband *obj, NMHashState *h) -{ - nm_hash_update_val(h, obj->p_key); - nm_hash_update_str0(h, obj->mode); -} - -int -nm_platform_lnk_infiniband_cmp(const NMPlatformLnkInfiniband *a, const NMPlatformLnkInfiniband *b) -{ - NM_CMP_SELF(a, b); - NM_CMP_FIELD(a, b, p_key); - NM_CMP_FIELD_STR_INTERNED(a, b, mode); - return 0; -} - -void -nm_platform_lnk_ip6tnl_hash_update(const NMPlatformLnkIp6Tnl *obj, NMHashState *h) -{ - nm_hash_update_vals(h, - obj->local, - obj->remote, - obj->parent_ifindex, - obj->ttl, - obj->tclass, - obj->encap_limit, - obj->proto, - obj->flow_label, - obj->flags, - obj->input_flags, - obj->output_flags, - obj->input_key, - obj->output_key, - (bool) obj->is_gre, - (bool) obj->is_tap); -} - -int -nm_platform_lnk_ip6tnl_cmp(const NMPlatformLnkIp6Tnl *a, const NMPlatformLnkIp6Tnl *b) -{ - NM_CMP_SELF(a, b); - NM_CMP_FIELD(a, b, parent_ifindex); - NM_CMP_FIELD_MEMCMP(a, b, local); - NM_CMP_FIELD_MEMCMP(a, b, remote); - NM_CMP_FIELD(a, b, ttl); - NM_CMP_FIELD(a, b, tclass); - NM_CMP_FIELD(a, b, encap_limit); - NM_CMP_FIELD(a, b, flow_label); - NM_CMP_FIELD(a, b, proto); - NM_CMP_FIELD(a, b, flags); - NM_CMP_FIELD(a, b, input_flags); - NM_CMP_FIELD(a, b, output_flags); - NM_CMP_FIELD(a, b, input_key); - NM_CMP_FIELD(a, b, output_key); - NM_CMP_FIELD_BOOL(a, b, is_gre); - NM_CMP_FIELD_BOOL(a, b, is_tap); - return 0; -} - -void -nm_platform_lnk_ipip_hash_update(const NMPlatformLnkIpIp *obj, NMHashState *h) -{ - nm_hash_update_vals(h, - obj->local, - obj->remote, - obj->parent_ifindex, - obj->ttl, - obj->tos, - (bool) obj->path_mtu_discovery); -} - -int -nm_platform_lnk_ipip_cmp(const NMPlatformLnkIpIp *a, const NMPlatformLnkIpIp *b) -{ - NM_CMP_SELF(a, b); - NM_CMP_FIELD(a, b, parent_ifindex); - NM_CMP_FIELD(a, b, local); - NM_CMP_FIELD(a, b, remote); - NM_CMP_FIELD(a, b, ttl); - NM_CMP_FIELD(a, b, tos); - NM_CMP_FIELD_BOOL(a, b, path_mtu_discovery); - return 0; -} - -void -nm_platform_lnk_macsec_hash_update(const NMPlatformLnkMacsec *obj, NMHashState *h) -{ - nm_hash_update_vals(h, - obj->parent_ifindex, - obj->sci, - obj->cipher_suite, - obj->window, - obj->icv_length, - obj->encoding_sa, - obj->validation, - NM_HASH_COMBINE_BOOLS(guint8, - obj->encrypt, - obj->protect, - obj->include_sci, - obj->es, - obj->scb, - obj->replay_protect)); -} - -int -nm_platform_lnk_macsec_cmp(const NMPlatformLnkMacsec *a, const NMPlatformLnkMacsec *b) -{ - NM_CMP_SELF(a, b); - NM_CMP_FIELD(a, b, parent_ifindex); - NM_CMP_FIELD(a, b, sci); - NM_CMP_FIELD(a, b, icv_length); - NM_CMP_FIELD(a, b, cipher_suite); - NM_CMP_FIELD(a, b, window); - NM_CMP_FIELD(a, b, encoding_sa); - NM_CMP_FIELD(a, b, validation); - NM_CMP_FIELD_UNSAFE(a, b, encrypt); - NM_CMP_FIELD_UNSAFE(a, b, protect); - NM_CMP_FIELD_UNSAFE(a, b, include_sci); - NM_CMP_FIELD_UNSAFE(a, b, es); - NM_CMP_FIELD_UNSAFE(a, b, scb); - NM_CMP_FIELD_UNSAFE(a, b, replay_protect); - return 0; -} - -void -nm_platform_lnk_macvlan_hash_update(const NMPlatformLnkMacvlan *obj, NMHashState *h) -{ - nm_hash_update_vals(h, obj->mode, NM_HASH_COMBINE_BOOLS(guint8, obj->no_promisc, obj->tap)); -} - -int -nm_platform_lnk_macvlan_cmp(const NMPlatformLnkMacvlan *a, const NMPlatformLnkMacvlan *b) -{ - NM_CMP_SELF(a, b); - NM_CMP_FIELD(a, b, mode); - NM_CMP_FIELD_UNSAFE(a, b, no_promisc); - NM_CMP_FIELD_UNSAFE(a, b, tap); - return 0; -} - -void -nm_platform_lnk_sit_hash_update(const NMPlatformLnkSit *obj, NMHashState *h) -{ - nm_hash_update_vals(h, - obj->local, - obj->remote, - obj->parent_ifindex, - obj->flags, - obj->ttl, - obj->tos, - obj->proto, - (bool) obj->path_mtu_discovery); -} - -int -nm_platform_lnk_sit_cmp(const NMPlatformLnkSit *a, const NMPlatformLnkSit *b) -{ - NM_CMP_SELF(a, b); - NM_CMP_FIELD(a, b, parent_ifindex); - NM_CMP_FIELD(a, b, local); - NM_CMP_FIELD(a, b, remote); - NM_CMP_FIELD(a, b, ttl); - NM_CMP_FIELD(a, b, tos); - NM_CMP_FIELD_BOOL(a, b, path_mtu_discovery); - NM_CMP_FIELD(a, b, flags); - NM_CMP_FIELD(a, b, proto); - return 0; -} - -void -nm_platform_lnk_tun_hash_update(const NMPlatformLnkTun *obj, NMHashState *h) -{ - nm_hash_update_vals(h, - obj->type, - obj->owner, - obj->group, - NM_HASH_COMBINE_BOOLS(guint8, - obj->owner_valid, - obj->group_valid, - obj->pi, - obj->vnet_hdr, - obj->multi_queue, - obj->persist)); -} - -int -nm_platform_lnk_tun_cmp(const NMPlatformLnkTun *a, const NMPlatformLnkTun *b) -{ - NM_CMP_SELF(a, b); - NM_CMP_FIELD(a, b, type); - NM_CMP_FIELD(a, b, owner); - NM_CMP_FIELD(a, b, group); - NM_CMP_FIELD_BOOL(a, b, owner_valid); - NM_CMP_FIELD_BOOL(a, b, group_valid); - NM_CMP_FIELD_BOOL(a, b, pi); - NM_CMP_FIELD_BOOL(a, b, vnet_hdr); - NM_CMP_FIELD_BOOL(a, b, multi_queue); - NM_CMP_FIELD_BOOL(a, b, persist); - return 0; -} - -void -nm_platform_lnk_vlan_hash_update(const NMPlatformLnkVlan *obj, NMHashState *h) -{ - nm_hash_update_vals(h, obj->id, obj->flags); -} - -int -nm_platform_lnk_vlan_cmp(const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b) -{ - NM_CMP_SELF(a, b); - NM_CMP_FIELD(a, b, id); - NM_CMP_FIELD(a, b, flags); - return 0; -} - -void -nm_platform_lnk_vrf_hash_update(const NMPlatformLnkVrf *obj, NMHashState *h) -{ - nm_hash_update_vals(h, obj->table); -} - -int -nm_platform_lnk_vrf_cmp(const NMPlatformLnkVrf *a, const NMPlatformLnkVrf *b) -{ - NM_CMP_SELF(a, b); - NM_CMP_FIELD(a, b, table); - return 0; -} - -void -nm_platform_lnk_vxlan_hash_update(const NMPlatformLnkVxlan *obj, NMHashState *h) -{ - nm_hash_update_vals(h, - obj->group6, - obj->local6, - obj->group, - obj->local, - obj->parent_ifindex, - obj->id, - obj->ageing, - obj->limit, - obj->dst_port, - obj->src_port_min, - obj->src_port_max, - obj->tos, - obj->ttl, - NM_HASH_COMBINE_BOOLS(guint8, - obj->learning, - obj->proxy, - obj->rsc, - obj->l2miss, - obj->l3miss)); -} - -int -nm_platform_lnk_vxlan_cmp(const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *b) -{ - NM_CMP_SELF(a, b); - NM_CMP_FIELD(a, b, parent_ifindex); - NM_CMP_FIELD(a, b, id); - NM_CMP_FIELD(a, b, group); - NM_CMP_FIELD(a, b, local); - NM_CMP_FIELD_MEMCMP(a, b, group6); - NM_CMP_FIELD_MEMCMP(a, b, local6); - NM_CMP_FIELD(a, b, tos); - NM_CMP_FIELD(a, b, ttl); - NM_CMP_FIELD_BOOL(a, b, learning); - NM_CMP_FIELD(a, b, ageing); - NM_CMP_FIELD(a, b, limit); - NM_CMP_FIELD(a, b, dst_port); - NM_CMP_FIELD(a, b, src_port_min); - NM_CMP_FIELD(a, b, src_port_max); - NM_CMP_FIELD_BOOL(a, b, proxy); - NM_CMP_FIELD_BOOL(a, b, rsc); - NM_CMP_FIELD_BOOL(a, b, l2miss); - NM_CMP_FIELD_BOOL(a, b, l3miss); - return 0; -} - -void -nm_platform_lnk_wireguard_hash_update(const NMPlatformLnkWireGuard *obj, NMHashState *h) -{ - nm_hash_update_vals(h, obj->listen_port, obj->fwmark); - nm_hash_update(h, obj->private_key, sizeof(obj->private_key)); - nm_hash_update(h, obj->public_key, sizeof(obj->public_key)); -} - -int -nm_platform_lnk_wireguard_cmp(const NMPlatformLnkWireGuard *a, const NMPlatformLnkWireGuard *b) -{ - NM_CMP_SELF(a, b); - NM_CMP_FIELD(a, b, listen_port); - NM_CMP_FIELD(a, b, fwmark); - NM_CMP_FIELD_MEMCMP(a, b, private_key); - NM_CMP_FIELD_MEMCMP(a, b, public_key); - return 0; -} - -static int -_address_pretty_sort_get_prio_4(in_addr_t addr) -{ - if (nm_utils_ip4_address_is_link_local(addr)) - return 0; - return 1; -} - -int -nm_platform_ip4_address_pretty_sort_cmp(const NMPlatformIP4Address *a1, - const NMPlatformIP4Address *a2) -{ - in_addr_t n1; - in_addr_t n2; - - nm_assert(a1); - nm_assert(a2); - - /* Sort by address type. For example link local will - * be sorted *after* a global address. */ - NM_CMP_DIRECT(_address_pretty_sort_get_prio_4(a2->address), - _address_pretty_sort_get_prio_4(a1->address)); - - /* Sort the addresses based on their source. */ - NM_CMP_DIRECT(a2->addr_source, a1->addr_source); - - NM_CMP_DIRECT((a2->label[0] == '\0'), (a1->label[0] == '\0')); - - /* Finally, sort addresses lexically. We compare only the - * network part so that the order of addresses in the same - * subnet (and thus also the primary/secondary role) is - * preserved. - */ - n1 = a1->address & _nm_utils_ip4_prefix_to_netmask(a1->plen); - n2 = a2->address & _nm_utils_ip4_prefix_to_netmask(a2->plen); - NM_CMP_DIRECT_MEMCMP(&n1, &n2, sizeof(guint32)); - return 0; -} - -static int -_address_pretty_sort_get_prio_6(const struct in6_addr *addr) -{ - if (IN6_IS_ADDR_V4MAPPED(addr)) - return 0; - if (IN6_IS_ADDR_V4COMPAT(addr)) - return 1; - if (IN6_IS_ADDR_UNSPECIFIED(addr)) - return 2; - if (IN6_IS_ADDR_LOOPBACK(addr)) - return 3; - if (IN6_IS_ADDR_LINKLOCAL(addr)) - return 4; - if (IN6_IS_ADDR_SITELOCAL(addr)) - return 5; - return 6; -} - -int -nm_platform_ip6_address_pretty_sort_cmp(const NMPlatformIP6Address *a1, - const NMPlatformIP6Address *a2, - gboolean prefer_temp) -{ - gboolean ipv6_privacy1; - gboolean ipv6_privacy2; - - nm_assert(a1); - nm_assert(a2); - - /* tentative addresses are always sorted back... */ - /* sort tentative addresses after non-tentative. */ - NM_CMP_DIRECT(NM_FLAGS_HAS(a1->n_ifa_flags, IFA_F_TENTATIVE), - NM_FLAGS_HAS(a2->n_ifa_flags, IFA_F_TENTATIVE)); - - /* Sort by address type. For example link local will - * be sorted *after* site local or global. */ - NM_CMP_DIRECT(_address_pretty_sort_get_prio_6(&a2->address), - _address_pretty_sort_get_prio_6(&a1->address)); - - ipv6_privacy1 = NM_FLAGS_ANY(a1->n_ifa_flags, IFA_F_MANAGETEMPADDR | IFA_F_TEMPORARY); - ipv6_privacy2 = NM_FLAGS_ANY(a2->n_ifa_flags, IFA_F_MANAGETEMPADDR | IFA_F_TEMPORARY); - if (ipv6_privacy1 || ipv6_privacy2) { - gboolean public1 = TRUE; - gboolean public2 = TRUE; - - if (ipv6_privacy1) { - if (a1->n_ifa_flags & IFA_F_TEMPORARY) - public1 = prefer_temp; - else - public1 = !prefer_temp; - } - if (ipv6_privacy2) { - if (a2->n_ifa_flags & IFA_F_TEMPORARY) - public2 = prefer_temp; - else - public2 = !prefer_temp; - } - - NM_CMP_DIRECT(public2, public1); - } - - /* Sort the addresses based on their source. */ - NM_CMP_DIRECT(a2->addr_source, a1->addr_source); - - /* sort permanent addresses before non-permanent. */ - NM_CMP_DIRECT(NM_FLAGS_HAS(a2->n_ifa_flags, IFA_F_PERMANENT), - NM_FLAGS_HAS(a1->n_ifa_flags, IFA_F_PERMANENT)); - - /* finally sort addresses lexically */ - NM_CMP_DIRECT_IN6ADDR(&a1->address, &a2->address); - NM_CMP_DIRECT_MEMCMP(a1, a2, sizeof(*a1)); - return 0; -} - -void -nm_platform_ip4_address_hash_update(const NMPlatformIP4Address *obj, NMHashState *h) -{ - nm_hash_update_vals(h, - obj->ifindex, - obj->addr_source, - obj->use_ip4_broadcast_address ? obj->broadcast_address : ((in_addr_t) 0u), - obj->timestamp, - obj->lifetime, - obj->preferred, - obj->n_ifa_flags, - obj->plen, - obj->address, - obj->peer_address, - NM_HASH_COMBINE_BOOLS(guint8, - obj->external, - obj->use_ip4_broadcast_address, - obj->ip4acd_not_ready)); - nm_hash_update_strarr(h, obj->label); -} - -int -nm_platform_ip4_address_cmp(const NMPlatformIP4Address *a, const NMPlatformIP4Address *b) -{ - NM_CMP_SELF(a, b); - NM_CMP_FIELD(a, b, ifindex); - NM_CMP_FIELD(a, b, address); - NM_CMP_FIELD(a, b, plen); - NM_CMP_FIELD(a, b, peer_address); - NM_CMP_FIELD_UNSAFE(a, b, use_ip4_broadcast_address); - if (a->use_ip4_broadcast_address) - NM_CMP_FIELD(a, b, broadcast_address); - NM_CMP_FIELD(a, b, addr_source); - NM_CMP_FIELD(a, b, timestamp); - NM_CMP_FIELD(a, b, lifetime); - NM_CMP_FIELD(a, b, preferred); - NM_CMP_FIELD(a, b, n_ifa_flags); - NM_CMP_FIELD_STR(a, b, label); - NM_CMP_FIELD_UNSAFE(a, b, external); - NM_CMP_FIELD_UNSAFE(a, b, ip4acd_not_ready); - return 0; -} - -void -nm_platform_ip6_address_hash_update(const NMPlatformIP6Address *obj, NMHashState *h) -{ - nm_hash_update_vals(h, - obj->ifindex, - obj->addr_source, - obj->timestamp, - obj->lifetime, - obj->preferred, - obj->n_ifa_flags, - obj->plen, - obj->address, - obj->peer_address, - NM_HASH_COMBINE_BOOLS(guint8, obj->external)); -} - -int -nm_platform_ip6_address_cmp(const NMPlatformIP6Address *a, const NMPlatformIP6Address *b) -{ - const struct in6_addr *p_a, *p_b; - - NM_CMP_SELF(a, b); - NM_CMP_FIELD(a, b, ifindex); - NM_CMP_FIELD_MEMCMP(a, b, address); - NM_CMP_FIELD(a, b, plen); - p_a = nm_platform_ip6_address_get_peer(a); - p_b = nm_platform_ip6_address_get_peer(b); - NM_CMP_DIRECT_MEMCMP(p_a, p_b, sizeof(*p_a)); - NM_CMP_FIELD(a, b, addr_source); - NM_CMP_FIELD(a, b, timestamp); - NM_CMP_FIELD(a, b, lifetime); - NM_CMP_FIELD(a, b, preferred); - NM_CMP_FIELD(a, b, n_ifa_flags); - NM_CMP_FIELD_UNSAFE(a, b, external); - return 0; -} - -void -nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj, - NMPlatformIPRouteCmpType cmp_type, - NMHashState * h) -{ - switch (cmp_type) { - case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID: - nm_hash_update_vals( - h, - nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)), - nm_utils_ip4_address_clear_host_address(obj->network, obj->plen), - obj->plen, - obj->metric, - obj->tos, - NM_HASH_COMBINE_BOOLS(guint8, obj->metric_any, obj->table_any)); - break; - case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID: - nm_hash_update_vals( - h, - obj->type_coerced, - nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)), - nm_utils_ip4_address_clear_host_address(obj->network, obj->plen), - obj->plen, - obj->metric, - obj->tos, - /* on top of WEAK_ID: */ - obj->ifindex, - nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source), - _ip_route_scope_inv_get_normalized(obj), - obj->gateway, - obj->mss, - obj->pref_src, - obj->window, - obj->cwnd, - obj->initcwnd, - obj->initrwnd, - obj->mtu, - obj->r_rtm_flags & RTNH_F_ONLINK, - NM_HASH_COMBINE_BOOLS(guint8, - obj->metric_any, - obj->table_any, - obj->lock_window, - obj->lock_cwnd, - obj->lock_initcwnd, - obj->lock_initrwnd, - obj->lock_mtu)); - break; - case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY: - nm_hash_update_vals( - h, - obj->type_coerced, - nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)), - obj->ifindex, - nm_utils_ip4_address_clear_host_address(obj->network, obj->plen), - obj->plen, - obj->metric, - obj->gateway, - nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source), - _ip_route_scope_inv_get_normalized(obj), - obj->tos, - obj->mss, - obj->pref_src, - obj->window, - obj->cwnd, - obj->initcwnd, - obj->initrwnd, - obj->mtu, - obj->r_rtm_flags & (RTM_F_CLONED | RTNH_F_ONLINK), - NM_HASH_COMBINE_BOOLS(guint8, - obj->metric_any, - obj->table_any, - obj->lock_window, - obj->lock_cwnd, - obj->lock_initcwnd, - obj->lock_initrwnd, - obj->lock_mtu)); - break; - case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL: - nm_hash_update_vals(h, - obj->type_coerced, - obj->table_coerced, - obj->ifindex, - obj->network, - obj->plen, - obj->metric, - obj->gateway, - obj->rt_source, - obj->scope_inv, - obj->tos, - obj->mss, - obj->pref_src, - obj->window, - obj->cwnd, - obj->initcwnd, - obj->initrwnd, - obj->mtu, - obj->r_rtm_flags, - NM_HASH_COMBINE_BOOLS(guint8, - obj->metric_any, - obj->table_any, - obj->lock_window, - obj->lock_cwnd, - obj->lock_initcwnd, - obj->lock_initrwnd, - obj->lock_mtu)); - break; - } -} - -int -nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a, - const NMPlatformIP4Route *b, - NMPlatformIPRouteCmpType cmp_type) -{ - NM_CMP_SELF(a, b); - switch (cmp_type) { - case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID: - case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID: - NM_CMP_FIELD_UNSAFE(a, b, table_any); - NM_CMP_DIRECT(nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(a)), - nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(b))); - NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX(a->network, b->network, MIN(a->plen, b->plen)); - NM_CMP_FIELD(a, b, plen); - NM_CMP_FIELD_UNSAFE(a, b, metric_any); - NM_CMP_FIELD(a, b, metric); - NM_CMP_FIELD(a, b, tos); - if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) { - NM_CMP_FIELD(a, b, ifindex); - NM_CMP_FIELD(a, b, type_coerced); - NM_CMP_DIRECT(nmp_utils_ip_config_source_round_trip_rtprot(a->rt_source), - nmp_utils_ip_config_source_round_trip_rtprot(b->rt_source)); - NM_CMP_DIRECT(_ip_route_scope_inv_get_normalized(a), - _ip_route_scope_inv_get_normalized(b)); - NM_CMP_FIELD(a, b, gateway); - NM_CMP_FIELD(a, b, mss); - NM_CMP_FIELD(a, b, pref_src); - NM_CMP_FIELD(a, b, window); - NM_CMP_FIELD(a, b, cwnd); - NM_CMP_FIELD(a, b, initcwnd); - NM_CMP_FIELD(a, b, initrwnd); - NM_CMP_FIELD(a, b, mtu); - NM_CMP_DIRECT(a->r_rtm_flags & RTNH_F_ONLINK, b->r_rtm_flags & RTNH_F_ONLINK); - NM_CMP_FIELD_UNSAFE(a, b, lock_window); - NM_CMP_FIELD_UNSAFE(a, b, lock_cwnd); - NM_CMP_FIELD_UNSAFE(a, b, lock_initcwnd); - NM_CMP_FIELD_UNSAFE(a, b, lock_initrwnd); - NM_CMP_FIELD_UNSAFE(a, b, lock_mtu); - } - break; - case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY: - case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL: - NM_CMP_FIELD(a, b, type_coerced); - NM_CMP_FIELD_UNSAFE(a, b, table_any); - if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) { - NM_CMP_DIRECT(nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(a)), - nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(b))); - } else - NM_CMP_FIELD(a, b, table_coerced); - NM_CMP_FIELD(a, b, ifindex); - if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) - NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX(a->network, b->network, MIN(a->plen, b->plen)); - else - NM_CMP_FIELD(a, b, network); - NM_CMP_FIELD(a, b, plen); - NM_CMP_FIELD_UNSAFE(a, b, metric_any); - NM_CMP_FIELD(a, b, metric); - NM_CMP_FIELD(a, b, gateway); - if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) { - NM_CMP_DIRECT(nmp_utils_ip_config_source_round_trip_rtprot(a->rt_source), - nmp_utils_ip_config_source_round_trip_rtprot(b->rt_source)); - NM_CMP_DIRECT(_ip_route_scope_inv_get_normalized(a), - _ip_route_scope_inv_get_normalized(b)); - } else { - NM_CMP_FIELD(a, b, rt_source); - NM_CMP_FIELD(a, b, scope_inv); - } - NM_CMP_FIELD(a, b, mss); - NM_CMP_FIELD(a, b, pref_src); - if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) { - NM_CMP_DIRECT(a->r_rtm_flags & (RTM_F_CLONED | RTNH_F_ONLINK), - b->r_rtm_flags & (RTM_F_CLONED | RTNH_F_ONLINK)); - } else - NM_CMP_FIELD(a, b, r_rtm_flags); - NM_CMP_FIELD(a, b, tos); - NM_CMP_FIELD_UNSAFE(a, b, lock_window); - NM_CMP_FIELD_UNSAFE(a, b, lock_cwnd); - NM_CMP_FIELD_UNSAFE(a, b, lock_initcwnd); - NM_CMP_FIELD_UNSAFE(a, b, lock_initrwnd); - NM_CMP_FIELD_UNSAFE(a, b, lock_mtu); - NM_CMP_FIELD(a, b, window); - NM_CMP_FIELD(a, b, cwnd); - NM_CMP_FIELD(a, b, initcwnd); - NM_CMP_FIELD(a, b, initrwnd); - NM_CMP_FIELD(a, b, mtu); - break; - } - return 0; -} - -void -nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj, - NMPlatformIPRouteCmpType cmp_type, - NMHashState * h) -{ - struct in6_addr a1, a2; - - switch (cmp_type) { - case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID: - nm_hash_update_vals( - h, - nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)), - *nm_utils_ip6_address_clear_host_address(&a1, &obj->network, obj->plen), - obj->plen, - obj->metric, - *nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen), - obj->src_plen, - NM_HASH_COMBINE_BOOLS(guint8, obj->metric_any, obj->table_any)); - break; - case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID: - nm_hash_update_vals( - h, - obj->type_coerced, - nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)), - *nm_utils_ip6_address_clear_host_address(&a1, &obj->network, obj->plen), - obj->plen, - obj->metric, - *nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen), - obj->src_plen, - NM_HASH_COMBINE_BOOLS(guint8, obj->metric_any, obj->table_any), - /* on top of WEAK_ID: */ - obj->ifindex, - obj->gateway); - break; - case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY: - nm_hash_update_vals( - h, - obj->type_coerced, - nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(obj)), - obj->ifindex, - *nm_utils_ip6_address_clear_host_address(&a1, &obj->network, obj->plen), - obj->plen, - obj->metric, - obj->gateway, - obj->pref_src, - *nm_utils_ip6_address_clear_host_address(&a2, &obj->src, obj->src_plen), - obj->src_plen, - nmp_utils_ip_config_source_round_trip_rtprot(obj->rt_source), - obj->mss, - obj->r_rtm_flags & RTM_F_CLONED, - NM_HASH_COMBINE_BOOLS(guint8, - obj->metric_any, - obj->table_any, - obj->lock_window, - obj->lock_cwnd, - obj->lock_initcwnd, - obj->lock_initrwnd, - obj->lock_mtu), - obj->window, - obj->cwnd, - obj->initcwnd, - obj->initrwnd, - obj->mtu, - _route_pref_normalize(obj->rt_pref)); - break; - case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL: - nm_hash_update_vals(h, - obj->type_coerced, - obj->table_coerced, - obj->ifindex, - obj->network, - obj->metric, - obj->gateway, - obj->pref_src, - obj->src, - obj->src_plen, - obj->rt_source, - obj->mss, - obj->r_rtm_flags, - NM_HASH_COMBINE_BOOLS(guint8, - obj->metric_any, - obj->table_any, - obj->lock_window, - obj->lock_cwnd, - obj->lock_initcwnd, - obj->lock_initrwnd, - obj->lock_mtu), - obj->window, - obj->cwnd, - obj->initcwnd, - obj->initrwnd, - obj->mtu, - obj->rt_pref); - break; - } -} - -int -nm_platform_ip6_route_cmp(const NMPlatformIP6Route *a, - const NMPlatformIP6Route *b, - NMPlatformIPRouteCmpType cmp_type) -{ - NM_CMP_SELF(a, b); - switch (cmp_type) { - case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID: - case NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID: - NM_CMP_FIELD_UNSAFE(a, b, table_any); - NM_CMP_DIRECT(nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(a)), - nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(b))); - NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX(&a->network, &b->network, MIN(a->plen, b->plen)); - NM_CMP_FIELD(a, b, plen); - NM_CMP_FIELD_UNSAFE(a, b, metric_any); - NM_CMP_FIELD(a, b, metric); - NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX(&a->src, &b->src, MIN(a->src_plen, b->src_plen)); - NM_CMP_FIELD(a, b, src_plen); - if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) { - NM_CMP_FIELD(a, b, ifindex); - NM_CMP_FIELD(a, b, type_coerced); - NM_CMP_FIELD_IN6ADDR(a, b, gateway); - } - break; - case NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY: - case NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL: - NM_CMP_FIELD(a, b, type_coerced); - NM_CMP_FIELD_UNSAFE(a, b, table_any); - if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) { - NM_CMP_DIRECT(nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(a)), - nm_platform_ip_route_get_effective_table(NM_PLATFORM_IP_ROUTE_CAST(b))); - } else - NM_CMP_FIELD(a, b, table_coerced); - NM_CMP_FIELD(a, b, ifindex); - if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) - NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX(&a->network, &b->network, MIN(a->plen, b->plen)); - else - NM_CMP_FIELD_IN6ADDR(a, b, network); - NM_CMP_FIELD(a, b, plen); - NM_CMP_FIELD_UNSAFE(a, b, metric_any); - NM_CMP_FIELD(a, b, metric); - NM_CMP_FIELD_IN6ADDR(a, b, gateway); - NM_CMP_FIELD_IN6ADDR(a, b, pref_src); - if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) { - NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX(&a->src, &b->src, MIN(a->src_plen, b->src_plen)); - NM_CMP_FIELD(a, b, src_plen); - NM_CMP_DIRECT(nmp_utils_ip_config_source_round_trip_rtprot(a->rt_source), - nmp_utils_ip_config_source_round_trip_rtprot(b->rt_source)); - } else { - NM_CMP_FIELD_IN6ADDR(a, b, src); - NM_CMP_FIELD(a, b, src_plen); - NM_CMP_FIELD(a, b, rt_source); - } - NM_CMP_FIELD(a, b, mss); - if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) { - NM_CMP_DIRECT(a->r_rtm_flags & RTM_F_CLONED, b->r_rtm_flags & RTM_F_CLONED); - } else - NM_CMP_FIELD(a, b, r_rtm_flags); - NM_CMP_FIELD_UNSAFE(a, b, lock_window); - NM_CMP_FIELD_UNSAFE(a, b, lock_cwnd); - NM_CMP_FIELD_UNSAFE(a, b, lock_initcwnd); - NM_CMP_FIELD_UNSAFE(a, b, lock_initrwnd); - NM_CMP_FIELD_UNSAFE(a, b, lock_mtu); - NM_CMP_FIELD(a, b, window); - NM_CMP_FIELD(a, b, cwnd); - NM_CMP_FIELD(a, b, initcwnd); - NM_CMP_FIELD(a, b, initrwnd); - NM_CMP_FIELD(a, b, mtu); - if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) - NM_CMP_DIRECT(_route_pref_normalize(a->rt_pref), _route_pref_normalize(b->rt_pref)); - else - NM_CMP_FIELD(a, b, rt_pref); - break; - } - return 0; -} - -#define _ROUTING_RULE_FLAGS_IGNORE \ - (FIB_RULE_UNRESOLVED | FIB_RULE_IIF_DETACHED | FIB_RULE_OIF_DETACHED) - -#define _routing_rule_compare(cmp_type, kernel_support_type) \ - ((cmp_type) == NM_PLATFORM_ROUTING_RULE_CMP_TYPE_FULL \ - || nm_platform_kernel_support_get(kernel_support_type)) - -void -nm_platform_routing_rule_hash_update(const NMPlatformRoutingRule *obj, - NMPlatformRoutingRuleCmpType cmp_type, - NMHashState * h) -{ - gboolean cmp_full = TRUE; - gsize addr_size; - guint32 flags_mask = G_MAXUINT32; - - if (G_UNLIKELY(!NM_IN_SET(obj->addr_family, AF_INET, AF_INET6))) { - /* the address family is not one of the supported ones. That means, the - * instance will only compare equal to itself (pointer-equality). */ - nm_hash_update_val(h, (gconstpointer) obj); - return; - } - - switch (cmp_type) { - case NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID: - - flags_mask &= ~_ROUTING_RULE_FLAGS_IGNORE; - - /* fall-through */ - case NM_PLATFORM_ROUTING_RULE_CMP_TYPE_SEMANTICALLY: - - cmp_full = FALSE; - - /* fall-through */ - case NM_PLATFORM_ROUTING_RULE_CMP_TYPE_FULL: - - nm_hash_update_vals( - h, - obj->addr_family, - obj->tun_id, - obj->table, - obj->flags & flags_mask, - obj->priority, - obj->fwmark, - obj->fwmask, - ((cmp_full - || (cmp_type == NM_PLATFORM_ROUTING_RULE_CMP_TYPE_SEMANTICALLY - && obj->action == FR_ACT_GOTO)) - ? obj->goto_target - : (guint32) 0u), - ((cmp_full || obj->addr_family == AF_INET) ? obj->flow : (guint32) 0u), - NM_HASH_COMBINE_BOOLS( - guint8, - (_routing_rule_compare(cmp_type, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_UID_RANGE) - ? obj->uid_range_has - : FALSE)), - obj->suppress_prefixlen_inverse, - obj->suppress_ifgroup_inverse, - (_routing_rule_compare(cmp_type, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_L3MDEV) - ? (cmp_full ? (guint16) obj->l3mdev : (guint16) !!obj->l3mdev) - : G_MAXUINT16), - obj->action, - obj->tos, - obj->src_len, - obj->dst_len, - (_routing_rule_compare(cmp_type, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_PROTOCOL) - ? (guint16) obj->protocol - : G_MAXUINT16)); - addr_size = nm_utils_addr_family_to_size(obj->addr_family); - if (cmp_full || obj->src_len > 0) - nm_hash_update(h, &obj->src, addr_size); - if (cmp_full || obj->dst_len > 0) - nm_hash_update(h, &obj->dst, addr_size); - if (_routing_rule_compare(cmp_type, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_UID_RANGE)) { - if (cmp_full || obj->uid_range_has) - nm_hash_update_valp(h, &obj->uid_range); - } - if (_routing_rule_compare(cmp_type, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_IP_PROTO)) { - nm_hash_update_val(h, obj->ip_proto); - nm_hash_update_valp(h, &obj->sport_range); - nm_hash_update_valp(h, &obj->dport_range); - } - nm_hash_update_str(h, obj->iifname); - nm_hash_update_str(h, obj->oifname); - return; - } - - nm_assert_not_reached(); -} - -int -nm_platform_routing_rule_cmp(const NMPlatformRoutingRule *a, - const NMPlatformRoutingRule *b, - NMPlatformRoutingRuleCmpType cmp_type) -{ - gboolean cmp_full = TRUE; - gsize addr_size; - bool valid; - guint32 flags_mask = G_MAXUINT32; - - NM_CMP_SELF(a, b); - - valid = NM_IN_SET(a->addr_family, AF_INET, AF_INET6); - NM_CMP_DIRECT(valid, (bool) NM_IN_SET(b->addr_family, AF_INET, AF_INET6)); - - if (G_UNLIKELY(!valid)) { - /* the address family is not one of the supported ones. That means, the - * instance will only compare equal to itself. */ - NM_CMP_DIRECT((uintptr_t) a, (uintptr_t) b); - nm_assert_not_reached(); - return 0; - } - - switch (cmp_type) { - case NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID: - - flags_mask &= ~_ROUTING_RULE_FLAGS_IGNORE; - - /* fall-through */ - case NM_PLATFORM_ROUTING_RULE_CMP_TYPE_SEMANTICALLY: - - cmp_full = FALSE; - - /* fall-through */ - case NM_PLATFORM_ROUTING_RULE_CMP_TYPE_FULL: - NM_CMP_FIELD(a, b, addr_family); - NM_CMP_FIELD(a, b, action); - NM_CMP_FIELD(a, b, priority); - NM_CMP_FIELD(a, b, tun_id); - - if (_routing_rule_compare(cmp_type, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_L3MDEV)) { - if (cmp_full) - NM_CMP_FIELD(a, b, l3mdev); - else - NM_CMP_FIELD_BOOL(a, b, l3mdev); - } - - NM_CMP_FIELD(a, b, table); - - NM_CMP_DIRECT(a->flags & flags_mask, b->flags & flags_mask); - - NM_CMP_FIELD(a, b, fwmark); - NM_CMP_FIELD(a, b, fwmask); - - if (cmp_full - || (cmp_type == NM_PLATFORM_ROUTING_RULE_CMP_TYPE_SEMANTICALLY - && a->action == FR_ACT_GOTO)) - NM_CMP_FIELD(a, b, goto_target); - - NM_CMP_FIELD(a, b, suppress_prefixlen_inverse); - NM_CMP_FIELD(a, b, suppress_ifgroup_inverse); - NM_CMP_FIELD(a, b, tos); - - if (cmp_full || a->addr_family == AF_INET) - NM_CMP_FIELD(a, b, flow); - - if (_routing_rule_compare(cmp_type, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_PROTOCOL)) - NM_CMP_FIELD(a, b, protocol); - - if (_routing_rule_compare(cmp_type, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_IP_PROTO)) { - NM_CMP_FIELD(a, b, ip_proto); - NM_CMP_FIELD(a, b, sport_range.start); - NM_CMP_FIELD(a, b, sport_range.end); - NM_CMP_FIELD(a, b, dport_range.start); - NM_CMP_FIELD(a, b, dport_range.end); - } - - addr_size = nm_utils_addr_family_to_size(a->addr_family); - - NM_CMP_FIELD(a, b, src_len); - if (cmp_full || a->src_len > 0) - NM_CMP_FIELD_MEMCMP_LEN(a, b, src, addr_size); - - NM_CMP_FIELD(a, b, dst_len); - if (cmp_full || a->dst_len > 0) - NM_CMP_FIELD_MEMCMP_LEN(a, b, dst, addr_size); - - if (_routing_rule_compare(cmp_type, NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_UID_RANGE)) { - NM_CMP_FIELD_UNSAFE(a, b, uid_range_has); - if (cmp_full || a->uid_range_has) { - NM_CMP_FIELD(a, b, uid_range.start); - NM_CMP_FIELD(a, b, uid_range.end); - } - } - - NM_CMP_FIELD_STR(a, b, iifname); - NM_CMP_FIELD_STR(a, b, oifname); - return 0; - } - - nm_assert_not_reached(); - return 0; -} - -/** - * nm_platform_ip_address_cmp_expiry: - * @a: a NMPlatformIPAddress to compare - * @b: the other NMPlatformIPAddress to compare - * - * Compares two addresses and returns which one has a longer remaining lifetime. - * If both addresses have the same lifetime, look at the remaining preferred time. - * - * For comparison, only the timestamp, lifetime and preferred fields are considered. - * If they compare equal (== 0), their other fields were not considered. - * - * Returns: -1, 0, or 1 according to the comparison - **/ -int -nm_platform_ip_address_cmp_expiry(const NMPlatformIPAddress *a, const NMPlatformIPAddress *b) -{ - gint64 ta = 0, tb = 0; - - NM_CMP_SELF(a, b); - - if (a->lifetime == NM_PLATFORM_LIFETIME_PERMANENT || a->lifetime == 0) - ta = G_MAXINT64; - else if (a->timestamp) - ta = ((gint64) a->timestamp) + a->lifetime; - - if (b->lifetime == NM_PLATFORM_LIFETIME_PERMANENT || b->lifetime == 0) - tb = G_MAXINT64; - else if (b->timestamp) - tb = ((gint64) b->timestamp) + b->lifetime; - - if (ta == tb) { - /* if the lifetime is equal, compare the preferred time. */ - ta = tb = 0; - - if (a->preferred == NM_PLATFORM_LIFETIME_PERMANENT - || a->lifetime == 0 /* lifetime==0 means permanent! */) - ta = G_MAXINT64; - else if (a->timestamp) - ta = ((gint64) a->timestamp) + a->preferred; - - if (b->preferred == NM_PLATFORM_LIFETIME_PERMANENT || b->lifetime == 0) - tb = G_MAXINT64; - else if (b->timestamp) - tb = ((gint64) b->timestamp) + b->preferred; - - if (ta == tb) - return 0; - } - - return ta < tb ? -1 : 1; -} - -/*****************************************************************************/ - -GHashTable * -nm_platform_ip4_address_addr_to_hash(NMPlatform *self, int ifindex) -{ - const NMDedupMultiHeadEntry *head_entry; - NMDedupMultiIter iter; - const NMPObject * obj; - NMPLookup lookup; - GHashTable * hash; - - g_return_val_if_fail(NM_IS_PLATFORM(self), NULL); - g_return_val_if_fail(ifindex > 0, NULL); - - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex); - - head_entry = nmp_cache_lookup(NM_PLATFORM_GET_PRIVATE(self)->cache, &lookup); - - if (!head_entry) - return NULL; - - hash = g_hash_table_new(nm_direct_hash, NULL); - - nmp_cache_iter_for_each (&iter, head_entry, &obj) { - const NMPlatformIP4Address *a = NMP_OBJECT_CAST_IP4_ADDRESS(obj); - - g_hash_table_add(hash, GUINT_TO_POINTER(a->address)); - } - - return hash; -} - -/*****************************************************************************/ - -const char * -nm_platform_signal_change_type_to_string(NMPlatformSignalChangeType change_type) -{ - switch (change_type) { - case NM_PLATFORM_SIGNAL_ADDED: - return "added"; - case NM_PLATFORM_SIGNAL_CHANGED: - return "changed"; - case NM_PLATFORM_SIGNAL_REMOVED: - return "removed"; - default: - g_return_val_if_reached("UNKNOWN"); - } -} - -static void -log_link(NMPlatform * self, - NMPObjectType obj_type, - int ifindex, - NMPlatformLink * device, - NMPlatformSignalChangeType change_type, - gpointer user_data) -{ - _LOG3D("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) -{ - _LOG3D("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) -{ - _LOG3D("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) -{ - _LOG3D("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) -{ - _LOG3D("signal: route 6 %7s: %s", - nm_platform_signal_change_type_to_string(change_type), - nm_platform_ip6_route_to_string(route, NULL, 0)); -} - -static void -log_routing_rule(NMPlatform * self, - NMPObjectType obj_type, - int ifindex, - NMPlatformRoutingRule * routing_rule, - NMPlatformSignalChangeType change_type, - gpointer user_data) -{ - /* routing rules don't have an ifindex. We probably should refactor the signals that are emitted for platform changes. */ - _LOG3D("signal: rt-rule %7s: %s", - nm_platform_signal_change_type_to_string(change_type), - nm_platform_routing_rule_to_string(routing_rule, NULL, 0)); -} - -static void -log_qdisc(NMPlatform * self, - NMPObjectType obj_type, - int ifindex, - NMPlatformQdisc * qdisc, - NMPlatformSignalChangeType change_type, - gpointer user_data) -{ - _LOG3D("signal: qdisc %7s: %s", - nm_platform_signal_change_type_to_string(change_type), - nm_platform_qdisc_to_string(qdisc, NULL, 0)); -} - -static void -log_tfilter(NMPlatform * self, - NMPObjectType obj_type, - int ifindex, - NMPlatformTfilter * tfilter, - NMPlatformSignalChangeType change_type, - gpointer user_data) -{ - _LOG3D("signal: tfilter %7s: %s", - nm_platform_signal_change_type_to_string(change_type), - nm_platform_tfilter_to_string(tfilter, NULL, 0)); -} - -/*****************************************************************************/ - -void -nm_platform_cache_update_emit_signal(NMPlatform * self, - NMPCacheOpsType cache_op, - const NMPObject *obj_old, - const NMPObject *obj_new) -{ - gboolean visible_new; - gboolean visible_old; - const NMPObject *o; - const NMPClass * klass; - int ifindex; - - nm_assert(NM_IN_SET((NMPlatformSignalChangeType) cache_op, - NM_PLATFORM_SIGNAL_NONE, - NM_PLATFORM_SIGNAL_ADDED, - NM_PLATFORM_SIGNAL_CHANGED, - NM_PLATFORM_SIGNAL_REMOVED)); - - ASSERT_nmp_cache_ops(nm_platform_get_cache(self), cache_op, obj_old, obj_new); - - NMTST_ASSERT_PLATFORM_NETNS_CURRENT(self); - - switch (cache_op) { - case NMP_CACHE_OPS_ADDED: - if (!nmp_object_is_visible(obj_new)) - return; - o = obj_new; - break; - case NMP_CACHE_OPS_UPDATED: - visible_old = nmp_object_is_visible(obj_old); - visible_new = nmp_object_is_visible(obj_new); - if (!visible_old && visible_new) { - o = obj_new; - cache_op = NMP_CACHE_OPS_ADDED; - } else if (visible_old && !visible_new) { - o = obj_old; - cache_op = NMP_CACHE_OPS_REMOVED; - } else if (!visible_new) { - /* it was invisible and stayed invisible. Nothing to do. */ - return; - } else - o = obj_new; - break; - case NMP_CACHE_OPS_REMOVED: - if (!nmp_object_is_visible(obj_old)) - return; - o = obj_old; - break; - default: - nm_assert(cache_op == NMP_CACHE_OPS_UNCHANGED); - return; - } - - klass = NMP_OBJECT_GET_CLASS(o); - - if (klass->obj_type == NMP_OBJECT_TYPE_ROUTING_RULE) - ifindex = 0; - else - ifindex = NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(o)->ifindex; - - if (klass->obj_type == NMP_OBJECT_TYPE_IP4_ROUTE - && NM_PLATFORM_GET_PRIVATE(self)->ip4_dev_route_blacklist_gc_timeout_id - && NM_IN_SET(cache_op, NMP_CACHE_OPS_ADDED, NMP_CACHE_OPS_UPDATED)) - _ip4_dev_route_blacklist_notify_route(self, o); - - _LOG3t("emit signal %s %s: %s", - klass->signal_type, - nm_platform_signal_change_type_to_string((NMPlatformSignalChangeType) cache_op), - nmp_object_to_string(o, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - - nmp_object_ref(o); - g_signal_emit(self, - _nm_platform_signal_id_get(klass->signal_type_id), - 0, - (int) klass->obj_type, - ifindex, - &o->object, - (int) cache_op); - nmp_object_unref(o); -} - -/*****************************************************************************/ - -NMPCache * -nm_platform_get_cache(NMPlatform *self) -{ - return NM_PLATFORM_GET_PRIVATE(self)->cache; -} - -NMPNetns * -nm_platform_netns_get(NMPlatform *self) -{ - _CHECK_SELF(self, klass, NULL); - - return self->_netns; -} - -gboolean -nm_platform_netns_push(NMPlatform *self, NMPNetns **netns) -{ - g_return_val_if_fail(NM_IS_PLATFORM(self), FALSE); - - if (self->_netns && !nmp_netns_push(self->_netns)) { - NM_SET_OUT(netns, NULL); - return FALSE; - } - - NM_SET_OUT(netns, self->_netns); - return TRUE; -} - -/*****************************************************************************/ - -const _NMPlatformVTableRouteUnion nm_platform_vtable_route = { - .v4 = - { - .is_ip4 = TRUE, - .obj_type = NMP_OBJECT_TYPE_IP4_ROUTE, - .addr_family = AF_INET, - .sizeof_route = sizeof(NMPlatformIP4Route), - .route_cmp = (int (*)(const NMPlatformIPXRoute *a, - const NMPlatformIPXRoute *b, - NMPlatformIPRouteCmpType cmp_type)) nm_platform_ip4_route_cmp, - .route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, - char * buf, - gsize len)) nm_platform_ip4_route_to_string, - }, - .v6 = - { - .is_ip4 = FALSE, - .obj_type = NMP_OBJECT_TYPE_IP6_ROUTE, - .addr_family = AF_INET6, - .sizeof_route = sizeof(NMPlatformIP6Route), - .route_cmp = (int (*)(const NMPlatformIPXRoute *a, - const NMPlatformIPXRoute *b, - NMPlatformIPRouteCmpType cmp_type)) nm_platform_ip6_route_cmp, - .route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, - char * buf, - gsize len)) nm_platform_ip6_route_to_string, - }, -}; - -/*****************************************************************************/ - -static void -set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - NMPlatform * self = NM_PLATFORM(object); - NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self); - - switch (prop_id) { - case PROP_NETNS_SUPPORT: - /* construct-only */ - if (g_value_get_boolean(value)) { - NMPNetns *netns; - - netns = nmp_netns_get_current(); - if (netns) - self->_netns = g_object_ref(netns); - } - break; - case PROP_USE_UDEV: - /* construct-only */ - priv->use_udev = g_value_get_boolean(value); - break; - case PROP_LOG_WITH_PTR: - /* construct-only */ - priv->log_with_ptr = g_value_get_boolean(value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -nm_platform_init(NMPlatform *self) -{ - self->_priv = G_TYPE_INSTANCE_GET_PRIVATE(self, NM_TYPE_PLATFORM, NMPlatformPrivate); -} - -static GObject * -constructor(GType type, guint n_construct_params, GObjectConstructParam *construct_params) -{ - GObject * object; - NMPlatform * self; - NMPlatformPrivate *priv; - - object = G_OBJECT_CLASS(nm_platform_parent_class) - ->constructor(type, n_construct_params, construct_params); - self = NM_PLATFORM(object); - priv = NM_PLATFORM_GET_PRIVATE(self); - - priv->multi_idx = nm_dedup_multi_index_new(); - - priv->cache = nmp_cache_new(priv->multi_idx, priv->use_udev); - - return object; -} - -static void -finalize(GObject *object) -{ - NMPlatform * self = NM_PLATFORM(object); - NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self); - - nm_clear_g_source(&priv->ip4_dev_route_blacklist_check_id); - nm_clear_g_source(&priv->ip4_dev_route_blacklist_gc_timeout_id); - nm_clear_pointer(&priv->ip4_dev_route_blacklist_hash, g_hash_table_unref); - g_clear_object(&self->_netns); - nm_dedup_multi_index_unref(priv->multi_idx); - nmp_cache_free(priv->cache); -} - -static void -nm_platform_class_init(NMPlatformClass *platform_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS(platform_class); - - g_type_class_add_private(object_class, sizeof(NMPlatformPrivate)); - - object_class->constructor = constructor; - object_class->set_property = set_property; - object_class->finalize = finalize; - - platform_class->wifi_set_powersave = wifi_set_powersave; - - g_object_class_install_property( - object_class, - PROP_NETNS_SUPPORT, - g_param_spec_boolean(NM_PLATFORM_NETNS_SUPPORT, - "", - "", - NM_PLATFORM_NETNS_SUPPORT_DEFAULT, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property( - object_class, - PROP_USE_UDEV, - g_param_spec_boolean(NM_PLATFORM_USE_UDEV, - "", - "", - FALSE, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property( - object_class, - PROP_LOG_WITH_PTR, - g_param_spec_boolean(NM_PLATFORM_LOG_WITH_PTR, - "", - "", - TRUE, - G_PARAM_WRITABLE | 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, \ - G_TYPE_INT, /* (int) NMPObjectType */ \ - G_TYPE_INT, /* ifindex */ \ - G_TYPE_POINTER /* const NMPObject * */, \ - G_TYPE_INT /* (int) NMPlatformSignalChangeType */ \ - ); \ - } \ - G_STMT_END - - /* Signals */ - 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); - SIGNAL(NM_PLATFORM_SIGNAL_ID_ROUTING_RULE, - NM_PLATFORM_SIGNAL_ROUTING_RULE_CHANGED, - log_routing_rule); - SIGNAL(NM_PLATFORM_SIGNAL_ID_QDISC, NM_PLATFORM_SIGNAL_QDISC_CHANGED, log_qdisc); - SIGNAL(NM_PLATFORM_SIGNAL_ID_TFILTER, NM_PLATFORM_SIGNAL_TFILTER_CHANGED, log_tfilter); -} diff --git a/src/core/platform/nm-platform.h b/src/core/platform/nm-platform.h deleted file mode 100644 index d400c568..00000000 --- a/src/core/platform/nm-platform.h +++ /dev/null @@ -1,2372 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2009 - 2018 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_PLATFORM_H__ -#define __NETWORKMANAGER_PLATFORM_H__ - -#include "nm-dbus-interface.h" -#include "nm-core-types-internal.h" - -#include "nm-platform/nmp-base.h" -#include "nm-base/nm-base.h" - -#include "nm-core-utils.h" -#include "nm-setting-vlan.h" -#include "nm-setting-wired.h" -#include "nm-setting-wireless.h" -#include "nm-setting-ip-tunnel.h" - -#define NM_TYPE_PLATFORM (nm_platform_get_type()) -#define NM_PLATFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_PLATFORM, NMPlatform)) -#define NM_PLATFORM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_PLATFORM, NMPlatformClass)) -#define NM_IS_PLATFORM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_PLATFORM)) -#define NM_IS_PLATFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_PLATFORM)) -#define NM_PLATFORM_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_PLATFORM, NMPlatformClass)) - -#define NM_PLATFORM_NETNS_SUPPORT_DEFAULT FALSE - -/*****************************************************************************/ - -#define NM_PLATFORM_NETNS_SUPPORT "netns-support" -#define NM_PLATFORM_USE_UDEV "use-udev" -#define NM_PLATFORM_LOG_WITH_PTR "log-with-ptr" - -/*****************************************************************************/ - -/* IFNAMSIZ is both defined in and . In the past, these - * headers conflicted, so we cannot simply include either of them in a header-file.*/ -#define NMP_IFNAMSIZ 16 - -/*****************************************************************************/ - -struct _NMPWireGuardPeer; - -struct udev_device; - -typedef gboolean (*NMPObjectPredicateFunc)(const NMPObject *obj, gpointer user_data); - -/* workaround for older libnl version, that does not define these flags. */ -#ifndef IFA_F_MANAGETEMPADDR - #define IFA_F_MANAGETEMPADDR 0x100 -#endif -#ifndef IFA_F_NOPREFIXROUTE - #define IFA_F_NOPREFIXROUTE 0x200 -#endif - -#define NM_RT_SCOPE_LINK 253 /* RT_SCOPE_LINK */ - -/* 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_IN6_ADDR_GEN_MODE_RANDOM 3 /* IN6_ADDR_GEN_MODE_RANDOM */ - -#define NM_IFF_MULTI_QUEUE 0x0100 /* IFF_MULTI_QUEUE */ - -/* Redefine this in host's endianness */ -#define NM_GRE_KEY 0x2000 - -typedef enum { - NMP_NLM_FLAG_F_ECHO = 0x08, /* NLM_F_ECHO, Echo this request */ - - /* use our own platform enum for the nlmsg-flags. Otherwise, we'd have - * to include */ - NMP_NLM_FLAG_F_REPLACE = 0x100, /* NLM_F_REPLACE, Override existing */ - NMP_NLM_FLAG_F_EXCL = 0x200, /* NLM_F_EXCL, Do not touch, if it exists */ - NMP_NLM_FLAG_F_CREATE = 0x400, /* NLM_F_CREATE, Create, if it does not exist */ - NMP_NLM_FLAG_F_APPEND = 0x800, /* NLM_F_APPEND, Add to end of list */ - - NMP_NLM_FLAG_FMASK = 0xFFFF, /* a mask for all NMP_NLM_FLAG_F_* flags */ - - /* instructs NM to suppress logging an error message for any failures - * received from kernel. - * - * It will still log with debug-level, and it will still log - * other failures aside the kernel response. */ - NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE = 0x10000, - - /* the following aliases correspond to iproute2's `ip route CMD` for - * RTM_NEWROUTE, with CMD being one of add, change, replace, prepend, - * append and test. */ - NMP_NLM_FLAG_ADD = NMP_NLM_FLAG_F_CREATE | NMP_NLM_FLAG_F_EXCL, - NMP_NLM_FLAG_CHANGE = NMP_NLM_FLAG_F_REPLACE, - NMP_NLM_FLAG_REPLACE = NMP_NLM_FLAG_F_CREATE | NMP_NLM_FLAG_F_REPLACE, - NMP_NLM_FLAG_PREPEND = NMP_NLM_FLAG_F_CREATE, - NMP_NLM_FLAG_APPEND = NMP_NLM_FLAG_F_CREATE | NMP_NLM_FLAG_F_APPEND, - NMP_NLM_FLAG_TEST = NMP_NLM_FLAG_F_EXCL, -} NMPNlmFlags; - -typedef enum { - /* compare fields which kernel considers as similar routes. - * It is a looser comparisong then NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID - * and means that `ip route add` would fail to add two routes - * that have the same NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID. - * On the other hand, `ip route append` would allow that, as - * long as NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID differs. */ - NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID, - - /* compare two routes as kernel would allow to add them with - * `ip route append`. In other words, kernel does not allow you to - * add two routes (at the same time) which compare equal according - * to NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID. - * - * For the ID we can only recognize route fields that we actually implement. - * However, kernel supports more routing options, some of them also part of - * the ID. NetworkManager is oblivious to these options and will wrongly think - * that two routes are identical, while they are not. That can lead to an - * inconsistent platform cache. Not much what we can do about that, except - * implementing all options that kernel supports *sigh*. See rh#1337860. - */ - NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID, - - /* compare all fields as they make sense for kernel. For example, - * a route destination 192.168.1.5/24 is not accepted by kernel and - * we treat it identical to 192.168.1.0/24. Semantically these - * routes are identical, but NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL will - * report them as different. - * - * The result shall be identical to call first nm_platform_ip_route_normalize() - * on both routes and then doing a full comparison. */ - NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY, - - /* compare all fields. This should have the same effect as memcmp(), - * except allowing for undefined data in holes between field alignment. - */ - NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL, - -} NMPlatformIPRouteCmpType; - -typedef enum { - NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID, - - NM_PLATFORM_ROUTING_RULE_CMP_TYPE_SEMANTICALLY, - - NM_PLATFORM_ROUTING_RULE_CMP_TYPE_FULL, -} NMPlatformRoutingRuleCmpType; - -typedef struct { - union { - guint8 data[20 /* NM_UTILS_HWADDR_LEN_MAX */]; - NMEtherAddr ether_addr; - }; - guint8 len; -} NMPLinkAddress; - -/* assert that NMEtherAddr does not affect the alignment of NMPLinkAddress struct. */ -G_STATIC_ASSERT(_nm_alignof(NMEtherAddr) == 1); -G_STATIC_ASSERT(_nm_alignof(NMPLinkAddress) == 1); - -gconstpointer nmp_link_address_get(const NMPLinkAddress *addr, size_t *length); -GBytes * nmp_link_address_get_as_bytes(const NMPLinkAddress *addr); - -typedef enum { - - /* match-flags are strictly inclusive. That means, - * by default nothing is matched, but if you enable a particular - * flag, a candidate that matches passes the check. - * - * In other words: adding more flags can only extend the result - * set of matching objects. - * - * Also, the flags form partitions. Like, an address can be either of - * ADDRTYPE_NORMAL or ADDRTYPE_LINKLOCAL, but never both. Same for - * the ADDRSTATE match types. - */ - NM_PLATFORM_MATCH_WITH_NONE = 0, - - NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL = (1LL << 0), - NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL = (1LL << 1), - NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY = - NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL | NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL, - - NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL = (1LL << 2), - NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE = (1LL << 3), - NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED = (1LL << 4), - NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY = NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED, -} NMPlatformMatchFlags; - -#define NM_PLATFORM_LINK_OTHER_NETNS (-1) - -struct _NMPlatformObject { - /* the object type has no fields of its own, it is only used to having - * a special pointer type that can be used to indicate "any" type. */ - char _dummy_don_t_use_me; -}; - -#define __NMPlatformObjWithIfindex_COMMON \ - int ifindex; \ - ; - -struct _NMPlatformObjWithIfindex { - __NMPlatformObjWithIfindex_COMMON; -}; - -struct _NMPlatformLink { - __NMPlatformObjWithIfindex_COMMON; - char name[NMP_IFNAMSIZ]; - NMLinkType type; - - /* rtnl_link_get_type(), IFLA_INFO_KIND. */ - /* NMPlatform initializes this field with a static string. */ - const char *kind; - - /* NMPlatform initializes this field with a static string. */ - const char *driver; - - int master; - - /* rtnl_link_get_link(), IFLA_LINK. - * If IFLA_LINK_NETNSID indicates that the parent is in another namespace, - * this field be set to (negative) NM_PLATFORM_LINK_OTHER_NETNS. */ - int parent; - - /* IFF_* flags. Note that the flags in 'struct ifinfomsg' are declared as 'unsigned'. */ - guint n_ifi_flags; - - guint mtu; - - /* rtnl_link_get_arptype(), ifinfomsg.ifi_type. */ - guint32 arptype; - - /* IFLA_ADDRESS */ - NMPLinkAddress l_address; - - /* IFLA_BROADCAST */ - NMPLinkAddress l_broadcast; - - /* rtnl_link_inet6_get_token(), IFLA_INET6_TOKEN */ - NMUtilsIPv6IfaceId inet6_token; - - /* The bitwise inverse of rtnl_link_inet6_get_addr_gen_mode(). It is inverse - * to have a default of 0 -- meaning: unspecified. That way, a struct - * initialized with memset(0) has and unset value.*/ - guint8 inet6_addr_gen_mode_inv; - - /* Statistics */ - guint64 rx_packets; - guint64 rx_bytes; - guint64 tx_packets; - guint64 tx_bytes; - - /* @connected is mostly identical to (@n_ifi_flags & IFF_UP). Except for bridge/bond masters, - * where we coerce the link as disconnect if it has no slaves. */ - bool connected : 1; - - bool initialized : 1; -}; - -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_ROUTING_RULE, - NM_PLATFORM_SIGNAL_ID_QDISC, - NM_PLATFORM_SIGNAL_ID_TFILTER, - _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, - NM_PLATFORM_SIGNAL_CHANGED, - NM_PLATFORM_SIGNAL_REMOVED, -} NMPlatformSignalChangeType; - -#define NM_PLATFORM_IP_ADDRESS_CAST(address) \ - NM_CONSTCAST(NMPlatformIPAddress, \ - (address), \ - NMPlatformIPXAddress, \ - NMPlatformIP4Address, \ - NMPlatformIP6Address) - -#define __NMPlatformIPAddress_COMMON \ - __NMPlatformObjWithIfindex_COMMON; \ - NMIPConfigSource addr_source; \ - \ - /* Timestamp in seconds in the reference system of nm_utils_get_monotonic_timestamp_*(). - * - * The rules are: - * 1 @lifetime==0: @timestamp and @preferred is irrelevant (but mostly set to 0 too). Such addresses - * are permanent. This rule is so that unset addresses (calloc) are permanent by default. - * 2 @lifetime==@preferred==NM_PLATFORM_LIFETIME_PERMANENT: @timestamp is irrelevant (but mostly - * set to 0). Such addresses are permanent. - * 3 Non permanent addresses should (almost) always have @timestamp > 0. 0 is not a valid timestamp - * and never returned by nm_utils_get_monotonic_timestamp_sec(). In this case @valid/@preferred - * is anchored at @timestamp. - * 4 Non permanent addresses with @timestamp == 0 are implicitly anchored at *now*, thus the time - * moves as time goes by. This is usually not useful, except e.g. nm_platform_ip[46]_address_add(). - * - * Non permanent addresses from DHCP/RA might have the @timestamp set to the moment of when the - * lease was received. Addresses from kernel might have the @timestamp based on the last modification - * time of the addresses. But don't rely on this behaviour, the @timestamp is only defined for anchoring - * @lifetime and @preferred. - */ \ - guint32 timestamp; \ - guint32 lifetime; /* seconds since timestamp */ \ - guint32 preferred; /* seconds since timestamp */ \ - \ - /* ifa_flags in 'struct ifaddrmsg' from , extended to 32 bit by - * IFA_FLAGS attribute. */ \ - guint32 n_ifa_flags; \ - \ - guint8 plen; \ - \ - /* FIXME(l3cfg): the external marker won't be necessary anymore, because we only - * merge addresses we care about, and ignore (don't remove) external addresses. */ \ - bool external : 1; \ - \ - bool use_ip4_broadcast_address : 1; \ - \ - /* Whether the address is ready to be configured. By default, an address is, but this - * flag may indicate that the address is just for tracking purpose only, but the ACD - * state is not yet ready for the address to be configured. */ \ - bool ip4acd_not_ready : 1; \ - ; - -/** - * NMPlatformIPAddress: - * - * Common parts of NMPlatformIP4Address and NMPlatformIP6Address. - **/ -typedef struct { - __NMPlatformIPAddress_COMMON; - union { - guint8 address_ptr[1]; - guint32 __dummy_for_32bit_alignment; - }; -} NMPlatformIPAddress; - -/** - * NMPlatformIP4Address: - * @timestamp: timestamp as returned by nm_utils_get_monotonic_timestamp_sec() - **/ -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. However, 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 */ - - /* IFA_BROADCAST. - * - * This parameter is ignored unless use_ip4_broadcast_address is TRUE. - * See nm_platform_ip4_broadcast_address_from_addr(). */ - in_addr_t broadcast_address; - - char label[NMP_IFNAMSIZ]; -}; - -/** - * NMPlatformIP6Address: - * @timestamp: timestamp as returned by nm_utils_get_monotonic_timestamp_sec() - **/ -struct _NMPlatformIP6Address { - __NMPlatformIPAddress_COMMON; - struct in6_addr address; - struct in6_addr peer_address; -}; - -typedef union { - NMPlatformIPAddress ax; - NMPlatformIP4Address a4; - NMPlatformIP6Address a6; -} NMPlatformIPXAddress; - -#undef __NMPlatformIPAddress_COMMON - -#define NM_PLATFORM_IP4_ADDRESS_INIT(...) (&((const NMPlatformIP4Address){__VA_ARGS__})) - -#define NM_PLATFORM_IP6_ADDRESS_INIT(...) (&((const NMPlatformIP6Address){__VA_ARGS__})) - -/* Default value for adding an IPv4 route. This is also what iproute2 does. - * Note that contrary to IPv6, you can add routes with metric 0 and it is even - * the default. - */ -#define NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4 ((guint32) 0u) - -/* Default value for adding an IPv6 route. This is also what iproute2 does. - * Adding an IPv6 route with metric 0, kernel translates to IP6_RT_PRIO_USER (1024). - * - * Note that kernel doesn't allow adding IPv6 routes with metric zero via netlink. - * It however can itself add routes with metric zero. */ -#define NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6 ((guint32) 1024u) - -/* For IPv4, kernel adds a device route (subnet routes) with metric 0 when user - * configures addresses. */ -#define NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE ((guint32) 0u) - -#define __NMPlatformIPRoute_COMMON \ - __NMPlatformObjWithIfindex_COMMON; \ - \ - /* The NMIPConfigSource. For routes that we receive from cache this corresponds - * to the rtm_protocol field (and is one of the NM_IP_CONFIG_SOURCE_RTPROT_* values). - * When adding a route, the source will be coerced to the protocol using - * nmp_utils_ip_config_source_coerce_to_rtprot(). - * - * rtm_protocol is part of the primary key of an IPv4 route (meaning, you can add - * two IPv4 routes that only differ in their rtm_protocol. For IPv6, that is not - * the case. - * - * When deleting an IPv4/IPv6 route, the rtm_protocol field must match (even - * if it is not part of the primary key for IPv6) -- unless rtm_protocol is set - * to zero, in which case the first matching route (with proto ignored) is deleted. */ \ - NMIPConfigSource rt_source; \ - \ - guint8 plen; \ - \ - /* RTA_METRICS: - * - * For IPv4 routes, these properties are part of their - * ID (meaning: you can add otherwise identical IPv4 routes that - * only differ by the metric property). - * On the other hand, for IPv6 you cannot add two IPv6 routes that only differ - * by an RTA_METRICS property. - * - * When deleting a route, kernel seems to ignore the RTA_METRICS properties. - * That is a problem/bug for IPv4 because you cannot explicitly select which - * route to delete. Kernel just picks the first. See rh#1475642. */ \ - \ - /* RTA_METRICS.RTAX_LOCK (iproute2: "lock" arguments) */ \ - bool lock_window : 1; \ - bool lock_cwnd : 1; \ - bool lock_initcwnd : 1; \ - bool lock_initrwnd : 1; \ - bool lock_mtu : 1; \ - \ - /* if TRUE, the "metric" field is interpreted as an offset that is added to a default - * metric. For example, form a DHCP lease we don't know the actually used metric, because - * that is determined by upper layers (the configuration). However, we have a default - * metric that should be used. So we set "metric_any" to %TRUE, which means to use - * the default metric. However, we still treat the "metric" field as an offset that - * will be added to the default metric. In most case, you want that "metric" is zero - * when setting "metric_any". */ \ - bool metric_any : 1; \ - \ - /* like "metric_any", the table is determined by other layers of the code. - * This field overrides "table_coerced" field. If "table_any" is true, then - * the "table_coerced" field is ignored (unlike for the metric). */ \ - bool table_any : 1; \ - \ - /* rtnh_flags - * - * Routes with rtm_flags RTM_F_CLONED are hidden by platform and - * do not exist from the point-of-view of platform users. - * Such a route is not alive, according to nmp_object_is_alive(). - * - * NOTE: currently we ignore all flags except RTM_F_CLONED - * and RTNH_F_ONLINK. - * We also may not properly consider the flags as part of the ID - * in route-cmp. */ \ - unsigned r_rtm_flags; \ - \ - /* RTA_METRICS.RTAX_ADVMSS (iproute2: advmss) */ \ - guint32 mss; \ - \ - /* RTA_METRICS.RTAX_WINDOW (iproute2: window) */ \ - guint32 window; \ - \ - /* RTA_METRICS.RTAX_CWND (iproute2: cwnd) */ \ - guint32 cwnd; \ - \ - /* RTA_METRICS.RTAX_INITCWND (iproute2: initcwnd) */ \ - guint32 initcwnd; \ - \ - /* RTA_METRICS.RTAX_INITRWND (iproute2: initrwnd) */ \ - guint32 initrwnd; \ - \ - /* RTA_METRICS.RTAX_MTU (iproute2: mtu) */ \ - guint32 mtu; \ - \ - /* RTA_PRIORITY (iproute2: metric) - * If "metric_any" is %TRUE, then this is interpreted as an offset that will be - * added to a default base metric. In such cases, the offset is usually zero. */ \ - guint32 metric; \ - \ - /* rtm_table, RTA_TABLE. - * - * This is not the original table ID. Instead, 254 (RT_TABLE_MAIN) and - * zero (RT_TABLE_UNSPEC) are swapped, so that the default is the main - * table. Use nm_platform_route_table_coerce()/nm_platform_route_table_uncoerce(). */ \ - guint32 table_coerced; \ - \ - /* rtm_type. - * - * This is not the original type, if type_coerced is 0 then - * it means RTN_UNSPEC otherwise the type value is preserved. - * */ \ - guint8 type_coerced; \ - \ - /*end*/ - -typedef struct { - __NMPlatformIPRoute_COMMON; - union { - guint8 network_ptr[1]; - guint32 __dummy_for_32bit_alignment; - }; -} NMPlatformIPRoute; - -#define NM_PLATFORM_IP_ROUTE_CAST(route) \ - NM_CONSTCAST(NMPlatformIPRoute, \ - (route), \ - NMPlatformIPXRoute, \ - NMPlatformIP4Route, \ - NMPlatformIP6Route) - -#define NM_PLATFORM_IP_ROUTE_IS_DEFAULT(route) (NM_PLATFORM_IP_ROUTE_CAST(route)->plen <= 0) - -struct _NMPlatformIP4Route { - __NMPlatformIPRoute_COMMON; - in_addr_t network; - - /* RTA_GATEWAY. The gateway is part of the primary key for a route */ - in_addr_t gateway; - - /* RTA_PREFSRC (called "src" by iproute2). - * - * pref_src is part of the ID of an IPv4 route. When deleting a route, - * pref_src must match, unless set to 0.0.0.0 to match any. */ - in_addr_t pref_src; - - /* rtm_tos (iproute2: tos) - * - * For IPv4, tos is part of the weak-id (like metric). - * - * For IPv6, tos is ignored by kernel. */ - guint8 tos; - - /* The bitwise inverse of the route scope rtm_scope. It is inverted so that the - * default value (RT_SCOPE_NOWHERE) is zero. Use nm_platform_route_scope_inv() - * to convert back and forth between the inverse representation and the - * real value. - * - * rtm_scope is part of the primary key for IPv4 routes. When deleting a route, - * the scope must match, unless it is left at RT_SCOPE_NOWHERE, in which case the first - * matching route is deleted. - * - * For IPv6 routes, the scope is ignored and kernel always assumes global scope. - * Hence, this field is only in NMPlatformIP4Route. */ - guint8 scope_inv; -}; - -struct _NMPlatformIP6Route { - __NMPlatformIPRoute_COMMON; - struct in6_addr network; - - /* RTA_GATEWAY. The gateway is part of the primary key for a route */ - struct in6_addr gateway; - - /* RTA_PREFSRC (called "src" by iproute2). - * - * pref_src is not part of the ID for an IPv6 route. You cannot add two - * routes that only differ by pref_src. - * - * When deleting a route, pref_src is ignored by kernel. */ - struct in6_addr pref_src; - - /* RTA_SRC and rtm_src_len (called "from" by iproute2). - * - * Kernel clears the host part of src/src_plen. - * - * src/src_plen is part of the ID of a route just like network/plen. That is, - * Not only `ip route append`, but also `ip route add` allows to add routes that only - * differ in their src/src_plen. - */ - struct in6_addr src; - guint8 src_plen; - - /* RTA_PREF router preference. - * - * The type is guint8 to keep the struct size small. But the values are compatible with - * the NMIcmpv6RouterPref enum. */ - guint8 rt_pref; -}; - -typedef union { - NMPlatformIPRoute rx; - NMPlatformIP4Route r4; - NMPlatformIP6Route r6; -} NMPlatformIPXRoute; - -#undef __NMPlatformIPRoute_COMMON - -typedef struct { - /* struct fib_rule_uid_range */ - guint32 start; - guint32 end; -} NMFibRuleUidRange; - -typedef struct { - /* struct fib_rule_port_range */ - guint16 start; - guint16 end; -} NMFibRulePortRange; - -typedef struct { - NMIPAddr src; /* FRA_SRC */ - NMIPAddr dst; /* FRA_DST */ - guint64 tun_id; /* betoh64(FRA_TUN_ID) */ - guint32 table; /* (struct fib_rule_hdr).table, FRA_TABLE */ - guint32 flags; /* (struct fib_rule_hdr).flags */ - guint32 priority; /* RA_PRIORITY */ - guint32 fwmark; /* FRA_FWMARK */ - guint32 fwmask; /* FRA_FWMASK */ - guint32 goto_target; /* FRA_GOTO */ - guint32 flow; /* FRA_FLOW */ - guint32 suppress_prefixlen_inverse; /* ~(FRA_SUPPRESS_PREFIXLEN) */ - guint32 suppress_ifgroup_inverse; /* ~(FRA_SUPPRESS_IFGROUP) */ - NMFibRuleUidRange uid_range; /* FRA_UID_RANGE */ - NMFibRulePortRange sport_range; /* FRA_SPORT_RANGE */ - NMFibRulePortRange dport_range; /* FRA_DPORT_RANGE */ - char iifname[NMP_IFNAMSIZ]; /* FRA_IIFNAME */ - char oifname[NMP_IFNAMSIZ]; /* FRA_OIFNAME */ - guint8 addr_family; /* (struct fib_rule_hdr).family */ - guint8 action; /* (struct fib_rule_hdr).action */ - guint8 tos; /* (struct fib_rule_hdr).tos */ - guint8 src_len; /* (struct fib_rule_hdr).src_len */ - guint8 dst_len; /* (struct fib_rule_hdr).dst_len */ - guint8 l3mdev; /* FRA_L3MDEV */ - guint8 protocol; /* FRA_PROTOCOL */ - guint8 ip_proto; /* FRA_IP_PROTO */ - - bool uid_range_has : 1; /* has(FRA_UID_RANGE) */ -} NMPlatformRoutingRule; - -#define NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET (~((guint32) 0)) - -#define NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED ((guint32) 0x83126E97u) - -G_STATIC_ASSERT(((((guint64) NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED) * 1000u) >> 10) - == (guint64) INT_MAX); - -typedef struct { - guint32 limit; - guint32 flows; - guint32 target; - guint32 interval; - guint32 quantum; - - /* TCA_FQ_CODEL_CE_THRESHOLD: kernel internally stores this value as - * ((val64 * NSEC_PER_USEC) >> CODEL_SHIFT). The default value (in - * the domain with this coercion) is CODEL_DISABLED_THRESHOLD (INT_MAX). - * That means, "disabled" is expressed on RTM_NEWQDISC netlink API by absence of the - * netlink attribute but also as the special value 0x83126E97u - * (NM_PLATFORM_FQ_CODEL_CE_THRESHOLD_DISABLED). - * Beware: zero is not the default you must always explicitly set this value. */ - guint32 ce_threshold; - - /* TCA_FQ_CODEL_MEMORY_LIMIT: note that only values <= 2^31 are accepted by kernel - * and kernel defaults to 32MB. - * Note that we use the special value NM_PLATFORM_FQ_CODEL_MEMORY_LIMIT_UNSET - * to indicate that no explicit limit is set (when we send a RTM_NEWQDISC request). - * This will cause kernel to choose the default (32MB). - * Beware: zero is not the default you must always explicitly set this value. */ - guint32 memory_limit; - - bool ecn : 1; -} NMPlatformQdiscFqCodel; - -typedef struct { - unsigned quantum; - int perturb_period; - guint32 limit; - unsigned divisor; - unsigned flows; - unsigned depth; -} NMPlatformQdiscSfq; - -typedef struct { - guint64 rate; - guint32 burst; - guint32 limit; - guint32 latency; -} NMPlatformQdiscTbf; - -typedef struct { - __NMPlatformObjWithIfindex_COMMON; - - /* beware, kind is embedded in an NMPObject, hence you must - * take care of the lifetime of the string. */ - const char *kind; - - int addr_family; - guint32 handle; - guint32 parent; - guint32 info; - union { - NMPlatformQdiscFqCodel fq_codel; - NMPlatformQdiscSfq sfq; - NMPlatformQdiscTbf tbf; - }; -} NMPlatformQdisc; - -typedef struct { - char sdata[32]; -} NMPlatformActionSimple; - -typedef struct { - int ifindex; - bool egress : 1; - bool ingress : 1; - bool mirror : 1; - bool redirect : 1; -} NMPlatformActionMirred; - -typedef struct { - /* beware, kind is embedded in an NMPObject, hence you must - * take care of the lifetime of the string. */ - const char *kind; - - union { - NMPlatformActionSimple simple; - NMPlatformActionMirred mirred; - }; -} NMPlatformAction; - -#define NM_PLATFORM_ACTION_KIND_SIMPLE "simple" -#define NM_PLATFORM_ACTION_KIND_MIRRED "mirred" - -typedef struct { - __NMPlatformObjWithIfindex_COMMON; - - /* beware, kind is embedded in an NMPObject, hence you must - * take care of the lifetime of the string. */ - const char *kind; - - int addr_family; - guint32 handle; - guint32 parent; - guint32 info; - NMPlatformAction action; -} NMPlatformTfilter; - -#undef __NMPlatformObjWithIfindex_COMMON - -typedef struct { - gboolean is_ip4; - NMPObjectType obj_type; - int addr_family; - gsize sizeof_route; - int (*route_cmp)(const NMPlatformIPXRoute *a, - const NMPlatformIPXRoute *b, - NMPlatformIPRouteCmpType cmp_type); - const char *(*route_to_string)(const NMPlatformIPXRoute *route, char *buf, gsize len); -} NMPlatformVTableRoute; - -typedef union { - struct { - NMPlatformVTableRoute v6; - NMPlatformVTableRoute v4; - }; - NMPlatformVTableRoute vx[2]; -} _NMPlatformVTableRouteUnion; - -extern const _NMPlatformVTableRouteUnion nm_platform_vtable_route; - -typedef struct { - guint16 id; - guint32 qos; - bool proto_ad : 1; -} NMPlatformVFVlan; - -typedef struct { - guint32 index; - guint32 min_tx_rate; - guint32 max_tx_rate; - guint num_vlans; - NMPlatformVFVlan *vlans; - struct { - guint8 data[20]; /* NM_UTILS_HWADDR_LEN_MAX */ - guint8 len; - } mac; - gint8 spoofchk; - gint8 trust; -} NMPlatformVF; - -typedef struct { - guint16 vid_start; - guint16 vid_end; - bool untagged : 1; - bool pvid : 1; -} NMPlatformBridgeVlan; - -typedef struct { - NMEtherAddr group_addr; - bool mcast_querier : 1; - bool mcast_query_use_ifaddr : 1; - bool mcast_snooping : 1; - bool stp_state : 1; - bool vlan_stats_enabled : 1; - guint16 group_fwd_mask; - guint16 priority; - guint16 vlan_protocol; - guint32 ageing_time; - guint32 forward_delay; - guint32 hello_time; - guint32 max_age; - guint32 mcast_last_member_count; - guint32 mcast_startup_query_count; - guint32 mcast_hash_max; - guint64 mcast_last_member_interval; - guint64 mcast_membership_interval; - guint64 mcast_querier_interval; - guint64 mcast_query_interval; - guint64 mcast_query_response_interval; - guint64 mcast_startup_query_interval; - guint8 mcast_router; -} NMPlatformLnkBridge; - -extern const NMPlatformLnkBridge nm_platform_lnk_bridge_default; - -typedef struct { - in_addr_t local; - in_addr_t remote; - int parent_ifindex; - guint16 input_flags; - guint16 output_flags; - guint32 input_key; - guint32 output_key; - guint8 ttl; - guint8 tos; - bool path_mtu_discovery : 1; - bool is_tap : 1; -} NMPlatformLnkGre; - -typedef struct { - int p_key; - const char *mode; -} NMPlatformLnkInfiniband; - -typedef struct { - struct in6_addr local; - struct in6_addr remote; - int parent_ifindex; - guint8 ttl; - guint8 tclass; - guint8 encap_limit; - guint8 proto; - guint flow_label; - guint32 flags; - - /* IP6GRE only */ - guint32 input_key; - guint32 output_key; - guint16 input_flags; - guint16 output_flags; - bool is_tap : 1; - bool is_gre : 1; -} NMPlatformLnkIp6Tnl; - -typedef struct { - in_addr_t local; - in_addr_t remote; - int parent_ifindex; - guint8 ttl; - guint8 tos; - bool path_mtu_discovery : 1; -} NMPlatformLnkIpIp; - -typedef struct { - int parent_ifindex; - guint64 sci; /* host byte order */ - guint64 cipher_suite; - guint32 window; - guint8 icv_length; - guint8 encoding_sa; - guint8 validation; - bool encrypt : 1; - bool protect : 1; - bool include_sci : 1; - bool es : 1; - bool scb : 1; - bool replay_protect : 1; -} NMPlatformLnkMacsec; - -typedef struct { - guint mode; - bool no_promisc : 1; - bool tap : 1; -} NMPlatformLnkMacvlan; - -typedef struct { - in_addr_t local; - in_addr_t remote; - int parent_ifindex; - guint16 flags; - guint8 ttl; - guint8 tos; - guint8 proto; - bool path_mtu_discovery : 1; -} NMPlatformLnkSit; - -typedef struct { - guint32 owner; - guint32 group; - - guint8 type; - - bool owner_valid : 1; - bool group_valid : 1; - - bool pi : 1; - bool vnet_hdr : 1; - bool multi_queue : 1; - bool persist : 1; -} NMPlatformLnkTun; - -typedef struct { - /* rtnl_link_vlan_get_id(), IFLA_VLAN_ID */ - guint16 id; - NMVlanFlags flags; -} NMPlatformLnkVlan; - -typedef struct { - guint32 table; -} NMPlatformLnkVrf; - -typedef struct { - struct in6_addr group6; - struct in6_addr local6; - in_addr_t group; - in_addr_t local; - int parent_ifindex; - guint32 id; - guint32 ageing; - guint32 limit; - guint16 dst_port; - guint16 src_port_min; - guint16 src_port_max; - guint8 tos; - guint8 ttl; - bool learning : 1; - bool proxy : 1; - bool rsc : 1; - bool l2miss : 1; - bool l3miss : 1; -} NMPlatformLnkVxlan; - -#define NMP_WIREGUARD_PUBLIC_KEY_LEN 32 -#define NMP_WIREGUARD_SYMMETRIC_KEY_LEN 32 - -typedef struct { - guint32 fwmark; - guint16 listen_port; - guint8 private_key[NMP_WIREGUARD_PUBLIC_KEY_LEN]; - guint8 public_key[NMP_WIREGUARD_PUBLIC_KEY_LEN]; -} NMPlatformLnkWireGuard; - -typedef enum { - NM_PLATFORM_WIREGUARD_CHANGE_FLAG_NONE = 0, - NM_PLATFORM_WIREGUARD_CHANGE_FLAG_REPLACE_PEERS = (1LL << 0), - NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_PRIVATE_KEY = (1LL << 1), - NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_LISTEN_PORT = (1LL << 2), - NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_FWMARK = (1LL << 3), -} NMPlatformWireGuardChangeFlags; - -typedef enum { - NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_NONE = 0, - NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REMOVE_ME = (1LL << 0), - NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY = (1LL << 1), - NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_KEEPALIVE_INTERVAL = (1LL << 2), - NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ENDPOINT = (1LL << 3), - NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ALLOWEDIPS = (1LL << 4), - NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REPLACE_ALLOWEDIPS = (1LL << 5), - - NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_DEFAULT = - NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY - | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_KEEPALIVE_INTERVAL - | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ENDPOINT - | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ALLOWEDIPS, - -} NMPlatformWireGuardChangePeerFlags; - -typedef void (*NMPlatformAsyncCallback)(GError *error, gpointer user_data); - -/*****************************************************************************/ - -typedef enum { - NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS, - NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL, - NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF, - NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_L3MDEV, - NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_UID_RANGE, - NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_PROTOCOL, - NM_PLATFORM_KERNEL_SUPPORT_TYPE_IFLA_BR_VLAN_STATS_ENABLED, - - /* this also includes FRA_SPORT_RANGE and FRA_DPORT_RANGE which - * were added at the same time. */ - NM_PLATFORM_KERNEL_SUPPORT_TYPE_FRA_IP_PROTO, - - _NM_PLATFORM_KERNEL_SUPPORT_NUM, -} NMPlatformKernelSupportType; - -extern volatile int _nm_platform_kernel_support_state[_NM_PLATFORM_KERNEL_SUPPORT_NUM]; - -int _nm_platform_kernel_support_init(NMPlatformKernelSupportType type, int value); - -static inline gboolean -_nm_platform_kernel_support_detected(NMPlatformKernelSupportType type) -{ - nm_assert(_NM_INT_NOT_NEGATIVE(type) && type < G_N_ELEMENTS(_nm_platform_kernel_support_state)); - - return G_LIKELY(g_atomic_int_get(&_nm_platform_kernel_support_state[type]) != 0); -} - -static inline NMOptionBool -nm_platform_kernel_support_get_full(NMPlatformKernelSupportType type, gboolean init_if_not_set) -{ - int v; - - nm_assert(_NM_INT_NOT_NEGATIVE(type) && type < G_N_ELEMENTS(_nm_platform_kernel_support_state)); - - v = g_atomic_int_get(&_nm_platform_kernel_support_state[type]); - if (G_UNLIKELY(v == 0)) { - if (!init_if_not_set) - return NM_OPTION_BOOL_DEFAULT; - v = _nm_platform_kernel_support_init(type, 0); - } - return (v >= 0); -} - -static inline gboolean -nm_platform_kernel_support_get(NMPlatformKernelSupportType type) -{ - return nm_platform_kernel_support_get_full(type, TRUE) != NM_OPTION_BOOL_FALSE; -} - -/*****************************************************************************/ - -struct _NMPlatformPrivate; - -struct _NMPlatform { - GObject parent; - NMPNetns * _netns; - struct _NMPlatformPrivate *_priv; -}; - -typedef struct { - GObjectClass parent; - - gboolean (*sysctl_set)(NMPlatform *self, - const char *pathid, - int dirfd, - const char *path, - const char *value); - void (*sysctl_set_async)(NMPlatform * self, - const char * pathid, - int dirfd, - const char * path, - const char *const * values, - NMPlatformAsyncCallback callback, - gpointer data, - GCancellable * cancellable); - char *(*sysctl_get)(NMPlatform *self, const char *pathid, int dirfd, const char *path); - - void (*refresh_all)(NMPlatform *self, NMPObjectType obj_type); - void (*process_events)(NMPlatform *self); - - int (*link_add)(NMPlatform * self, - NMLinkType type, - const char * name, - int parent, - const void * address, - size_t address_len, - guint32 mtu, - gconstpointer extra_data, - const NMPlatformLink **out_link); - gboolean (*link_delete)(NMPlatform *self, int ifindex); - gboolean (*link_refresh)(NMPlatform *self, int ifindex); - gboolean (*link_set_netns)(NMPlatform *self, int ifindex, int netns_fd); - gboolean (*link_set_up)(NMPlatform *self, int ifindex, gboolean *out_no_firmware); - gboolean (*link_set_down)(NMPlatform *self, int ifindex); - gboolean (*link_set_arp)(NMPlatform *self, int ifindex); - gboolean (*link_set_noarp)(NMPlatform *self, int ifindex); - - int (*link_set_user_ipv6ll_enabled)(NMPlatform *self, int ifindex, gboolean enabled); - gboolean (*link_set_token)(NMPlatform *self, int ifindex, NMUtilsIPv6IfaceId iid); - - gboolean (*link_get_permanent_address)(NMPlatform *self, - int ifindex, - guint8 * buf, - size_t * length); - int (*link_set_address)(NMPlatform *self, int ifindex, gconstpointer address, size_t length); - int (*link_set_mtu)(NMPlatform *self, int ifindex, guint32 mtu); - gboolean (*link_set_name)(NMPlatform *self, int ifindex, const char *name); - void (*link_set_sriov_params_async)(NMPlatform * self, - int ifindex, - guint num_vfs, - NMOptionBool autoprobe, - NMPlatformAsyncCallback callback, - gpointer callback_data, - GCancellable * cancellable); - gboolean (*link_set_sriov_vfs)(NMPlatform *self, int ifindex, const NMPlatformVF *const *vfs); - gboolean (*link_set_bridge_vlans)(NMPlatform * self, - int ifindex, - gboolean on_master, - const NMPlatformBridgeVlan *const *vlans); - - char *(*link_get_physical_port_id)(NMPlatform *self, int ifindex); - guint (*link_get_dev_id)(NMPlatform *self, int ifindex); - gboolean (*link_get_wake_on_lan)(NMPlatform *self, int ifindex); - gboolean (*link_get_driver_info)(NMPlatform *self, - int ifindex, - char ** out_driver_name, - char ** out_driver_version, - char ** out_fw_version); - - gboolean (*link_supports_carrier_detect)(NMPlatform *self, int ifindex); - gboolean (*link_supports_vlans)(NMPlatform *self, int ifindex); - gboolean (*link_supports_sriov)(NMPlatform *self, int ifindex); - - gboolean (*link_enslave)(NMPlatform *self, int master, int slave); - gboolean (*link_release)(NMPlatform *self, int master, int slave); - - gboolean (*link_can_assume)(NMPlatform *self, int ifindex); - - int (*link_wireguard_change)(NMPlatform * self, - int ifindex, - const NMPlatformLnkWireGuard * lnk_wireguard, - const struct _NMPWireGuardPeer * peers, - const NMPlatformWireGuardChangePeerFlags *peer_flags, - guint peers_len, - NMPlatformWireGuardChangeFlags change_flags); - - 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_tun_add)(NMPlatform * self, - const char * name, - const NMPlatformLnkTun *props, - const NMPlatformLink ** out_link, - int * out_fd); - - gboolean (*infiniband_partition_add)(NMPlatform * self, - int parent, - int p_key, - const NMPlatformLink **out_link); - gboolean (*infiniband_partition_delete)(NMPlatform *self, int parent, int p_key); - - gboolean (*wifi_get_capabilities)(NMPlatform * self, - int ifindex, - NMDeviceWifiCapabilities *caps); - gboolean (*wifi_get_station)(NMPlatform * self, - int ifindex, - NMEtherAddr *out_bssid, - int * out_quality, - guint32 * out_rate); - gboolean (*wifi_get_bssid)(NMPlatform *self, int ifindex, guint8 *bssid); - guint32 (*wifi_get_frequency)(NMPlatform *self, int ifindex); - int (*wifi_get_quality)(NMPlatform *self, int ifindex); - guint32 (*wifi_get_rate)(NMPlatform *self, int ifindex); - NM80211Mode (*wifi_get_mode)(NMPlatform *self, int ifindex); - void (*wifi_set_mode)(NMPlatform *self, int ifindex, NM80211Mode mode); - void (*wifi_set_powersave)(NMPlatform *self, int ifindex, guint32 powersave); - guint32 (*wifi_find_frequency)(NMPlatform *self, int ifindex, const guint32 *freqs); - void (*wifi_indicate_addressing_running)(NMPlatform *self, int ifindex, gboolean running); - NMSettingWirelessWakeOnWLan (*wifi_get_wake_on_wlan)(NMPlatform *self, int ifindex); - gboolean (*wifi_set_wake_on_wlan)(NMPlatform * self, - int ifindex, - NMSettingWirelessWakeOnWLan wowl); - - guint32 (*mesh_get_channel)(NMPlatform *self, int ifindex); - gboolean (*mesh_set_channel)(NMPlatform *self, int ifindex, guint32 channel); - gboolean (*mesh_set_ssid)(NMPlatform *self, int ifindex, const guint8 *ssid, gsize len); - - guint16 (*wpan_get_pan_id)(NMPlatform *self, int ifindex); - gboolean (*wpan_set_pan_id)(NMPlatform *self, int ifindex, guint16 pan_id); - guint16 (*wpan_get_short_addr)(NMPlatform *self, int ifindex); - gboolean (*wpan_set_short_addr)(NMPlatform *self, int ifindex, guint16 short_addr); - gboolean (*wpan_set_channel)(NMPlatform *self, int ifindex, guint8 page, guint8 channel); - - gboolean (*object_delete)(NMPlatform *self, const NMPObject *obj); - - gboolean (*ip4_address_add)(NMPlatform *self, - int ifindex, - in_addr_t address, - guint8 plen, - in_addr_t peer_address, - in_addr_t broadcast_address, - guint32 lifetime, - guint32 preferred_lft, - guint32 flags, - const char *label); - gboolean (*ip6_address_add)(NMPlatform * self, - int ifindex, - struct in6_addr address, - guint8 plen, - struct in6_addr peer_address, - guint32 lifetime, - guint32 preferred_lft, - guint32 flags); - gboolean (*ip4_address_delete)(NMPlatform *self, - int ifindex, - in_addr_t address, - guint8 plen, - in_addr_t peer_address); - gboolean (*ip6_address_delete)(NMPlatform * self, - int ifindex, - struct in6_addr address, - guint8 plen); - - int (*ip_route_add)(NMPlatform * self, - NMPNlmFlags flags, - int addr_family, - const NMPlatformIPRoute *route); - int (*ip_route_get)(NMPlatform * self, - int addr_family, - gconstpointer address, - int oif_ifindex, - NMPObject ** out_route); - - int (*routing_rule_add)(NMPlatform * self, - NMPNlmFlags flags, - const NMPlatformRoutingRule *routing_rule); - - int (*qdisc_add)(NMPlatform *self, NMPNlmFlags flags, const NMPlatformQdisc *qdisc); - - int (*tfilter_add)(NMPlatform *self, NMPNlmFlags flags, const NMPlatformTfilter *tfilter); -} NMPlatformClass; - -/* NMPlatform signals - * - * Each signal handler is called with a type-specific object that provides - * key attributes that constitute identity of the object. They may also - * provide additional attributes for convenience. - * - * The object only intended to be used by the signal handler to determine - * the current values. It is no longer valid after the signal handler exits - * but you are free to copy the provided information and use it for later - * reference. - */ -#define NM_PLATFORM_SIGNAL_LINK_CHANGED "link-changed" -#define NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED "ip4-address-changed" -#define NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED "ip6-address-changed" -#define NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED "ip4-route-changed" -#define NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED "ip6-route-changed" -#define NM_PLATFORM_SIGNAL_ROUTING_RULE_CHANGED "routing-rule-changed" -#define NM_PLATFORM_SIGNAL_QDISC_CHANGED "qdisc-changed" -#define NM_PLATFORM_SIGNAL_TFILTER_CHANGED "tfilter-changed" - -const char *nm_platform_signal_change_type_to_string(NMPlatformSignalChangeType change_type); - -/*****************************************************************************/ - -GType nm_platform_get_type(void); - -void nm_platform_setup(NMPlatform *instance); -NMPlatform *nm_platform_get(void); - -#define NM_PLATFORM_GET (nm_platform_get()) - -/*****************************************************************************/ - -static inline in_addr_t -nm_platform_ip4_broadcast_address_create(in_addr_t address, guint8 plen) -{ - return address | ~_nm_utils_ip4_prefix_to_netmask(plen); -} - -static inline in_addr_t -nm_platform_ip4_broadcast_address_from_addr(const NMPlatformIP4Address *addr) -{ - nm_assert(addr); - - if (addr->use_ip4_broadcast_address) - return addr->broadcast_address; - - /* the set broadcast-address gets ignored, and we determine a default brd base - * on the peer IFA_ADDRESS. */ - if (addr->peer_address != 0u && addr->plen < 31 /* RFC3021 */) - return nm_platform_ip4_broadcast_address_create(addr->peer_address, addr->plen); - return 0u; -} - -/*****************************************************************************/ - -/** - * nm_platform_route_table_coerce: - * @table: the route table, in its original value as received - * from rtm_table/RTA_TABLE. - * - * Returns: returns the coerced table id, that can be stored in - * NMPlatformIPRoute.table_coerced. - */ -static inline guint32 -nm_platform_route_table_coerce(guint32 table) -{ - /* For kernel, the default table is RT_TABLE_MAIN (254). - * We want that in NMPlatformIPRoute.table_coerced a numeric - * zero is the default. Hence, @table_coerced swaps the - * value 0 and 254. Use nm_platform_route_table_coerce() - * and nm_platform_route_table_uncoerce() to convert between - * the two domains. */ - switch (table) { - case 0 /* RT_TABLE_UNSPEC */: - return 254; - case 254 /* RT_TABLE_MAIN */: - return 0; - default: - return table; - } -} - -/** - * nm_platform_route_table_uncoerce: - * @table_coerced: the route table, in its coerced value - * @normalize: whether to normalize RT_TABLE_UNSPEC to - * RT_TABLE_MAIN. For kernel, routes with a table id - * RT_TABLE_UNSPEC do not exist and are treated like - * RT_TABLE_MAIN. - * - * Returns: reverts the coerced table ID in NMPlatformIPRoute.table_coerced - * to the original value as kernel understands it. - */ -static inline guint32 -nm_platform_route_table_uncoerce(guint32 table_coerced, gboolean normalize) -{ - /* this undoes nm_platform_route_table_coerce(). */ - switch (table_coerced) { - case 0 /* RT_TABLE_UNSPEC */: - return 254; - case 254 /* RT_TABLE_MAIN */: - return normalize ? 254 : 0; - default: - return table_coerced; - } -} - -static inline gboolean -nm_platform_route_table_is_main(guint32 table) -{ - /* same as - * nm_platform_route_table_uncoerce (table, TRUE) == RT_TABLE_MAIN - * and - * nm_platform_route_table_uncoerce (nm_platform_route_table_coerce (table), TRUE) == RT_TABLE_MAIN - * - * That is, the function operates the same on @table and its coerced - * form. - */ - return table == 0 || table == 254; -} - -/** - * nm_platform_route_scope_inv: - * @scope: the route scope, either its original value, or its inverse. - * - * This function is useful, because the constants such as RT_SCOPE_NOWHERE - * are 'int', so ~scope also gives an 'int'. This function gets the type - * casts to guint8 right. - * - * Returns: the bitwise inverse of the route scope. - * */ -#define nm_platform_route_scope_inv _nm_platform_uint8_inv -static inline guint8 -_nm_platform_uint8_inv(guint8 scope) -{ - return (guint8) ~scope; -} - -/** - * nm_platform_route_type_coerce: - * @table: the route type, in its original value. - * - * Returns: returns the coerced type, that can be stored in - * NMPlatformIPRoute.type_coerced. - */ -static inline guint8 -nm_platform_route_type_coerce(guint8 type) -{ - switch (type) { - case 0 /* RTN_UNSPEC */: - return 1; - case 1 /* RTN_UNICAST */: - return 0; - default: - return type; - } -} - -/** - * nm_platform_route_type_uncoerce: - * @table: the type table, in its coerced value - * - * Returns: reverts the coerced type in NMPlatformIPRoute.type_coerced - * to the original value as kernel understands it. - */ -static inline guint8 -nm_platform_route_type_uncoerce(guint8 type_coerced) -{ - return nm_platform_route_type_coerce(type_coerced); -} - -gboolean nm_platform_get_use_udev(NMPlatform *self); -gboolean nm_platform_get_log_with_ptr(NMPlatform *self); - -NMPNetns *nm_platform_netns_get(NMPlatform *self); -gboolean nm_platform_netns_push(NMPlatform *self, NMPNetns **netns); - -const char *nm_link_type_to_string(NMLinkType link_type); - -#define NMP_SYSCTL_PATHID_ABSOLUTE(path) ((const char *) NULL), -1, (path) - -#define NMP_SYSCTL_PATHID_NETDIR_unsafe(dirfd, ifname, path) \ - nm_sprintf_buf_unsafe_a(NM_STRLEN("net:/sys/class/net//\0") + NMP_IFNAMSIZ + ({ \ - const gsize _l = strlen(path); \ - \ - nm_assert(_l < 200); \ - _l; \ - }), \ - "net:/sys/class/net/%s/%s", \ - (ifname), \ - (path)), \ - (dirfd), (path) - -#define NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, path) \ - nm_sprintf_bufa(NM_STRLEN("net:/sys/class/net//" path "/\0") + NMP_IFNAMSIZ, \ - "net:/sys/class/net/%s/%s", \ - (ifname), \ - path), \ - (dirfd), ("" path "") - -int nm_platform_sysctl_open_netdir(NMPlatform *self, int ifindex, char *out_ifname); -gboolean nm_platform_sysctl_set(NMPlatform *self, - const char *pathid, - int dirfd, - const char *path, - const char *value); -void nm_platform_sysctl_set_async(NMPlatform * self, - const char * pathid, - int dirfd, - const char * path, - const char *const * values, - NMPlatformAsyncCallback callback, - gpointer data, - GCancellable * cancellable); -char * nm_platform_sysctl_get(NMPlatform *self, const char *pathid, int dirfd, const char *path); -gint32 nm_platform_sysctl_get_int32(NMPlatform *self, - const char *pathid, - int dirfd, - const char *path, - gint32 fallback); -gint64 nm_platform_sysctl_get_int_checked(NMPlatform *self, - const char *pathid, - int dirfd, - const char *path, - guint base, - gint64 min, - gint64 max, - gint64 fallback); - -char *nm_platform_sysctl_ip_conf_get(NMPlatform *self, - int addr_family, - const char *ifname, - const char *property); - -gint64 nm_platform_sysctl_ip_conf_get_int_checked(NMPlatform *self, - int addr_family, - const char *ifname, - const char *property, - guint base, - gint64 min, - gint64 max, - gint64 fallback); - -gboolean nm_platform_sysctl_ip_conf_set(NMPlatform *self, - int addr_family, - const char *ifname, - const char *property, - const char *value); - -gboolean nm_platform_sysctl_ip_conf_set_int64(NMPlatform *self, - int addr_family, - const char *ifname, - const char *property, - gint64 value); - -gboolean -nm_platform_sysctl_ip_conf_set_ipv6_hop_limit_safe(NMPlatform *self, const char *iface, int value); -gboolean nm_platform_sysctl_ip_neigh_set_ipv6_reachable_time(NMPlatform *self, - const char *iface, - guint value_ms); -gboolean nm_platform_sysctl_ip_neigh_set_ipv6_retrans_time(NMPlatform *self, - const char *iface, - guint value_ms); -int nm_platform_sysctl_ip_conf_get_rp_filter_ipv4(NMPlatform *platform, - const char *iface, - gboolean consider_all, - gboolean * out_due_to_all); - -const char *nm_platform_if_indextoname(NMPlatform *self, - int ifindex, - char out_ifname[static 16 /* IFNAMSIZ */]); -int nm_platform_if_nametoindex(NMPlatform *self, const char *ifname); - -const NMPObject *nm_platform_link_get_obj(NMPlatform *self, int ifindex, gboolean visible_only); -const NMPlatformLink *nm_platform_link_get(NMPlatform *self, int ifindex); -const NMPlatformLink *nm_platform_link_get_by_ifname(NMPlatform *self, const char *ifname); -const NMPlatformLink *nm_platform_link_get_by_address(NMPlatform * self, - NMLinkType link_type, - gconstpointer address, - size_t length); - -GPtrArray *nm_platform_link_get_all(NMPlatform *self, gboolean sort_by_name); - -int nm_platform_link_add(NMPlatform * self, - NMLinkType type, - const char * name, - int parent, - const void * address, - size_t address_len, - guint32 mtu, - gconstpointer extra_data, - const NMPlatformLink **out_link); - -static inline int -nm_platform_link_veth_add(NMPlatform * self, - const char * name, - const char * peer, - const NMPlatformLink **out_link) -{ - return nm_platform_link_add(self, NM_LINK_TYPE_VETH, name, 0, NULL, 0, 0, peer, out_link); -} - -static inline int -nm_platform_link_dummy_add(NMPlatform *self, const char *name, const NMPlatformLink **out_link) -{ - return nm_platform_link_add(self, NM_LINK_TYPE_DUMMY, name, 0, NULL, 0, 0, NULL, out_link); -} - -static inline int -nm_platform_link_bridge_add(NMPlatform * self, - const char * name, - const void * address, - size_t address_len, - guint32 mtu, - const NMPlatformLnkBridge *props, - const NMPlatformLink ** out_link) -{ - return nm_platform_link_add(self, - NM_LINK_TYPE_BRIDGE, - name, - 0, - address, - address_len, - mtu, - props, - out_link); -} - -static inline int -nm_platform_link_bond_add(NMPlatform *self, const char *name, const NMPlatformLink **out_link) -{ - return nm_platform_link_add(self, NM_LINK_TYPE_BOND, name, 0, NULL, 0, 0, NULL, out_link); -} - -static inline int -nm_platform_link_team_add(NMPlatform *self, const char *name, const NMPlatformLink **out_link) -{ - return nm_platform_link_add(self, NM_LINK_TYPE_TEAM, name, 0, NULL, 0, 0, NULL, out_link); -} - -static inline int -nm_platform_link_wireguard_add(NMPlatform *self, const char *name, const NMPlatformLink **out_link) -{ - return nm_platform_link_add(self, NM_LINK_TYPE_WIREGUARD, name, 0, NULL, 0, 0, NULL, out_link); -} - -static inline int -nm_platform_link_gre_add(NMPlatform * self, - const char * name, - const void * address, - size_t address_len, - const NMPlatformLnkGre *props, - const NMPlatformLink ** out_link) -{ - g_return_val_if_fail(props, -NME_BUG); - - return nm_platform_link_add(self, - props->is_tap ? NM_LINK_TYPE_GRETAP : NM_LINK_TYPE_GRE, - name, - 0, - address, - address_len, - 0, - props, - out_link); -} - -static inline int -nm_platform_link_sit_add(NMPlatform * self, - const char * name, - const NMPlatformLnkSit *props, - const NMPlatformLink ** out_link) -{ - return nm_platform_link_add(self, NM_LINK_TYPE_SIT, name, 0, NULL, 0, 0, props, out_link); -} - -static inline int -nm_platform_link_vlan_add(NMPlatform * self, - const char * name, - int parent, - int vlanid, - guint32 vlanflags, - const NMPlatformLink **out_link) -{ - g_return_val_if_fail(parent >= 0, -NME_BUG); - g_return_val_if_fail(vlanid >= 0, -NME_BUG); - - return nm_platform_link_add(self, - NM_LINK_TYPE_VLAN, - name, - parent, - NULL, - 0, - 0, - &((NMPlatformLnkVlan){ - .id = vlanid, - .flags = vlanflags, - }), - out_link); -} - -static inline int -nm_platform_link_vrf_add(NMPlatform * self, - const char * name, - const NMPlatformLnkVrf *props, - const NMPlatformLink ** out_link) -{ - return nm_platform_link_add(self, NM_LINK_TYPE_VRF, name, 0, NULL, 0, 0, props, out_link); -} - -static inline int -nm_platform_link_vxlan_add(NMPlatform * self, - const char * name, - const NMPlatformLnkVxlan *props, - const NMPlatformLink ** out_link) -{ - return nm_platform_link_add(self, NM_LINK_TYPE_VXLAN, name, 0, NULL, 0, 0, props, out_link); -} - -static inline int -nm_platform_link_6lowpan_add(NMPlatform * self, - const char * name, - int parent, - const NMPlatformLink **out_link) -{ - return nm_platform_link_add(self, - NM_LINK_TYPE_6LOWPAN, - name, - parent, - NULL, - 0, - 0, - NULL, - out_link); -} - -static inline int -nm_platform_link_ip6tnl_add(NMPlatform * self, - const char * name, - const NMPlatformLnkIp6Tnl *props, - const NMPlatformLink ** out_link) -{ - g_return_val_if_fail(props, -NME_BUG); - g_return_val_if_fail(!props->is_gre, -NME_BUG); - - return nm_platform_link_add(self, NM_LINK_TYPE_IP6TNL, name, 0, NULL, 0, 0, props, out_link); -} - -static inline int -nm_platform_link_ip6gre_add(NMPlatform * self, - const char * name, - const void * address, - size_t address_len, - const NMPlatformLnkIp6Tnl *props, - const NMPlatformLink ** out_link) -{ - g_return_val_if_fail(props, -NME_BUG); - g_return_val_if_fail(props->is_gre, -NME_BUG); - - return nm_platform_link_add(self, - props->is_tap ? NM_LINK_TYPE_IP6GRETAP : NM_LINK_TYPE_IP6GRE, - name, - 0, - address, - address_len, - 0, - props, - out_link); -} - -static inline int -nm_platform_link_ipip_add(NMPlatform * self, - const char * name, - const NMPlatformLnkIpIp *props, - const NMPlatformLink ** out_link) -{ - g_return_val_if_fail(props, -NME_BUG); - - return nm_platform_link_add(self, NM_LINK_TYPE_IPIP, name, 0, NULL, 0, 0, props, out_link); -} - -static inline int -nm_platform_link_macsec_add(NMPlatform * self, - const char * name, - int parent, - const NMPlatformLnkMacsec *props, - const NMPlatformLink ** out_link) -{ - g_return_val_if_fail(props, -NME_BUG); - g_return_val_if_fail(parent > 0, -NME_BUG); - - return nm_platform_link_add(self, - NM_LINK_TYPE_MACSEC, - name, - parent, - NULL, - 0, - 0, - props, - out_link); -} - -static inline int -nm_platform_link_macvlan_add(NMPlatform * self, - const char * name, - int parent, - const NMPlatformLnkMacvlan *props, - const NMPlatformLink ** out_link) -{ - g_return_val_if_fail(props, -NME_BUG); - g_return_val_if_fail(parent > 0, -NME_BUG); - - return nm_platform_link_add(self, - props->tap ? NM_LINK_TYPE_MACVTAP : NM_LINK_TYPE_MACVLAN, - name, - parent, - NULL, - 0, - 0, - props, - out_link); -} - -gboolean nm_platform_link_delete(NMPlatform *self, int ifindex); - -gboolean nm_platform_link_set_netns(NMPlatform *self, int ifindex, int netns_fd); - -struct _NMDedupMultiHeadEntry; -struct _NMPLookup; -const struct _NMDedupMultiHeadEntry *nm_platform_lookup(NMPlatform * self, - const struct _NMPLookup *lookup); - -#define nm_platform_iter_obj_for_each(iter, self, lookup, obj) \ - for (nm_dedup_multi_iter_init((iter), nm_platform_lookup((self), (lookup))); \ - nm_platform_dedup_multi_iter_next_obj((iter), (obj), NMP_OBJECT_TYPE_UNKNOWN);) - -gboolean nm_platform_lookup_predicate_routes_main(const NMPObject *obj, gpointer user_data); -gboolean nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel(const NMPObject *obj, - gpointer user_data); - -GPtrArray *nm_platform_lookup_clone(NMPlatform * self, - const struct _NMPLookup *lookup, - NMPObjectPredicateFunc predicate, - gpointer user_data); - -/* convenience methods to lookup the link and access fields of NMPlatformLink. */ -int nm_platform_link_get_ifindex(NMPlatform *self, const char *name); -const char *nm_platform_link_get_name(NMPlatform *self, int ifindex); -NMLinkType nm_platform_link_get_type(NMPlatform *self, int ifindex); -gboolean nm_platform_link_is_software(NMPlatform *self, int ifindex); -int nm_platform_link_get_ifi_flags(NMPlatform *self, int ifindex, guint requested_flags); -gboolean nm_platform_link_is_up(NMPlatform *self, int ifindex); -gboolean nm_platform_link_is_connected(NMPlatform *self, int ifindex); -gboolean nm_platform_link_uses_arp(NMPlatform *self, int ifindex); -guint32 nm_platform_link_get_mtu(NMPlatform *self, int ifindex); -gboolean nm_platform_link_get_user_ipv6ll_enabled(NMPlatform *self, int ifindex); - -gconstpointer nm_platform_link_get_address(NMPlatform *self, int ifindex, size_t *length); - -int nm_platform_link_get_master(NMPlatform *self, int slave); - -gboolean nm_platform_link_can_assume(NMPlatform *self, int ifindex); - -gboolean nm_platform_link_get_unmanaged(NMPlatform *self, int ifindex, gboolean *unmanaged); -gboolean nm_platform_link_supports_slaves(NMPlatform *self, int ifindex); -const char *nm_platform_link_get_type_name(NMPlatform *self, int ifindex); - -gboolean nm_platform_link_refresh(NMPlatform *self, int ifindex); -void nm_platform_process_events(NMPlatform *self); - -const NMPlatformLink * -nm_platform_process_events_ensure_link(NMPlatform *self, int ifindex, const char *ifname); - -gboolean nm_platform_link_set_up(NMPlatform *self, int ifindex, gboolean *out_no_firmware); -gboolean nm_platform_link_set_down(NMPlatform *self, int ifindex); -gboolean nm_platform_link_set_arp(NMPlatform *self, int ifindex); -gboolean nm_platform_link_set_noarp(NMPlatform *self, int ifindex); - -const char *nm_platform_link_get_udi(NMPlatform *self, int ifindex); -const char *nm_platform_link_get_path(NMPlatform *self, int ifindex); - -struct udev_device *nm_platform_link_get_udev_device(NMPlatform *self, int ifindex); - -int nm_platform_link_set_user_ipv6ll_enabled(NMPlatform *self, int ifindex, gboolean enabled); -gboolean nm_platform_link_set_ipv6_token(NMPlatform *self, int ifindex, NMUtilsIPv6IfaceId iid); - -gboolean -nm_platform_link_get_permanent_address(NMPlatform *self, int ifindex, guint8 *buf, size_t *length); -int nm_platform_link_set_address(NMPlatform *self, int ifindex, const void *address, size_t length); -int nm_platform_link_set_mtu(NMPlatform *self, int ifindex, guint32 mtu); -gboolean nm_platform_link_set_name(NMPlatform *self, int ifindex, const char *name); - -void nm_platform_link_set_sriov_params_async(NMPlatform * self, - int ifindex, - guint num_vfs, - NMOptionBool autoprobe, - NMPlatformAsyncCallback callback, - gpointer callback_data, - GCancellable * cancellable); - -gboolean -nm_platform_link_set_sriov_vfs(NMPlatform *self, int ifindex, const NMPlatformVF *const *vfs); -gboolean nm_platform_link_set_bridge_vlans(NMPlatform * self, - int ifindex, - gboolean on_master, - const NMPlatformBridgeVlan *const *vlans); - -char * nm_platform_link_get_physical_port_id(NMPlatform *self, int ifindex); -guint nm_platform_link_get_dev_id(NMPlatform *self, int ifindex); -gboolean nm_platform_link_get_wake_on_lan(NMPlatform *self, int ifindex); -gboolean nm_platform_link_get_driver_info(NMPlatform *self, - int ifindex, - char ** out_driver_name, - char ** out_driver_version, - char ** out_fw_version); - -gboolean nm_platform_link_supports_carrier_detect(NMPlatform *self, int ifindex); -gboolean nm_platform_link_supports_vlans(NMPlatform *self, int ifindex); -gboolean nm_platform_link_supports_sriov(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_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 NMPlatformLnkBridge * -nm_platform_link_get_lnk_bridge(NMPlatform *self, int ifindex, const NMPlatformLink **out_link); -const NMPlatformLnkGre * -nm_platform_link_get_lnk_gre(NMPlatform *self, int ifindex, const NMPlatformLink **out_link); -const NMPlatformLnkGre * -nm_platform_link_get_lnk_gretap(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 NMPlatformLnkIp6Tnl * -nm_platform_link_get_lnk_ip6gre(NMPlatform *self, int ifindex, const NMPlatformLink **out_link); -const NMPlatformLnkIp6Tnl * -nm_platform_link_get_lnk_ip6gretap(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 NMPlatformLnkMacsec * -nm_platform_link_get_lnk_macsec(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 NMPlatformLnkMacvlan * -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 NMPlatformLnkTun * -nm_platform_link_get_lnk_tun(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 NMPlatformLnkVrf * -nm_platform_link_get_lnk_vrf(NMPlatform *self, int ifindex, const NMPlatformLink **out_link); -const NMPlatformLnkVxlan * -nm_platform_link_get_lnk_vxlan(NMPlatform *self, int ifindex, const NMPlatformLink **out_link); -const NMPlatformLnkWireGuard * -nm_platform_link_get_lnk_wireguard(NMPlatform *self, int ifindex, 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); - -int nm_platform_link_infiniband_add(NMPlatform * self, - int parent, - int p_key, - const NMPlatformLink **out_link); -int nm_platform_link_infiniband_delete(NMPlatform *self, int parent, int p_key); -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, - NMPlatformLnkTun *out_properties); - -gboolean -nm_platform_wifi_get_capabilities(NMPlatform *self, int ifindex, NMDeviceWifiCapabilities *caps); -guint32 nm_platform_wifi_get_frequency(NMPlatform *self, int ifindex); -gboolean nm_platform_wifi_get_station(NMPlatform * self, - int ifindex, - NMEtherAddr *out_bssid, - int * out_quality, - guint32 * out_rate); -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); -NMSettingWirelessWakeOnWLan nm_platform_wifi_get_wake_on_wlan(NMPlatform *self, int ifindex); -gboolean -nm_platform_wifi_set_wake_on_wlan(NMPlatform *self, int ifindex, NMSettingWirelessWakeOnWLan wowl); - -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); - -guint16 nm_platform_wpan_get_pan_id(NMPlatform *self, int ifindex); -gboolean nm_platform_wpan_set_pan_id(NMPlatform *self, int ifindex, guint16 pan_id); -guint16 nm_platform_wpan_get_short_addr(NMPlatform *self, int ifindex); -gboolean nm_platform_wpan_set_short_addr(NMPlatform *self, int ifindex, guint16 short_addr); -gboolean nm_platform_wpan_set_channel(NMPlatform *self, int ifindex, guint8 page, guint8 channel); - -void nm_platform_ip4_address_set_addr(NMPlatformIP4Address *addr, in_addr_t address, guint8 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, - guint8 plen, - in_addr_t peer_address); - -int nm_platform_link_sit_add(NMPlatform * self, - const char * name, - const NMPlatformLnkSit *props, - const NMPlatformLink ** out_link); -int nm_platform_link_tun_add(NMPlatform * self, - const char * name, - const NMPlatformLnkTun *props, - const NMPlatformLink ** out_link, - int * out_fd); -gboolean nm_platform_link_6lowpan_get_properties(NMPlatform *self, int ifindex, int *out_parent); - -int -nm_platform_link_wireguard_add(NMPlatform *self, const char *name, const NMPlatformLink **out_link); - -int nm_platform_link_wireguard_change(NMPlatform * self, - int ifindex, - const NMPlatformLnkWireGuard * lnk_wireguard, - const struct _NMPWireGuardPeer * peers, - const NMPlatformWireGuardChangePeerFlags *peer_flags, - guint peers_len, - NMPlatformWireGuardChangeFlags change_flags); - -const NMPlatformIP6Address * -nm_platform_ip6_address_get(NMPlatform *self, int ifindex, const struct in6_addr *address); - -gboolean nm_platform_object_delete(NMPlatform *self, const NMPObject *route); - -gboolean nm_platform_ip4_address_add(NMPlatform *self, - int ifindex, - in_addr_t address, - guint8 plen, - in_addr_t peer_address, - in_addr_t broadcast_address, - guint32 lifetime, - guint32 preferred_lft, - guint32 flags, - const char *label); -gboolean nm_platform_ip6_address_add(NMPlatform * self, - int ifindex, - struct in6_addr address, - guint8 plen, - struct in6_addr peer_address, - guint32 lifetime, - guint32 preferred_lft, - guint32 flags); -gboolean nm_platform_ip4_address_delete(NMPlatform *self, - int ifindex, - in_addr_t address, - guint8 plen, - in_addr_t peer_address); -gboolean -nm_platform_ip6_address_delete(NMPlatform *self, int ifindex, struct in6_addr address, guint8 plen); - -gboolean nm_platform_ip_address_sync(NMPlatform *self, - int addr_family, - int ifindex, - GPtrArray * known_addresses, - GPtrArray * addresses_prune); - -GPtrArray *nm_platform_ip_address_get_prune_list(NMPlatform *self, - int addr_family, - int ifindex, - gboolean exclude_ipv6_temporary_addrs); - -static inline gboolean -_nm_platform_ip_address_sync(NMPlatform *self, - int addr_family, - int ifindex, - GPtrArray * known_addresses, - gboolean full_sync) -{ - gs_unref_ptrarray GPtrArray *addresses_prune = NULL; - - addresses_prune = nm_platform_ip_address_get_prune_list(self, addr_family, ifindex, !full_sync); - return nm_platform_ip_address_sync(self, - addr_family, - ifindex, - known_addresses, - addresses_prune); -} - -static inline gboolean -nm_platform_ip4_address_sync(NMPlatform *self, int ifindex, GPtrArray *known_addresses) -{ - return _nm_platform_ip_address_sync(self, AF_INET, ifindex, known_addresses, TRUE); -} - -static inline gboolean -nm_platform_ip6_address_sync(NMPlatform *self, - int ifindex, - GPtrArray * known_addresses, - gboolean full_sync) -{ - return _nm_platform_ip_address_sync(self, AF_INET6, ifindex, known_addresses, full_sync); -} - -gboolean nm_platform_ip_address_flush(NMPlatform *self, int addr_family, int ifindex); - -static inline gconstpointer -nm_platform_ip_address_get_peer_address(int addr_family, const NMPlatformIPAddress *addr) -{ - nm_assert_addr_family(addr_family); - nm_assert(addr); - - if (NM_IS_IPv4(addr_family)) - return &((NMPlatformIP4Address *) addr)->peer_address; - return &((NMPlatformIP6Address *) addr)->peer_address; -} - -void nm_platform_ip_route_normalize(int addr_family, NMPlatformIPRoute *route); - -static inline guint32 -nm_platform_ip4_route_get_effective_metric(const NMPlatformIP4Route *r) -{ - nm_assert(r); - - return r->metric_any ? nm_add_clamped_u32(NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4, r->metric) - : r->metric; -} - -static inline guint32 -nm_platform_ip6_route_get_effective_metric(const NMPlatformIP6Route *r) -{ - nm_assert(r); - - return r->metric_any ? nm_add_clamped_u32(NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6, r->metric) - : r->metric; -} - -static inline guint32 -nm_platform_ip_route_get_effective_table(const NMPlatformIPRoute *r) -{ - nm_assert(r); - nm_assert(!r->table_any || r->table_coerced == 0); - - return r->table_any ? 254u /* RT_TABLE_MAIN */ - : nm_platform_route_table_uncoerce(r->table_coerced, TRUE); -} - -static inline gconstpointer -nm_platform_ip_route_get_gateway(int addr_family, const NMPlatformIPRoute *route) -{ - nm_assert_addr_family(addr_family); - nm_assert(route); - - if (NM_IS_IPv4(addr_family)) - return &((NMPlatformIP4Route *) route)->gateway; - return &((NMPlatformIP6Route *) route)->gateway; -} - -int nm_platform_ip_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPObject *route); -int nm_platform_ip4_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP4Route *route); -int nm_platform_ip6_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP6Route *route); - -GPtrArray *nm_platform_ip_route_get_prune_list(NMPlatform * self, - int addr_family, - int ifindex, - NMIPRouteTableSyncMode route_table_sync); - -gboolean nm_platform_ip_route_sync(NMPlatform *self, - int addr_family, - int ifindex, - GPtrArray * routes, - GPtrArray * routes_prune, - GPtrArray **out_temporary_not_available); - -gboolean nm_platform_ip_route_flush(NMPlatform *self, int addr_family, int ifindex); - -int nm_platform_ip_route_get(NMPlatform * self, - int addr_family, - gconstpointer address, - int oif_ifindex, - NMPObject ** out_route); - -int nm_platform_routing_rule_add(NMPlatform * self, - NMPNlmFlags flags, - const NMPlatformRoutingRule *routing_rule); - -int nm_platform_qdisc_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformQdisc *qdisc); -gboolean nm_platform_qdisc_sync(NMPlatform *self, int ifindex, GPtrArray *known_qdiscs); - -int nm_platform_tfilter_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformTfilter *tfilter); -gboolean nm_platform_tfilter_sync(NMPlatform *self, int ifindex, GPtrArray *known_tfilters); - -const char *nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len); -const char *nm_platform_lnk_bridge_to_string(const NMPlatformLnkBridge *lnk, 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_macsec_to_string(const NMPlatformLnkMacsec *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_tun_to_string(const NMPlatformLnkTun *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_vrf_to_string(const NMPlatformLnkVrf *lnk, char *buf, gsize len); -const char *nm_platform_lnk_vxlan_to_string(const NMPlatformLnkVxlan *lnk, char *buf, gsize len); -const char * -nm_platform_lnk_wireguard_to_string(const NMPlatformLnkWireGuard *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_routing_rule_to_string(const NMPlatformRoutingRule *routing_rule, char *buf, gsize len); -const char *nm_platform_qdisc_to_string(const NMPlatformQdisc *qdisc, char *buf, gsize len); -const char *nm_platform_tfilter_to_string(const NMPlatformTfilter *tfilter, char *buf, gsize len); -const char *nm_platform_vf_to_string(const NMPlatformVF *vf, char *buf, gsize len); -const char * -nm_platform_bridge_vlan_to_string(const NMPlatformBridgeVlan *vlan, 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); - -const char * -nm_platform_wireguard_peer_to_string(const struct _NMPWireGuardPeer *peer, char *buf, gsize len); - -int nm_platform_link_cmp(const NMPlatformLink *a, const NMPlatformLink *b); -int nm_platform_lnk_bridge_cmp(const NMPlatformLnkBridge *a, const NMPlatformLnkBridge *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_macsec_cmp(const NMPlatformLnkMacsec *a, const NMPlatformLnkMacsec *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_tun_cmp(const NMPlatformLnkTun *a, const NMPlatformLnkTun *b); -int nm_platform_lnk_vlan_cmp(const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b); -int nm_platform_lnk_vrf_cmp(const NMPlatformLnkVrf *a, const NMPlatformLnkVrf *b); -int nm_platform_lnk_vxlan_cmp(const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *b); -int nm_platform_lnk_wireguard_cmp(const NMPlatformLnkWireGuard *a, const NMPlatformLnkWireGuard *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_address_pretty_sort_cmp(const NMPlatformIP4Address *a1, - const NMPlatformIP4Address *a2); - -int nm_platform_ip6_address_pretty_sort_cmp(const NMPlatformIP6Address *a1, - const NMPlatformIP6Address *a2, - gboolean prefer_temp); - -GHashTable *nm_platform_ip4_address_addr_to_hash(NMPlatform *self, int ifindex); - -int nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a, - const NMPlatformIP4Route *b, - NMPlatformIPRouteCmpType cmp_type); -int nm_platform_ip6_route_cmp(const NMPlatformIP6Route *a, - const NMPlatformIP6Route *b, - NMPlatformIPRouteCmpType cmp_type); - -static inline int -nm_platform_ip4_route_cmp_full(const NMPlatformIP4Route *a, const NMPlatformIP4Route *b) -{ - return nm_platform_ip4_route_cmp(a, b, NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL); -} - -static inline int -nm_platform_ip6_route_cmp_full(const NMPlatformIP6Route *a, const NMPlatformIP6Route *b) -{ - return nm_platform_ip6_route_cmp(a, b, NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL); -} - -int nm_platform_routing_rule_cmp(const NMPlatformRoutingRule *a, - const NMPlatformRoutingRule *b, - NMPlatformRoutingRuleCmpType cmp_type); - -static inline int -nm_platform_routing_rule_cmp_full(const NMPlatformRoutingRule *a, const NMPlatformRoutingRule *b) -{ - return nm_platform_routing_rule_cmp(a, b, NM_PLATFORM_ROUTING_RULE_CMP_TYPE_FULL); -} - -int nm_platform_qdisc_cmp(const NMPlatformQdisc *a, const NMPlatformQdisc *b); -int nm_platform_qdisc_cmp_full(const NMPlatformQdisc *a, - const NMPlatformQdisc *b, - gboolean compare_handle); -int nm_platform_tfilter_cmp(const NMPlatformTfilter *a, const NMPlatformTfilter *b); - -void nm_platform_link_hash_update(const NMPlatformLink *obj, NMHashState *h); -void nm_platform_ip4_address_hash_update(const NMPlatformIP4Address *obj, NMHashState *h); -void nm_platform_ip6_address_hash_update(const NMPlatformIP6Address *obj, NMHashState *h); -void nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj, - NMPlatformIPRouteCmpType cmp_type, - NMHashState * h); -void nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj, - NMPlatformIPRouteCmpType cmp_type, - NMHashState * h); -void nm_platform_routing_rule_hash_update(const NMPlatformRoutingRule *obj, - NMPlatformRoutingRuleCmpType cmp_type, - NMHashState * h); -void nm_platform_lnk_bridge_hash_update(const NMPlatformLnkBridge *obj, NMHashState *h); -void nm_platform_lnk_gre_hash_update(const NMPlatformLnkGre *obj, NMHashState *h); -void nm_platform_lnk_infiniband_hash_update(const NMPlatformLnkInfiniband *obj, NMHashState *h); -void nm_platform_lnk_ip6tnl_hash_update(const NMPlatformLnkIp6Tnl *obj, NMHashState *h); -void nm_platform_lnk_ipip_hash_update(const NMPlatformLnkIpIp *obj, NMHashState *h); -void nm_platform_lnk_macsec_hash_update(const NMPlatformLnkMacsec *obj, NMHashState *h); -void nm_platform_lnk_macvlan_hash_update(const NMPlatformLnkMacvlan *obj, NMHashState *h); -void nm_platform_lnk_sit_hash_update(const NMPlatformLnkSit *obj, NMHashState *h); -void nm_platform_lnk_tun_hash_update(const NMPlatformLnkTun *obj, NMHashState *h); -void nm_platform_lnk_vlan_hash_update(const NMPlatformLnkVlan *obj, NMHashState *h); -void nm_platform_lnk_vrf_hash_update(const NMPlatformLnkVrf *obj, NMHashState *h); -void nm_platform_lnk_vxlan_hash_update(const NMPlatformLnkVxlan *obj, NMHashState *h); -void nm_platform_lnk_wireguard_hash_update(const NMPlatformLnkWireGuard *obj, NMHashState *h); - -void nm_platform_qdisc_hash_update(const NMPlatformQdisc *obj, NMHashState *h); -void nm_platform_tfilter_hash_update(const NMPlatformTfilter *obj, NMHashState *h); - -#define NM_PLATFORM_LINK_FLAGS2STR_MAX_LEN ((gsize) 162) - -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); - -gboolean nm_platform_ethtool_set_wake_on_lan(NMPlatform * self, - int ifindex, - _NMSettingWiredWakeOnLan wol, - const char * wol_password); -gboolean nm_platform_ethtool_set_link_settings(NMPlatform * self, - int ifindex, - gboolean autoneg, - guint32 speed, - NMPlatformLinkDuplexType duplex); -gboolean nm_platform_ethtool_get_link_settings(NMPlatform * self, - int ifindex, - gboolean * out_autoneg, - guint32 * out_speed, - NMPlatformLinkDuplexType *out_duplex); - -NMEthtoolFeatureStates *nm_platform_ethtool_get_link_features(NMPlatform *self, int ifindex); -gboolean nm_platform_ethtool_set_features( - NMPlatform * self, - int ifindex, - const NMEthtoolFeatureStates *features, - const NMOptionBool *requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */, - gboolean do_set /* or reset */); - -gboolean nm_platform_ethtool_get_link_coalesce(NMPlatform * self, - int ifindex, - NMEthtoolCoalesceState *coalesce); - -gboolean nm_platform_ethtool_set_coalesce(NMPlatform * self, - int ifindex, - const NMEthtoolCoalesceState *coalesce); - -gboolean nm_platform_ethtool_get_link_ring(NMPlatform *self, int ifindex, NMEthtoolRingState *ring); - -gboolean -nm_platform_ethtool_set_ring(NMPlatform *self, int ifindex, const NMEthtoolRingState *ring); - -void nm_platform_ip4_dev_route_blacklist_set(NMPlatform *self, - int ifindex, - GPtrArray * ip4_dev_route_blacklist); - -struct _NMDedupMultiIndex *nm_platform_get_multi_idx(NMPlatform *self); - -/*****************************************************************************/ - -gboolean nm_platform_ip6_address_match(const NMPlatformIP6Address *addr, - NMPlatformMatchFlags match_flag); - -#endif /* __NETWORKMANAGER_PLATFORM_H__ */ diff --git a/src/core/platform/nmp-object.c b/src/core/platform/nmp-object.c deleted file mode 100644 index 6a26595e..00000000 --- a/src/core/platform/nmp-object.c +++ /dev/null @@ -1,3457 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2015 - 2018 Red Hat, Inc. - */ - -#include "src/core/nm-default-daemon.h" - -#include "nmp-object.h" - -#include -#include -#include -#include - -#include "nm-utils.h" -#include "nm-glib-aux/nm-secret-utils.h" - -#include "nm-core-utils.h" -#include "nm-platform/nm-platform-utils.h" - -#include "wifi/nm-wifi-utils.h" -#include "wpan/nm-wpan-utils.h" - -/*****************************************************************************/ - -#define _NMLOG_DOMAIN LOGD_PLATFORM -#define _NMLOG(level, obj, ...) \ - G_STMT_START \ - { \ - const NMLogLevel __level = (level); \ - \ - if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) { \ - const NMPObject *const __obj = (obj); \ - \ - _nm_log(__level, \ - _NMLOG_DOMAIN, \ - 0, \ - NULL, \ - NULL, \ - "nmp-object[%p/%s]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - __obj, \ - (__obj ? NMP_OBJECT_GET_CLASS(__obj)->obj_type_name \ - : "???") _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } \ - G_STMT_END - -/*****************************************************************************/ - -typedef struct { - NMDedupMultiIdxType parent; - NMPCacheIdType cache_id_type; -} DedupMultiIdxType; - -struct _NMPCache { - /* the cache contains only one hash table for all object types, and similarly - * it contains only one NMMultiIndex. - * This works, because different object types don't ever compare equal and - * because their index ids also don't overlap. - * - * For routes and addresses, the cache contains an address if (and only if) the - * object was reported via netlink. - * For links, the cache contain a link if it was reported by either netlink - * or udev. That means, a link object can be alive, even if it was already - * removed via netlink. - * - * This effectively merges the udev-device cache into the NMPCache. - */ - - NMDedupMultiIndex *multi_idx; - - /* an idx_type entry for each NMP_CACHE_ID_TYPE. Note that NONE (zero) - * is skipped, so the index is shifted by one: idx_type[cache_id_type - 1]. - * - * Don't bother, use _idx_type_get() instead! */ - DedupMultiIdxType idx_types[NMP_CACHE_ID_TYPE_MAX]; - - gboolean use_udev; -}; - -/*****************************************************************************/ - -int -nm_sock_addr_union_cmp(const NMSockAddrUnion *a, const NMSockAddrUnion *b) -{ - nm_assert(!a || NM_IN_SET(a->sa.sa_family, AF_UNSPEC, AF_INET, AF_INET6)); - nm_assert(!b || NM_IN_SET(b->sa.sa_family, AF_UNSPEC, AF_INET, AF_INET6)); - - NM_CMP_SELF(a, b); - - NM_CMP_FIELD(a, b, sa.sa_family); - switch (a->sa.sa_family) { - case AF_INET: - NM_CMP_DIRECT(ntohl(a->in.sin_addr.s_addr), ntohl(b->in.sin_addr.s_addr)); - NM_CMP_DIRECT(htons(a->in.sin_port), htons(b->in.sin_port)); - break; - case AF_INET6: - NM_CMP_DIRECT_IN6ADDR(&a->in6.sin6_addr, &b->in6.sin6_addr); - NM_CMP_DIRECT(htons(a->in6.sin6_port), htons(b->in6.sin6_port)); - NM_CMP_FIELD(a, b, in6.sin6_scope_id); - NM_CMP_FIELD(a, b, in6.sin6_flowinfo); - break; - } - return 0; -} - -void -nm_sock_addr_union_hash_update(const NMSockAddrUnion *a, NMHashState *h) -{ - if (!a) { - nm_hash_update_val(h, 1241364739u); - return; - } - - nm_assert(NM_IN_SET(a->sa.sa_family, AF_UNSPEC, AF_INET, AF_INET6)); - - switch (a->sa.sa_family) { - case AF_INET: - nm_hash_update_vals(h, a->in.sin_family, a->in.sin_addr.s_addr, a->in.sin_port); - return; - case AF_INET6: - nm_hash_update_vals(h, - a->in6.sin6_family, - a->in6.sin6_addr, - a->in6.sin6_port, - a->in6.sin6_scope_id, - a->in6.sin6_flowinfo); - return; - default: - nm_hash_update_val(h, a->sa.sa_family); - return; - } -} - -/** - * nm_sock_addr_union_cpy: - * @dst: the destination #NMSockAddrUnion. It will always be fully initialized, - * to one of the address families AF_INET, AF_INET6, or AF_UNSPEC (in case of - * error). - * @src: (allow-none): the source buffer with an sockaddr to copy. It may be unaligned in - * memory. If not %NULL, the buffer must be at least large enough to contain - * sa.sa_family, and then, depending on sa.sa_family, it must be large enough - * to hold struct sockaddr_in or struct sockaddr_in6. - * - * @dst will always be fully initialized (including setting all un-used bytes to zero). - */ -void -nm_sock_addr_union_cpy(NMSockAddrUnion *dst, - gconstpointer src /* unaligned (const NMSockAddrUnion *) */) -{ - struct sockaddr sa; - gsize src_len; - - nm_assert(dst); - - *dst = (NMSockAddrUnion) NM_SOCK_ADDR_UNION_INIT_UNSPEC; - - if (!src) - return; - - memcpy(&sa.sa_family, &((struct sockaddr *) src)->sa_family, sizeof(sa.sa_family)); - - if (sa.sa_family == AF_INET) - src_len = sizeof(struct sockaddr_in); - else if (sa.sa_family == AF_INET6) - src_len = sizeof(struct sockaddr_in6); - else - return; - - memcpy(dst, src, src_len); - nm_assert(dst->sa.sa_family == sa.sa_family); -} - -/** - * nm_sock_addr_union_cpy_untrusted: - * @dst: the destination #NMSockAddrUnion. It will always be fully initialized, - * to one of the address families AF_INET, AF_INET6, or AF_UNSPEC (in case of - * error). - * @src: the source buffer with an sockaddr to copy. It may be unaligned in - * memory. - * @src_len: the length of @src in bytes. - * - * The function requires @src_len to be either sizeof(struct sockaddr_in) or sizeof (struct sockaddr_in6). - * If that's the case, then @src will be interpreted as such structure (unaligned), and - * accessed. It will check sa.sa_family to match the expected sizes, and if it does, the - * struct will be copied. - * - * On any failure, @dst will be set to sa.sa_family AF_UNSPEC. - * @dst will always be fully initialized (including setting all un-used bytes to zero). - */ -void -nm_sock_addr_union_cpy_untrusted(NMSockAddrUnion *dst, - gconstpointer src /* unaligned (const NMSockAddrUnion *) */, - gsize src_len) -{ - int f_expected; - struct sockaddr sa; - - nm_assert(dst); - - *dst = (NMSockAddrUnion) NM_SOCK_ADDR_UNION_INIT_UNSPEC; - - if (src_len == sizeof(struct sockaddr_in)) - f_expected = AF_INET; - else if (src_len == sizeof(struct sockaddr_in6)) - f_expected = AF_INET6; - else - return; - - memcpy(&sa.sa_family, &((struct sockaddr *) src)->sa_family, sizeof(sa.sa_family)); - - if (sa.sa_family != f_expected) - return; - - memcpy(dst, src, src_len); - nm_assert(dst->sa.sa_family == sa.sa_family); -} - -const char * -nm_sock_addr_union_to_string(const NMSockAddrUnion *sa, char *buf, gsize len) -{ - char s_addr[NM_UTILS_INET_ADDRSTRLEN]; - char s_scope_id[40]; - - if (!nm_utils_to_string_buffer_init_null(sa, &buf, &len)) - return buf; - - /* maybe we should use getnameinfo(), but here implement it ourself. - * - * We want to see the actual bytes for debugging (as we understand them), - * and now what getnameinfo() makes of it. Also, it's simpler this way. */ - - switch (sa->sa.sa_family) { - case AF_INET: - g_snprintf(buf, - len, - "%s:%u", - _nm_utils_inet4_ntop(sa->in.sin_addr.s_addr, s_addr), - (guint) htons(sa->in.sin_port)); - break; - case AF_INET6: - g_snprintf(buf, - len, - "[%s%s]:%u", - _nm_utils_inet6_ntop(&sa->in6.sin6_addr, s_addr), - (sa->in6.sin6_scope_id != 0 - ? nm_sprintf_buf(s_scope_id, "%u", sa->in6.sin6_scope_id) - : ""), - (guint) htons(sa->in6.sin6_port)); - break; - case AF_UNSPEC: - g_snprintf(buf, len, "unspec"); - break; - default: - g_snprintf(buf, len, "{addr-family:%u}", (unsigned) sa->sa.sa_family); - break; - } - - return buf; -} - -/*****************************************************************************/ - -static const NMDedupMultiIdxTypeClass _dedup_multi_idx_type_class; - -static void -_idx_obj_id_hash_update(const NMDedupMultiIdxType *idx_type, - const NMDedupMultiObj * obj, - NMHashState * h) -{ - const NMPObject *o = (NMPObject *) obj; - - nm_assert(idx_type && idx_type->klass == &_dedup_multi_idx_type_class); - nm_assert(NMP_OBJECT_GET_TYPE(o) != NMP_OBJECT_TYPE_UNKNOWN); - - nmp_object_id_hash_update(o, h); -} - -static gboolean -_idx_obj_id_equal(const NMDedupMultiIdxType *idx_type, - const NMDedupMultiObj * obj_a, - const NMDedupMultiObj * obj_b) -{ - const NMPObject *o_a = (NMPObject *) obj_a; - const NMPObject *o_b = (NMPObject *) obj_b; - - nm_assert(idx_type && idx_type->klass == &_dedup_multi_idx_type_class); - nm_assert(NMP_OBJECT_GET_TYPE(o_a) != NMP_OBJECT_TYPE_UNKNOWN); - nm_assert(NMP_OBJECT_GET_TYPE(o_b) != NMP_OBJECT_TYPE_UNKNOWN); - - return nmp_object_id_equal(o_a, o_b); -} - -static guint -_idx_obj_part(const DedupMultiIdxType *idx_type, - const NMPObject * obj_a, - const NMPObject * obj_b, - NMHashState * h) -{ - NMPObjectType obj_type; - - /* the hash/equals functions are strongly related. So, keep them - * side-by-side and do it all in _idx_obj_part(). */ - - nm_assert(idx_type); - nm_assert(idx_type->parent.klass == &_dedup_multi_idx_type_class); - nm_assert(obj_a); - nm_assert(NMP_OBJECT_GET_TYPE(obj_a) != NMP_OBJECT_TYPE_UNKNOWN); - nm_assert(!obj_b || (NMP_OBJECT_GET_TYPE(obj_b) != NMP_OBJECT_TYPE_UNKNOWN)); - nm_assert(!h || !obj_b); - - switch (idx_type->cache_id_type) { - case NMP_CACHE_ID_TYPE_OBJECT_TYPE: - if (obj_b) - return NMP_OBJECT_GET_TYPE(obj_a) == NMP_OBJECT_GET_TYPE(obj_b); - if (h) { - nm_hash_update_vals(h, idx_type->cache_id_type, NMP_OBJECT_GET_TYPE(obj_a)); - } - return 1; - - case NMP_CACHE_ID_TYPE_LINK_BY_IFNAME: - if (NMP_OBJECT_GET_TYPE(obj_a) != NMP_OBJECT_TYPE_LINK) { - /* first check, whether obj_a is suitable for this idx_type. - * If not, return 0 (which is correct for partitionable(), hash() and equal() - * functions. */ - if (h) - nm_hash_update_val(h, obj_a); - return 0; - } - if (obj_b) { - /* we are in equal() mode. Compare obj_b with obj_a. */ - return NMP_OBJECT_GET_TYPE(obj_b) == NMP_OBJECT_TYPE_LINK - && nm_streq(obj_a->link.name, obj_b->link.name); - } - if (h) { - nm_hash_update_val(h, idx_type->cache_id_type); - nm_hash_update_strarr(h, obj_a->link.name); - } - /* just return 1, to indicate that obj_a is partitionable by this idx_type. */ - return 1; - - case NMP_CACHE_ID_TYPE_DEFAULT_ROUTES: - if (!NM_IN_SET(NMP_OBJECT_GET_TYPE(obj_a), - NMP_OBJECT_TYPE_IP4_ROUTE, - NMP_OBJECT_TYPE_IP6_ROUTE) - || !NM_PLATFORM_IP_ROUTE_IS_DEFAULT(&obj_a->ip_route) - || !nmp_object_is_visible(obj_a)) { - if (h) - nm_hash_update_val(h, obj_a); - return 0; - } - if (obj_b) { - return NMP_OBJECT_GET_TYPE(obj_a) == NMP_OBJECT_GET_TYPE(obj_b) - && NM_PLATFORM_IP_ROUTE_IS_DEFAULT(&obj_b->ip_route) - && nmp_object_is_visible(obj_b); - } - if (h) { - nm_hash_update_vals(h, idx_type->cache_id_type, NMP_OBJECT_GET_TYPE(obj_a)); - } - return 1; - - case NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX: - if (!NM_IN_SET(NMP_OBJECT_GET_TYPE(obj_a), - NMP_OBJECT_TYPE_IP4_ADDRESS, - NMP_OBJECT_TYPE_IP6_ADDRESS, - NMP_OBJECT_TYPE_IP4_ROUTE, - NMP_OBJECT_TYPE_IP6_ROUTE, - NMP_OBJECT_TYPE_QDISC, - NMP_OBJECT_TYPE_TFILTER) - || !nmp_object_is_visible(obj_a)) { - if (h) - nm_hash_update_val(h, obj_a); - return 0; - } - nm_assert(NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj_a)->ifindex > 0); - if (obj_b) { - return NMP_OBJECT_GET_TYPE(obj_a) == NMP_OBJECT_GET_TYPE(obj_b) - && NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj_a)->ifindex - == NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj_b)->ifindex - && nmp_object_is_visible(obj_b); - } - if (h) { - nm_hash_update_vals(h, idx_type->cache_id_type, obj_a->obj_with_ifindex.ifindex); - } - return 1; - - case NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID: - obj_type = NMP_OBJECT_GET_TYPE(obj_a); - if (!NM_IN_SET(obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE) - || NMP_OBJECT_CAST_IP_ROUTE(obj_a)->ifindex <= 0) { - if (h) - nm_hash_update_val(h, obj_a); - return 0; - } - if (obj_b) { - return obj_type == NMP_OBJECT_GET_TYPE(obj_b) - && NMP_OBJECT_CAST_IP_ROUTE(obj_b)->ifindex > 0 - && (obj_type == NMP_OBJECT_TYPE_IP4_ROUTE - ? (nm_platform_ip4_route_cmp(&obj_a->ip4_route, - &obj_b->ip4_route, - NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID) - == 0) - : (nm_platform_ip6_route_cmp(&obj_a->ip6_route, - &obj_b->ip6_route, - NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID) - == 0)); - } - if (h) { - nm_hash_update_val(h, idx_type->cache_id_type); - if (obj_type == NMP_OBJECT_TYPE_IP4_ROUTE) - nm_platform_ip4_route_hash_update(&obj_a->ip4_route, - NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID, - h); - else - nm_platform_ip6_route_hash_update(&obj_a->ip6_route, - NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID, - h); - } - return 1; - - case NMP_CACHE_ID_TYPE_OBJECT_BY_ADDR_FAMILY: - obj_type = NMP_OBJECT_GET_TYPE(obj_a); - /* currently, only routing rules are supported for this cache-id-type. */ - if (obj_type != NMP_OBJECT_TYPE_ROUTING_RULE - || !NM_IN_SET(obj_a->routing_rule.addr_family, AF_INET, AF_INET6)) { - if (h) - nm_hash_update_val(h, obj_a); - return 0; - } - if (obj_b) { - return NMP_OBJECT_GET_TYPE(obj_b) == NMP_OBJECT_TYPE_ROUTING_RULE - && obj_a->routing_rule.addr_family == obj_b->routing_rule.addr_family; - } - if (h) { - nm_hash_update_vals(h, idx_type->cache_id_type, obj_a->routing_rule.addr_family); - } - return 1; - - case NMP_CACHE_ID_TYPE_NONE: - case __NMP_CACHE_ID_TYPE_MAX: - break; - } - nm_assert_not_reached(); - return 0; -} - -static gboolean -_idx_obj_partitionable(const NMDedupMultiIdxType *idx_type, const NMDedupMultiObj *obj) -{ - return _idx_obj_part((DedupMultiIdxType *) idx_type, (NMPObject *) obj, NULL, NULL) != 0; -} - -static void -_idx_obj_partition_hash_update(const NMDedupMultiIdxType *idx_type, - const NMDedupMultiObj * obj, - NMHashState * h) -{ - _idx_obj_part((DedupMultiIdxType *) idx_type, (NMPObject *) obj, NULL, h); -} - -static gboolean -_idx_obj_partition_equal(const NMDedupMultiIdxType *idx_type, - const NMDedupMultiObj * obj_a, - const NMDedupMultiObj * obj_b) -{ - return _idx_obj_part((DedupMultiIdxType *) idx_type, - (NMPObject *) obj_a, - (NMPObject *) obj_b, - NULL); -} - -static const NMDedupMultiIdxTypeClass _dedup_multi_idx_type_class = { - .idx_obj_id_hash_update = _idx_obj_id_hash_update, - .idx_obj_id_equal = _idx_obj_id_equal, - .idx_obj_partitionable = _idx_obj_partitionable, - .idx_obj_partition_hash_update = _idx_obj_partition_hash_update, - .idx_obj_partition_equal = _idx_obj_partition_equal, -}; - -static void -_dedup_multi_idx_type_init(DedupMultiIdxType *idx_type, NMPCacheIdType cache_id_type) -{ - nm_dedup_multi_idx_type_init((NMDedupMultiIdxType *) idx_type, &_dedup_multi_idx_type_class); - idx_type->cache_id_type = cache_id_type; -} - -/*****************************************************************************/ - -static void -_vlan_xgress_qos_mappings_hash_update(guint n_map, const NMVlanQosMapping *map, NMHashState *h) -{ - /* ensure no padding. */ - G_STATIC_ASSERT(sizeof(NMVlanQosMapping) == 2 * sizeof(guint32)); - - nm_hash_update_val(h, n_map); - if (n_map) - nm_hash_update(h, map, n_map * sizeof(*map)); -} - -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, - NMVlanQosMapping ** dst_map, - guint src_n_map, - const NMVlanQosMapping *src_map) -{ - if (src_n_map == 0) { - nm_clear_g_free(dst_map); - *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) { - nm_clear_g_free(dst_map); - *dst_n_map = src_n_map; - if (src_n_map > 0) - *dst_map = nm_memdup(src_map, sizeof(*src_map) * src_n_map); - } -} - -/*****************************************************************************/ - -static void -_wireguard_allowed_ip_hash_update(const NMPWireGuardAllowedIP *ip, NMHashState *h) -{ - nm_hash_update_vals(h, ip->family, ip->mask); - - if (ip->family == AF_INET) - nm_hash_update_val(h, ip->addr.addr4); - else if (ip->family == AF_INET6) - nm_hash_update_val(h, ip->addr.addr6); -} - -static int -_wireguard_allowed_ip_cmp(const NMPWireGuardAllowedIP *a, const NMPWireGuardAllowedIP *b) -{ - NM_CMP_SELF(a, b); - - NM_CMP_FIELD(a, b, family); - NM_CMP_FIELD(a, b, mask); - - if (a->family == AF_INET) - NM_CMP_FIELD(a, b, addr.addr4); - else if (a->family == AF_INET6) - NM_CMP_FIELD_IN6ADDR(a, b, addr.addr6); - - return 0; -} - -static void -_wireguard_peer_hash_update(const NMPWireGuardPeer *peer, NMHashState *h) -{ - guint i; - - nm_hash_update(h, peer->public_key, sizeof(peer->public_key)); - nm_hash_update(h, peer->preshared_key, sizeof(peer->preshared_key)); - nm_hash_update_vals(h, - peer->persistent_keepalive_interval, - peer->allowed_ips_len, - peer->rx_bytes, - peer->tx_bytes, - peer->last_handshake_time.tv_sec, - peer->last_handshake_time.tv_nsec); - - nm_sock_addr_union_hash_update(&peer->endpoint, h); - - for (i = 0; i < peer->allowed_ips_len; i++) - _wireguard_allowed_ip_hash_update(&peer->allowed_ips[i], h); -} - -static int -_wireguard_peer_cmp(const NMPWireGuardPeer *a, const NMPWireGuardPeer *b) -{ - guint i; - - NM_CMP_SELF(a, b); - - NM_CMP_FIELD(a, b, last_handshake_time.tv_sec); - NM_CMP_FIELD(a, b, last_handshake_time.tv_nsec); - NM_CMP_FIELD(a, b, rx_bytes); - NM_CMP_FIELD(a, b, tx_bytes); - NM_CMP_FIELD(a, b, allowed_ips_len); - NM_CMP_FIELD(a, b, persistent_keepalive_interval); - NM_CMP_FIELD(a, b, endpoint.sa.sa_family); - NM_CMP_FIELD_MEMCMP(a, b, public_key); - NM_CMP_FIELD_MEMCMP(a, b, preshared_key); - - NM_CMP_RETURN(nm_sock_addr_union_cmp(&a->endpoint, &b->endpoint)); - - for (i = 0; i < a->allowed_ips_len; i++) { - NM_CMP_RETURN(_wireguard_allowed_ip_cmp(&a->allowed_ips[i], &b->allowed_ips[i])); - } - - return 0; -} - -/*****************************************************************************/ - -static const char * -_link_get_driver(struct udev_device *udevice, const char *kind, int ifindex) -{ - const char *driver = NULL; - - nm_assert(kind == g_intern_string(kind)); - - if (udevice) { - driver = nmp_utils_udev_get_driver(udevice); - if (driver) - return driver; - } - - if (kind) - return kind; - - if (ifindex > 0) { - NMPUtilsEthtoolDriverInfo driver_info; - - if (nmp_utils_ethtool_get_driver_info(ifindex, &driver_info)) { - if (driver_info.driver[0]) - return g_intern_string(driver_info.driver); - } - } - - return "unknown"; -} - -void -_nmp_object_fixup_link_udev_fields(NMPObject **obj_new, NMPObject *obj_orig, gboolean use_udev) -{ - const char *driver = NULL; - gboolean initialized = FALSE; - NMPObject * obj; - - nm_assert(obj_orig || *obj_new); - nm_assert(obj_new); - nm_assert(!obj_orig || NMP_OBJECT_GET_TYPE(obj_orig) == NMP_OBJECT_TYPE_LINK); - nm_assert(!*obj_new || NMP_OBJECT_GET_TYPE(*obj_new) == NMP_OBJECT_TYPE_LINK); - - obj = *obj_new ?: obj_orig; - - /* The link contains internal fields that are combined by - * properties from netlink and udev. Update those properties */ - - /* When a link is not in netlink, its udev fields don't matter. */ - if (obj->_link.netlink.is_in_netlink) { - driver = _link_get_driver(obj->_link.udev.device, obj->link.kind, obj->link.ifindex); - if (obj->_link.udev.device) - initialized = TRUE; - else if (!use_udev) { - /* If we don't use udev, we immediately mark the link as initialized. - * - * For that, we consult @use_udev argument, that is cached via - * nmp_cache_use_udev_get(). It is on purpose not to test - * for a writable /sys on every call. A minor reason for that is - * performance, but the real reason is reproducibility. - * */ - initialized = TRUE; - } - } - - if (nm_streq0(obj->link.driver, driver) && obj->link.initialized == initialized) - return; - - if (!*obj_new) - obj = *obj_new = nmp_object_clone(obj, FALSE); - - obj->link.driver = driver; - obj->link.initialized = initialized; -} - -static void -_nmp_object_fixup_link_master_connected(NMPObject ** obj_new, - NMPObject * obj_orig, - const NMPCache *cache) -{ - NMPObject *obj; - - nm_assert(obj_orig || *obj_new); - nm_assert(obj_new); - nm_assert(!obj_orig || NMP_OBJECT_GET_TYPE(obj_orig) == NMP_OBJECT_TYPE_LINK); - nm_assert(!*obj_new || NMP_OBJECT_GET_TYPE(*obj_new) == NMP_OBJECT_TYPE_LINK); - - obj = *obj_new ?: obj_orig; - - if (nmp_cache_link_connected_needs_toggle(cache, obj, NULL, NULL)) { - if (!*obj_new) - obj = *obj_new = nmp_object_clone(obj, FALSE); - obj->link.connected = !obj->link.connected; - } -} - -/*****************************************************************************/ - -static void -_vt_cmd_obj_dispose_link(NMPObject *obj) -{ - if (obj->_link.udev.device) { - udev_device_unref(obj->_link.udev.device); - obj->_link.udev.device = NULL; - } - g_clear_object(&obj->_link.ext_data); - 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 void -_wireguard_clear(NMPObjectLnkWireGuard *lnk) -{ - guint i; - - nm_explicit_bzero(lnk->_public.private_key, sizeof(lnk->_public.private_key)); - for (i = 0; i < lnk->peers_len; i++) { - NMPWireGuardPeer *peer = (NMPWireGuardPeer *) &lnk->peers[i]; - - nm_explicit_bzero(peer->preshared_key, sizeof(peer->preshared_key)); - } - g_free((gpointer) lnk->peers); - g_free((gpointer) lnk->_allowed_ips_buf); -} - -static void -_vt_cmd_obj_dispose_lnk_wireguard(NMPObject *obj) -{ - _wireguard_clear(&obj->_lnk_wireguard); -} - -static NMPObject * -_nmp_object_new_from_class(const NMPClass *klass) -{ - NMPObject *obj; - - nm_assert(klass); - nm_assert(klass->sizeof_data > 0); - nm_assert(klass->sizeof_public > 0 && klass->sizeof_public <= klass->sizeof_data); - - obj = g_slice_alloc0(klass->sizeof_data + G_STRUCT_OFFSET(NMPObject, object)); - obj->_class = klass; - obj->parent._ref_count = 1; - return obj; -} - -NMPObject * -nmp_object_new(NMPObjectType obj_type, gconstpointer plobj) -{ - const NMPClass *klass = nmp_class_from_type(obj_type); - NMPObject * obj; - - obj = _nmp_object_new_from_class(klass); - if (plobj) - memcpy(&obj->object, plobj, klass->sizeof_public); - return obj; -} - -NMPObject * -nmp_object_new_link(int ifindex) -{ - NMPObject *obj; - - obj = nmp_object_new(NMP_OBJECT_TYPE_LINK, NULL); - obj->link.ifindex = ifindex; - return obj; -} - -/*****************************************************************************/ - -static void -_nmp_object_stackinit_from_class(NMPObject *obj, const NMPClass *klass) -{ - nm_assert(obj); - nm_assert(klass); - - *obj = (NMPObject){ - .parent = - { - .klass = (const NMDedupMultiObjClass *) klass, - ._ref_count = NM_OBJ_REF_COUNT_STACKINIT, - }, - }; -} - -static NMPObject * -_nmp_object_stackinit_from_type(NMPObject *obj, NMPObjectType obj_type) -{ - const NMPClass *klass; - - nm_assert(obj); - klass = nmp_class_from_type(obj_type); - nm_assert(klass); - - *obj = (NMPObject){ - .parent = - { - .klass = (const NMDedupMultiObjClass *) klass, - ._ref_count = NM_OBJ_REF_COUNT_STACKINIT, - }, - }; - return obj; -} - -const NMPObject * -nmp_object_stackinit(NMPObject *obj, NMPObjectType obj_type, gconstpointer plobj) -{ - const NMPClass *klass = nmp_class_from_type(obj_type); - - _nmp_object_stackinit_from_class(obj, klass); - if (plobj) - memcpy(&obj->object, plobj, klass->sizeof_public); - return obj; -} - -const NMPObject * -nmp_object_stackinit_id(NMPObject *obj, const NMPObject *src) -{ - const NMPClass *klass; - - nm_assert(NMP_OBJECT_IS_VALID(src)); - nm_assert(obj); - - klass = NMP_OBJECT_GET_CLASS(src); - _nmp_object_stackinit_from_class(obj, klass); - if (klass->cmd_plobj_id_copy) - klass->cmd_plobj_id_copy(&obj->object, &src->object); - return obj; -} - -const NMPObject * -nmp_object_stackinit_id_link(NMPObject *obj, int ifindex) -{ - _nmp_object_stackinit_from_type(obj, NMP_OBJECT_TYPE_LINK); - obj->link.ifindex = ifindex; - return obj; -} - -const NMPObject * -nmp_object_stackinit_id_ip4_address(NMPObject *obj, - int ifindex, - guint32 address, - guint8 plen, - guint32 peer_address) -{ - _nmp_object_stackinit_from_type(obj, NMP_OBJECT_TYPE_IP4_ADDRESS); - obj->ip4_address.ifindex = ifindex; - obj->ip4_address.address = address; - obj->ip4_address.plen = plen; - obj->ip4_address.peer_address = peer_address; - return obj; -} - -const NMPObject * -nmp_object_stackinit_id_ip6_address(NMPObject *obj, int ifindex, const struct in6_addr *address) -{ - _nmp_object_stackinit_from_type(obj, NMP_OBJECT_TYPE_IP6_ADDRESS); - obj->ip4_address.ifindex = ifindex; - if (address) - obj->ip6_address.address = *address; - return obj; -} - -/*****************************************************************************/ - -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_utils_to_string_buffer)]; - - 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_snprintf( - buf, - buf_size, - "[%s,%p,%u,%calive,%cvisible; %s]", - klass->obj_type_name, - obj, - obj->parent._ref_count, - 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"); - } -} - -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 * b = buf; - - 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: - nm_utils_strbuf_append(&b, - &buf_size, - "[%s,%p,%u,%calive,%cvisible,%cin-nl,%p; ", - klass->obj_type_name, - obj, - obj->parent._ref_count, - nmp_object_is_alive(obj) ? '+' : '-', - nmp_object_is_visible(obj) ? '+' : '-', - obj->_link.netlink.is_in_netlink ? '+' : '-', - obj->_link.udev.device); - NMP_OBJECT_GET_CLASS(obj)->cmd_plobj_to_string(&obj->object, b, buf_size); - nm_utils_strbuf_seek_end(&b, &buf_size); - if (obj->_link.netlink.lnk) { - nm_utils_strbuf_append_str(&b, &buf_size, "; "); - nmp_object_to_string(obj->_link.netlink.lnk, NMP_OBJECT_TO_STRING_ALL, b, buf_size); - nm_utils_strbuf_seek_end(&b, &buf_size); - } - nm_utils_strbuf_append_c(&b, &buf_size, ']'); - return buf; - case NMP_OBJECT_TO_STRING_PUBLIC: - NMP_OBJECT_GET_CLASS(obj)->cmd_plobj_to_string(&obj->object, b, buf_size); - if (obj->_link.netlink.lnk) { - nm_utils_strbuf_seek_end(&b, &buf_size); - nm_utils_strbuf_append_str(&b, &buf_size, "; "); - nmp_object_to_string(obj->_link.netlink.lnk, NMP_OBJECT_TO_STRING_PUBLIC, b, 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; - 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,%u,%calive,%cvisible; %s]", - klass->obj_type_name, - obj, - obj->parent._ref_count, - nmp_object_is_alive(obj) ? '+' : '-', - nmp_object_is_visible(obj) ? '+' : '-', - nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, 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); - - 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"); - } -} - -static const char * -_vt_cmd_obj_to_string_lnk_wireguard(const NMPObject * obj, - NMPObjectToStringMode to_string_mode, - char * buf, - gsize buf_size) -{ - const NMPClass *klass; - char buf2[sizeof(_nm_utils_to_string_buffer)]; - char * b; - guint i; - - 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: - b = buf; - - nm_utils_strbuf_append( - &b, - &buf_size, - "[%s,%p,%u,%calive,%cvisible; %s" - "%s", - klass->obj_type_name, - obj, - obj->parent._ref_count, - nmp_object_is_alive(obj) ? '+' : '-', - nmp_object_is_visible(obj) ? '+' : '-', - nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_PUBLIC, buf2, sizeof(buf2)), - obj->_lnk_wireguard.peers_len > 0 ? " peers {" : ""); - - for (i = 0; i < obj->_lnk_wireguard.peers_len; i++) { - const NMPWireGuardPeer *peer = &obj->_lnk_wireguard.peers[i]; - - nm_utils_strbuf_append_str(&b, &buf_size, " { "); - nm_platform_wireguard_peer_to_string(peer, b, buf_size); - nm_utils_strbuf_seek_end(&b, &buf_size); - nm_utils_strbuf_append_str(&b, &buf_size, " }"); - } - if (obj->_lnk_wireguard.peers_len) - nm_utils_strbuf_append_str(&b, &buf_size, " }"); - - 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"); - } -} - -#define _vt_cmd_plobj_to_string_id(type, plat_type, ...) \ - static const char *_vt_cmd_plobj_to_string_id_##type(const NMPlatformObject *_obj, \ - char * buf, \ - gsize buf_len) \ - { \ - plat_type *const obj = (plat_type *) _obj; \ - _nm_unused char buf1[NM_UTILS_INET_ADDRSTRLEN]; \ - _nm_unused char buf2[NM_UTILS_INET_ADDRSTRLEN]; \ - \ - g_snprintf(buf, buf_len, __VA_ARGS__); \ - return buf; \ - } \ - _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON - -_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( - nm_utils_ip4_address_clear_host_address(obj->peer_address, - 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(qdisc, NMPlatformQdisc, "%d: %d", obj->ifindex, obj->parent); - -_vt_cmd_plobj_to_string_id(tfilter, NMPlatformTfilter, "%d: %d", obj->ifindex, obj->parent); - -void -nmp_object_hash_update(const NMPObject *obj, NMHashState *h) -{ - const NMPClass *klass; - - g_return_if_fail(NMP_OBJECT_IS_VALID(obj)); - - klass = NMP_OBJECT_GET_CLASS(obj); - - nm_hash_update_val(h, klass->obj_type); - if (klass->cmd_obj_hash_update) - klass->cmd_obj_hash_update(obj, h); - else if (klass->cmd_plobj_hash_update) - klass->cmd_plobj_hash_update(&obj->object, h); - else - nm_hash_update_val(h, obj); -} - -static void -_vt_cmd_obj_hash_update_link(const NMPObject *obj, NMHashState *h) -{ - nm_assert(NMP_OBJECT_GET_TYPE(obj) == NMP_OBJECT_TYPE_LINK); - - nm_platform_link_hash_update(&obj->link, h); - nm_hash_update_vals(h, - obj->_link.netlink.is_in_netlink, - obj->_link.wireguard_family_id, - obj->_link.udev.device); - if (obj->_link.netlink.lnk) - nmp_object_hash_update(obj->_link.netlink.lnk, h); -} - -static void -_vt_cmd_obj_hash_update_lnk_vlan(const NMPObject *obj, NMHashState *h) -{ - nm_assert(NMP_OBJECT_GET_TYPE(obj) == NMP_OBJECT_TYPE_LNK_VLAN); - - nm_platform_lnk_vlan_hash_update(&obj->lnk_vlan, h); - _vlan_xgress_qos_mappings_hash_update(obj->_lnk_vlan.n_ingress_qos_map, - obj->_lnk_vlan.ingress_qos_map, - h); - _vlan_xgress_qos_mappings_hash_update(obj->_lnk_vlan.n_egress_qos_map, - obj->_lnk_vlan.egress_qos_map, - h); -} - -static void -_vt_cmd_obj_hash_update_lnk_wireguard(const NMPObject *obj, NMHashState *h) -{ - guint i; - - nm_assert(NMP_OBJECT_GET_TYPE(obj) == NMP_OBJECT_TYPE_LNK_WIREGUARD); - - nm_platform_lnk_wireguard_hash_update(&obj->lnk_wireguard, h); - - nm_hash_update_val(h, obj->_lnk_wireguard.peers_len); - for (i = 0; i < obj->_lnk_wireguard.peers_len; i++) - _wireguard_peer_hash_update(&obj->_lnk_wireguard.peers[i], h); -} - -int -nmp_object_cmp(const NMPObject *obj1, const NMPObject *obj2) -{ - const NMPClass *klass1, *klass2; - - NM_CMP_SELF(obj1, obj2); - - g_return_val_if_fail(NMP_OBJECT_IS_VALID(obj1), -1); - g_return_val_if_fail(NMP_OBJECT_IS_VALID(obj2), 1); - - klass1 = NMP_OBJECT_GET_CLASS(obj1); - klass2 = NMP_OBJECT_GET_CLASS(obj2); - - if (klass1 != klass2) { - nm_assert(klass1->obj_type != klass2->obj_type); - return klass1->obj_type < klass2->obj_type ? -1 : 1; - } - - if (klass1->cmd_obj_cmp) - return klass1->cmd_obj_cmp(obj1, obj2); - return klass1->cmd_plobj_cmp(&obj1->object, &obj2->object); -} - -static int -_vt_cmd_obj_cmp_link(const NMPObject *obj1, const NMPObject *obj2) -{ - NM_CMP_RETURN(nm_platform_link_cmp(&obj1->link, &obj2->link)); - NM_CMP_DIRECT(obj1->_link.netlink.is_in_netlink, obj2->_link.netlink.is_in_netlink); - NM_CMP_RETURN(nmp_object_cmp(obj1->_link.netlink.lnk, obj2->_link.netlink.lnk)); - NM_CMP_DIRECT(obj1->_link.wireguard_family_id, obj2->_link.wireguard_family_id); - - 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. - * - * Have this check as very last. */ - return (obj1->_link.udev.device < obj2->_link.udev.device) ? -1 : 1; - } - - return 0; -} - -static int -_vt_cmd_obj_cmp_lnk_vlan(const NMPObject *obj1, const NMPObject *obj2) -{ - int c; - - c = nm_platform_lnk_vlan_cmp(&obj1->lnk_vlan, &obj2->lnk_vlan); - if (c) - return c; - - 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; - - 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); - - return c; -} - -static int -_vt_cmd_obj_cmp_lnk_wireguard(const NMPObject *obj1, const NMPObject *obj2) -{ - guint i; - - NM_CMP_RETURN(nm_platform_lnk_wireguard_cmp(&obj1->lnk_wireguard, &obj2->lnk_wireguard)); - - NM_CMP_FIELD(obj1, obj2, _lnk_wireguard.peers_len); - - for (i = 0; i < obj1->_lnk_wireguard.peers_len; i++) - NM_CMP_RETURN( - _wireguard_peer_cmp(&obj1->_lnk_wireguard.peers[i], &obj2->_lnk_wireguard.peers[i])); - - return 0; -} - -/* @src is a const object, which is not entirely correct for link types, where - * we increase the ref count for src->_link.udev.device. - * Hence, nmp_object_copy() can violate the const promise of @src. - * */ -void -nmp_object_copy(NMPObject *dst, const NMPObject *src, gboolean id_only) -{ - g_return_if_fail(NMP_OBJECT_IS_VALID(dst)); - g_return_if_fail(NMP_OBJECT_IS_VALID(src)); - g_return_if_fail(!NMP_OBJECT_IS_STACKINIT(dst)); - - if (src != dst) { - const NMPClass *klass = NMP_OBJECT_GET_CLASS(dst); - - g_return_if_fail(klass == NMP_OBJECT_GET_CLASS(src)); - - 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) - udev_device_ref(src->_link.udev.device); - if (dst->_link.udev.device) - udev_device_unref(dst->_link.udev.device); - dst->_link.udev.device = src->_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.netlink.lnk = src->_link.netlink.lnk; - } - if (dst->_link.ext_data != src->_link.ext_data) { - if (dst->_link.ext_data) - g_clear_object(&dst->_link.ext_data); - if (src->_link.ext_data) - dst->_link.ext_data = g_object_ref(src->_link.ext_data); - } - 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, - NM_UNCONST_PPTR(NMVlanQosMapping, &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, - NM_UNCONST_PPTR(NMVlanQosMapping, &dst->_lnk_vlan.egress_qos_map), - src->_lnk_vlan.n_egress_qos_map, - src->_lnk_vlan.egress_qos_map); -} - -static void -_vt_cmd_obj_copy_lnk_wireguard(NMPObject *dst, const NMPObject *src) -{ - guint i; - - nm_assert(dst != src); - - _wireguard_clear(&dst->_lnk_wireguard); - - dst->_lnk_wireguard = src->_lnk_wireguard; - - dst->_lnk_wireguard.peers = nm_memdup(dst->_lnk_wireguard.peers, - sizeof(NMPWireGuardPeer) * dst->_lnk_wireguard.peers_len); - dst->_lnk_wireguard._allowed_ips_buf = - nm_memdup(dst->_lnk_wireguard._allowed_ips_buf, - sizeof(NMPWireGuardAllowedIP) * dst->_lnk_wireguard._allowed_ips_buf_len); - - /* all the peers' pointers point into the buffer. They need to be readjusted. */ - for (i = 0; i < dst->_lnk_wireguard.peers_len; i++) { - NMPWireGuardPeer *peer = (NMPWireGuardPeer *) &dst->_lnk_wireguard.peers[i]; - - if (peer->allowed_ips_len == 0) { - nm_assert(!peer->allowed_ips); - continue; - } - nm_assert(dst->_lnk_wireguard._allowed_ips_buf_len > 0); - nm_assert(src->_lnk_wireguard._allowed_ips_buf); - nm_assert(peer->allowed_ips >= src->_lnk_wireguard._allowed_ips_buf); - nm_assert( - &peer->allowed_ips[peer->allowed_ips_len] - <= &src->_lnk_wireguard._allowed_ips_buf[src->_lnk_wireguard._allowed_ips_buf_len]); - - peer->allowed_ips = - &dst->_lnk_wireguard - ._allowed_ips_buf[peer->allowed_ips - src->_lnk_wireguard._allowed_ips_buf]; - } - - nm_assert(nmp_object_equal(src, dst)); -} - -#define _vt_cmd_plobj_id_copy(type, plat_type, cmd) \ - static void _vt_cmd_plobj_id_copy_##type(NMPlatformObject *_dst, const NMPlatformObject *_src) \ - { \ - plat_type *const dst = (plat_type *) _dst; \ - const plat_type *const src = (const plat_type *) _src; \ - { \ - cmd \ - } \ - } \ - _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON - -_vt_cmd_plobj_id_copy(link, NMPlatformLink, { dst->ifindex = src->ifindex; }); - -_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->address = src->address; -}); - -_vt_cmd_plobj_id_copy(ip4_route, NMPlatformIP4Route, { - *dst = *src; - nm_assert(nm_platform_ip4_route_cmp(dst, src, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) == 0); -}); - -_vt_cmd_plobj_id_copy(ip6_route, NMPlatformIP6Route, { - *dst = *src; - nm_assert(nm_platform_ip6_route_cmp(dst, src, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) == 0); -}); - -_vt_cmd_plobj_id_copy(routing_rule, NMPlatformRoutingRule, { - *dst = *src; - nm_assert(nm_platform_routing_rule_cmp(dst, src, NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID) == 0); -}); - -/* Uses internally nmp_object_copy(), hence it also violates the const - * promise for @obj. - * */ -NMPObject * -nmp_object_clone(const NMPObject *obj, gboolean id_only) -{ - NMPObject *dst; - - if (!obj) - return NULL; - - g_return_val_if_fail(NMP_OBJECT_IS_VALID(obj), NULL); - - dst = _nmp_object_new_from_class(NMP_OBJECT_GET_CLASS(obj)); - nmp_object_copy(dst, obj, id_only); - return dst; -} - -int -nmp_object_id_cmp(const NMPObject *obj1, const NMPObject *obj2) -{ - const NMPClass *klass, *klass2; - - NM_CMP_SELF(obj1, obj2); - - g_return_val_if_fail(NMP_OBJECT_IS_VALID(obj1), FALSE); - g_return_val_if_fail(NMP_OBJECT_IS_VALID(obj2), FALSE); - - klass = NMP_OBJECT_GET_CLASS(obj1); - nm_assert(!klass->cmd_plobj_id_hash_update == !klass->cmd_plobj_id_cmp); - - klass2 = NMP_OBJECT_GET_CLASS(obj2); - nm_assert(klass); - if (klass != klass2) { - nm_assert(klass2); - NM_CMP_DIRECT(klass->obj_type, klass2->obj_type); - /* resort to pointer comparison */ - NM_CMP_DIRECT_PTR(klass, klass2); - return 0; - } - - if (!klass->cmd_plobj_id_cmp) { - /* the klass doesn't implement ID cmp(). That means, different objects - * never compare equal, but the cmp() according to their pointer value. */ - NM_CMP_DIRECT_PTR(obj1, obj2); - return 0; - } - - return klass->cmd_plobj_id_cmp(&obj1->object, &obj2->object); -} - -#define _vt_cmd_plobj_id_cmp(type, plat_type, cmd) \ - static int _vt_cmd_plobj_id_cmp_##type(const NMPlatformObject *_obj1, \ - const NMPlatformObject *_obj2) \ - { \ - const plat_type *const obj1 = (const plat_type *) _obj1; \ - const plat_type *const obj2 = (const plat_type *) _obj2; \ - \ - NM_CMP_SELF(obj1, obj2); \ - { \ - cmd; \ - } \ - return 0; \ - } \ - _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON - -_vt_cmd_plobj_id_cmp(link, NMPlatformLink, { NM_CMP_FIELD(obj1, obj2, ifindex); }); - -_vt_cmd_plobj_id_cmp(ip4_address, NMPlatformIP4Address, { - NM_CMP_FIELD(obj1, obj2, ifindex); - NM_CMP_FIELD(obj1, obj2, plen); - NM_CMP_FIELD(obj1, obj2, address); - /* for IPv4 addresses, you can add the same local address with differing peer-address - * (IFA_ADDRESS), provided that their net-part differs. */ - NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX(obj1->peer_address, obj2->peer_address, obj1->plen); -}); - -_vt_cmd_plobj_id_cmp(ip6_address, NMPlatformIP6Address, { - NM_CMP_FIELD(obj1, obj2, ifindex); - /* for IPv6 addresses, the prefix length is not part of the primary identifier. */ - NM_CMP_FIELD_IN6ADDR(obj1, obj2, address); -}); - -_vt_cmd_plobj_id_cmp(qdisc, NMPlatformQdisc, { - NM_CMP_FIELD(obj1, obj2, ifindex); - NM_CMP_FIELD(obj1, obj2, parent); -}); - -_vt_cmd_plobj_id_cmp(tfilter, NMPlatformTfilter, { - NM_CMP_FIELD(obj1, obj2, ifindex); - NM_CMP_FIELD(obj1, obj2, handle); -}); - -static int -_vt_cmd_plobj_id_cmp_ip4_route(const NMPlatformObject *obj1, const NMPlatformObject *obj2) -{ - return nm_platform_ip4_route_cmp((NMPlatformIP4Route *) obj1, - (NMPlatformIP4Route *) obj2, - NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID); -} - -static int -_vt_cmd_plobj_id_cmp_ip6_route(const NMPlatformObject *obj1, const NMPlatformObject *obj2) -{ - return nm_platform_ip6_route_cmp((NMPlatformIP6Route *) obj1, - (NMPlatformIP6Route *) obj2, - NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID); -} - -static int -_vt_cmd_plobj_id_cmp_routing_rule(const NMPlatformObject *obj1, const NMPlatformObject *obj2) -{ - return nm_platform_routing_rule_cmp((NMPlatformRoutingRule *) obj1, - (NMPlatformRoutingRule *) obj2, - NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID); -} - -void -nmp_object_id_hash_update(const NMPObject *obj, NMHashState *h) -{ - const NMPClass *klass; - - g_return_if_fail(NMP_OBJECT_IS_VALID(obj)); - - klass = NMP_OBJECT_GET_CLASS(obj); - - nm_assert(!klass->cmd_plobj_id_hash_update == !klass->cmd_plobj_id_cmp); - - if (!klass->cmd_plobj_id_hash_update) { - /* The klass doesn't implement ID compare. It means, to use pointer - * equality. */ - nm_hash_update_val(h, obj); - return; - } - - nm_hash_update_val(h, klass->obj_type); - klass->cmd_plobj_id_hash_update(&obj->object, h); -} - -guint -nmp_object_id_hash(const NMPObject *obj) -{ - NMHashState h; - - if (!obj) - return nm_hash_static(914932607u); - - nm_hash_init(&h, 914932607u); - nmp_object_id_hash_update(obj, &h); - return nm_hash_complete(&h); -} - -#define _vt_cmd_plobj_id_hash_update(type, plat_type, cmd) \ - static void _vt_cmd_plobj_id_hash_update_##type(const NMPlatformObject *_obj, NMHashState *h) \ - { \ - const plat_type *const obj = (const plat_type *) _obj; \ - { \ - cmd; \ - } \ - } \ - _NM_DUMMY_STRUCT_FOR_TRAILING_SEMICOLON - -_vt_cmd_plobj_id_hash_update(link, NMPlatformLink, { nm_hash_update_val(h, obj->ifindex); }); - -_vt_cmd_plobj_id_hash_update(ip4_address, NMPlatformIP4Address, { - nm_hash_update_vals( - h, - obj->ifindex, - obj->plen, - obj->address, - /* for IPv4 we must also consider the net-part of the peer-address (IFA_ADDRESS) */ - nm_utils_ip4_address_clear_host_address(obj->peer_address, obj->plen)); -}); - -_vt_cmd_plobj_id_hash_update(ip6_address, NMPlatformIP6Address, { - nm_hash_update_vals( - h, - obj->ifindex, - /* for IPv6 addresses, the prefix length is not part of the primary identifier. */ - obj->address); -}); - -_vt_cmd_plobj_id_hash_update(ip4_route, NMPlatformIP4Route, { - nm_platform_ip4_route_hash_update(obj, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID, h); -}); - -_vt_cmd_plobj_id_hash_update(ip6_route, NMPlatformIP6Route, { - nm_platform_ip6_route_hash_update(obj, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID, h); -}); - -_vt_cmd_plobj_id_hash_update(routing_rule, NMPlatformRoutingRule, { - nm_platform_routing_rule_hash_update(obj, NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID, h); -}); - -_vt_cmd_plobj_id_hash_update(qdisc, NMPlatformQdisc, { - nm_hash_update_vals(h, obj->ifindex, obj->parent); -}); - -_vt_cmd_plobj_id_hash_update(tfilter, NMPlatformTfilter, { - nm_hash_update_vals(h, obj->ifindex, obj->handle); -}); - -static void -_vt_cmd_plobj_hash_update_ip4_route(const NMPlatformObject *obj, NMHashState *h) -{ - return nm_platform_ip4_route_hash_update((const NMPlatformIP4Route *) obj, - NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL, - h); -} - -static void -_vt_cmd_plobj_hash_update_ip6_route(const NMPlatformObject *obj, NMHashState *h) -{ - return nm_platform_ip6_route_hash_update((const NMPlatformIP6Route *) obj, - NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL, - h); -} - -static void -_vt_cmd_plobj_hash_update_routing_rule(const NMPlatformObject *obj, NMHashState *h) -{ - return nm_platform_routing_rule_hash_update((const NMPlatformRoutingRule *) obj, - NM_PLATFORM_ROUTING_RULE_CMP_TYPE_FULL, - h); -} - -guint -nmp_object_indirect_id_hash(gconstpointer a) -{ - const NMPObject *const *p_obj = a; - - return nmp_object_id_hash(*p_obj); -} - -gboolean -nmp_object_indirect_id_equal(gconstpointer a, gconstpointer b) -{ - const NMPObject *const *p_obj_a = a; - const NMPObject *const *p_obj_b = b; - - return nmp_object_id_equal(*p_obj_a, *p_obj_b); -} - -/*****************************************************************************/ - -gboolean -nmp_object_is_alive(const NMPObject *obj) -{ - const NMPClass *klass; - - /* for convenience, allow NULL. */ - if (!obj) - return FALSE; - - klass = NMP_OBJECT_GET_CLASS(obj); - return !klass->cmd_obj_is_alive || klass->cmd_obj_is_alive(obj); -} - -static gboolean -_vt_cmd_obj_is_alive_link(const NMPObject *obj) -{ - return NMP_OBJECT_CAST_LINK(obj)->ifindex > 0 - && (obj->_link.netlink.is_in_netlink || obj->_link.udev.device); -} - -static gboolean -_vt_cmd_obj_is_alive_ipx_address(const NMPObject *obj) -{ - return NMP_OBJECT_CAST_IP_ADDRESS(obj)->ifindex > 0; -} - -static gboolean -_vt_cmd_obj_is_alive_ipx_route(const NMPObject *obj) -{ - /* We want to ignore routes that are RTM_F_CLONED but we still - * let nmp_object_from_nl() create such route objects, instead of - * returning NULL right away. - * - * The idea is, that if we have the same route (according to its id) - * in the cache with !RTM_F_CLONED, an update that changes the route - * to be RTM_F_CLONED must remove the instance. - * - * If nmp_object_from_nl() would just return NULL, we couldn't look - * into the cache to see if it contains a route that now disappears - * (because it changed to be cloned). - * - * Instead we create a dead object, and nmp_cache_update_netlink() - * will remove the old version of the update. - **/ - return NMP_OBJECT_CAST_IP_ROUTE(obj)->ifindex > 0 - && !NM_FLAGS_HAS(obj->ip_route.r_rtm_flags, RTM_F_CLONED); -} - -static gboolean -_vt_cmd_obj_is_alive_routing_rule(const NMPObject *obj) -{ - return NM_IN_SET(obj->routing_rule.addr_family, AF_INET, AF_INET6); -} - -static gboolean -_vt_cmd_obj_is_alive_qdisc(const NMPObject *obj) -{ - return NMP_OBJECT_CAST_QDISC(obj)->ifindex > 0; -} - -static gboolean -_vt_cmd_obj_is_alive_tfilter(const NMPObject *obj) -{ - return NMP_OBJECT_CAST_TFILTER(obj)->ifindex > 0; -} - -gboolean -nmp_object_is_visible(const NMPObject *obj) -{ - const NMPClass *klass; - - /* for convenience, allow NULL. */ - if (!obj) - return FALSE; - - klass = NMP_OBJECT_GET_CLASS(obj); - - /* a dead object is never visible. */ - if (klass->cmd_obj_is_alive && !klass->cmd_obj_is_alive(obj)) - return FALSE; - - return !klass->cmd_obj_is_visible || klass->cmd_obj_is_visible(obj); -} - -static gboolean -_vt_cmd_obj_is_visible_link(const NMPObject *obj) -{ - return obj->_link.netlink.is_in_netlink && obj->link.name[0]; -} - -/*****************************************************************************/ - -static const guint8 _supported_cache_ids_object[] = { - NMP_CACHE_ID_TYPE_OBJECT_TYPE, - NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX, - 0, -}; - -static const guint8 _supported_cache_ids_link[] = { - NMP_CACHE_ID_TYPE_OBJECT_TYPE, - NMP_CACHE_ID_TYPE_LINK_BY_IFNAME, - 0, -}; - -static const guint8 _supported_cache_ids_ipx_address[] = { - NMP_CACHE_ID_TYPE_OBJECT_TYPE, - NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX, - 0, -}; - -static const guint8 _supported_cache_ids_ipx_route[] = { - NMP_CACHE_ID_TYPE_OBJECT_TYPE, - NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX, - NMP_CACHE_ID_TYPE_DEFAULT_ROUTES, - NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID, - 0, -}; - -static const guint8 _supported_cache_ids_routing_rules[] = { - NMP_CACHE_ID_TYPE_OBJECT_TYPE, - NMP_CACHE_ID_TYPE_OBJECT_BY_ADDR_FAMILY, - 0, -}; - -/*****************************************************************************/ - -static void -_vt_dedup_obj_destroy(NMDedupMultiObj *obj) -{ - NMPObject * o = (NMPObject *) obj; - const NMPClass *klass; - - nm_assert(o->parent._ref_count == 0); - nm_assert(!o->parent._multi_idx); - - klass = o->_class; - if (klass->cmd_obj_dispose) - klass->cmd_obj_dispose(o); - g_slice_free1(klass->sizeof_data + G_STRUCT_OFFSET(NMPObject, object), o); -} - -static const NMDedupMultiObj * -_vt_dedup_obj_clone(const NMDedupMultiObj *obj) -{ - return (const NMDedupMultiObj *) nmp_object_clone((const NMPObject *) obj, FALSE); -} - -#define DEDUP_MULTI_OBJ_CLASS_INIT() \ - { \ - .obj_clone = _vt_dedup_obj_clone, .obj_destroy = _vt_dedup_obj_destroy, \ - .obj_full_hash_update = \ - (void (*)(const NMDedupMultiObj *obj, NMHashState *h)) nmp_object_hash_update, \ - .obj_full_equal = (gboolean(*)(const NMDedupMultiObj *obj_a, \ - const NMDedupMultiObj *obj_b)) nmp_object_equal, \ - } - -/*****************************************************************************/ - -static NMDedupMultiIdxType * -_idx_type_get(const NMPCache *cache, NMPCacheIdType cache_id_type) -{ - nm_assert(cache); - nm_assert(cache_id_type > NMP_CACHE_ID_TYPE_NONE); - nm_assert(cache_id_type <= NMP_CACHE_ID_TYPE_MAX); - nm_assert((int) cache_id_type - 1 >= 0); - nm_assert((int) cache_id_type - 1 < G_N_ELEMENTS(cache->idx_types)); - - return (NMDedupMultiIdxType *) &cache->idx_types[cache_id_type - 1]; -} - -gboolean -nmp_cache_use_udev_get(const NMPCache *cache) -{ - g_return_val_if_fail(cache, TRUE); - - return cache->use_udev; -} - -/*****************************************************************************/ - -gboolean -nmp_cache_link_connected_for_slave(int ifindex_master, const NMPObject *slave) -{ - nm_assert(NMP_OBJECT_GET_TYPE(slave) == NMP_OBJECT_TYPE_LINK); - - return ifindex_master > 0 && slave->link.master == ifindex_master && slave->link.connected - && nmp_object_is_visible(slave); -} - -/** - * nmp_cache_link_connected_needs_toggle: - * @cache: the platform cache - * @master: the link object, that is checked whether its connected property - * needs to be toggled. - * @potential_slave: (allow-none): an additional link object that is treated - * as if it was inside @cache. If given, it shaddows a link in the cache - * with the same ifindex. - * @ignore_slave: (allow-none): if set, the check will pretend that @ignore_slave - * is not in the cache. - * - * NMPlatformLink has two connected flags: (master->link.flags&IFF_LOWER_UP) (as reported - * from netlink) and master->link.connected. For bond and bridge master, kernel reports - * those links as IFF_LOWER_UP if they have no slaves attached. We want to present instead - * a combined @connected flag that shows masters without slaves as down. - * - * Check if the connected flag of @master should be toggled according to the content - * of @cache (including @potential_slave). - * - * Returns: %TRUE, if @master->link.connected should be flipped/toggled. - **/ -gboolean -nmp_cache_link_connected_needs_toggle(const NMPCache * cache, - const NMPObject *master, - const NMPObject *potential_slave, - const NMPObject *ignore_slave) -{ - gboolean is_lower_up = FALSE; - - if (!master || NMP_OBJECT_GET_TYPE(master) != NMP_OBJECT_TYPE_LINK || master->link.ifindex <= 0 - || !nmp_object_is_visible(master) - || !NM_IN_SET(master->link.type, NM_LINK_TYPE_BRIDGE, NM_LINK_TYPE_BOND)) - return FALSE; - - /* if native IFF_LOWER_UP is down, link.connected must also be down - * regardless of the slaves. */ - if (!NM_FLAGS_HAS(master->link.n_ifi_flags, IFF_LOWER_UP)) - return !!master->link.connected; - - if (potential_slave && NMP_OBJECT_GET_TYPE(potential_slave) != NMP_OBJECT_TYPE_LINK) - potential_slave = NULL; - - if (potential_slave - && nmp_cache_link_connected_for_slave(master->link.ifindex, potential_slave)) - is_lower_up = TRUE; - else { - NMPLookup lookup; - NMDedupMultiIter iter; - const NMPlatformLink *link = NULL; - - nmp_cache_iter_for_each_link ( - &iter, - nmp_cache_lookup(cache, nmp_lookup_init_obj_type(&lookup, NMP_OBJECT_TYPE_LINK)), - &link) { - const NMPObject *obj = NMP_OBJECT_UP_CAST((NMPlatformObject *) link); - - if ((!potential_slave || potential_slave->link.ifindex != link->ifindex) - && ignore_slave != obj - && nmp_cache_link_connected_for_slave(master->link.ifindex, obj)) { - is_lower_up = TRUE; - break; - } - } - } - return !!master->link.connected != is_lower_up; -} - -/** - * nmp_cache_link_connected_needs_toggle_by_ifindex: - * @cache: - * @master_ifindex: the ifindex of a potential master that should be checked - * whether it needs toggling. - * @potential_slave: (allow-none): passed to nmp_cache_link_connected_needs_toggle(). - * It considers @potential_slave as being inside the cache, replacing an existing - * link with the same ifindex. - * @ignore_slave: (allow-onne): passed to nmp_cache_link_connected_needs_toggle(). - * - * The flag obj->link.connected depends on the state of other links in the - * @cache. See also nmp_cache_link_connected_needs_toggle(). Given an ifindex - * of a master, check if the cache contains such a master link that needs - * toggling of the connected flag. - * - * Returns: NULL if there is no master link with ifindex @master_ifindex that should be toggled. - * Otherwise, return the link object from inside the cache with the given ifindex. - * The connected flag of that master should be toggled. - */ -const NMPObject * -nmp_cache_link_connected_needs_toggle_by_ifindex(const NMPCache * cache, - int master_ifindex, - const NMPObject *potential_slave, - const NMPObject *ignore_slave) -{ - const NMPObject *master; - - if (master_ifindex > 0) { - master = nmp_cache_lookup_link(cache, master_ifindex); - if (nmp_cache_link_connected_needs_toggle(cache, master, potential_slave, ignore_slave)) - return master; - } - return NULL; -} - -/*****************************************************************************/ - -static const NMDedupMultiEntry * -_lookup_entry_with_idx_type(const NMPCache * cache, - NMPCacheIdType cache_id_type, - const NMPObject *obj) -{ - const NMDedupMultiEntry *entry; - - nm_assert(cache); - nm_assert(NMP_OBJECT_IS_VALID(obj)); - - entry = - nm_dedup_multi_index_lookup_obj(cache->multi_idx, _idx_type_get(cache, cache_id_type), obj); - nm_assert(!entry - || (NMP_OBJECT_IS_VALID(entry->obj) - && NMP_OBJECT_GET_CLASS(entry->obj) == NMP_OBJECT_GET_CLASS(obj))); - return entry; -} - -static const NMDedupMultiEntry * -_lookup_entry(const NMPCache *cache, const NMPObject *obj) -{ - return _lookup_entry_with_idx_type(cache, NMP_CACHE_ID_TYPE_OBJECT_TYPE, obj); -} - -const NMDedupMultiEntry * -nmp_cache_lookup_entry_with_idx_type(const NMPCache * cache, - NMPCacheIdType cache_id_type, - const NMPObject *obj) -{ - g_return_val_if_fail(cache, NULL); - g_return_val_if_fail(obj, NULL); - g_return_val_if_fail(cache_id_type > NMP_CACHE_ID_TYPE_NONE - && cache_id_type <= NMP_CACHE_ID_TYPE_MAX, - NULL); - - return _lookup_entry_with_idx_type(cache, cache_id_type, obj); -} - -const NMDedupMultiEntry * -nmp_cache_lookup_entry(const NMPCache *cache, const NMPObject *obj) -{ - g_return_val_if_fail(cache, NULL); - g_return_val_if_fail(obj, NULL); - - return _lookup_entry(cache, obj); -} - -const NMDedupMultiEntry * -nmp_cache_lookup_entry_link(const NMPCache *cache, int ifindex) -{ - NMPObject obj_needle; - - g_return_val_if_fail(cache, NULL); - g_return_val_if_fail(ifindex > 0, NULL); - - nmp_object_stackinit_id_link(&obj_needle, ifindex); - return _lookup_entry(cache, &obj_needle); -} - -const NMPObject * -nmp_cache_lookup_obj(const NMPCache *cache, const NMPObject *obj) -{ - return nm_dedup_multi_entry_get_obj(nmp_cache_lookup_entry(cache, obj)); -} - -const NMPObject * -nmp_cache_lookup_link(const NMPCache *cache, int ifindex) -{ - return nm_dedup_multi_entry_get_obj(nmp_cache_lookup_entry_link(cache, ifindex)); -} - -/*****************************************************************************/ - -const NMDedupMultiHeadEntry * -nmp_cache_lookup_all(const NMPCache * cache, - NMPCacheIdType cache_id_type, - const NMPObject *select_obj) -{ - nm_assert(cache); - nm_assert(NMP_OBJECT_IS_VALID(select_obj)); - - return nm_dedup_multi_index_lookup_head(cache->multi_idx, - _idx_type_get(cache, cache_id_type), - select_obj); -} - -static const NMPLookup * -_L(const NMPLookup *lookup) -{ -#if NM_MORE_ASSERTS - DedupMultiIdxType idx_type; - - nm_assert(lookup); - _dedup_multi_idx_type_init(&idx_type, lookup->cache_id_type); - nm_assert( - idx_type.parent.klass->idx_obj_partitionable((NMDedupMultiIdxType *) &idx_type, - (NMDedupMultiObj *) &lookup->selector_obj)); -#endif - return lookup; -} - -const NMPLookup * -nmp_lookup_init_obj_type(NMPLookup *lookup, NMPObjectType obj_type) -{ - nm_assert(lookup); - - switch (obj_type) { - case NMP_OBJECT_TYPE_LINK: - case NMP_OBJECT_TYPE_IP4_ADDRESS: - case NMP_OBJECT_TYPE_IP6_ADDRESS: - case NMP_OBJECT_TYPE_IP4_ROUTE: - case NMP_OBJECT_TYPE_IP6_ROUTE: - case NMP_OBJECT_TYPE_ROUTING_RULE: - case NMP_OBJECT_TYPE_QDISC: - case NMP_OBJECT_TYPE_TFILTER: - _nmp_object_stackinit_from_type(&lookup->selector_obj, obj_type); - lookup->cache_id_type = NMP_CACHE_ID_TYPE_OBJECT_TYPE; - return _L(lookup); - default: - nm_assert_not_reached(); - return NULL; - } -} - -const NMPLookup * -nmp_lookup_init_link_by_ifname(NMPLookup *lookup, const char *ifname) -{ - NMPObject *o; - - nm_assert(lookup); - nm_assert(ifname); - nm_assert(strlen(ifname) < IFNAMSIZ); - - o = _nmp_object_stackinit_from_type(&lookup->selector_obj, NMP_OBJECT_TYPE_LINK); - if (g_strlcpy(o->link.name, ifname, sizeof(o->link.name)) >= sizeof(o->link.name)) - g_return_val_if_reached(NULL); - lookup->cache_id_type = NMP_CACHE_ID_TYPE_LINK_BY_IFNAME; - return _L(lookup); -} - -const NMPLookup * -nmp_lookup_init_object(NMPLookup *lookup, NMPObjectType obj_type, int ifindex) -{ - NMPObject *o; - - nm_assert(lookup); - nm_assert(NM_IN_SET(obj_type, - NMP_OBJECT_TYPE_IP4_ADDRESS, - NMP_OBJECT_TYPE_IP6_ADDRESS, - NMP_OBJECT_TYPE_IP4_ROUTE, - NMP_OBJECT_TYPE_IP6_ROUTE, - NMP_OBJECT_TYPE_QDISC, - NMP_OBJECT_TYPE_TFILTER)); - - if (ifindex <= 0) { - return nmp_lookup_init_obj_type(lookup, obj_type); - } - - o = _nmp_object_stackinit_from_type(&lookup->selector_obj, obj_type); - o->obj_with_ifindex.ifindex = ifindex; - lookup->cache_id_type = NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX; - return _L(lookup); -} - -const NMPLookup * -nmp_lookup_init_route_default(NMPLookup *lookup, NMPObjectType obj_type) -{ - NMPObject *o; - - nm_assert(lookup); - nm_assert(NM_IN_SET(obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); - - o = _nmp_object_stackinit_from_type(&lookup->selector_obj, obj_type); - o->ip_route.ifindex = 1; - lookup->cache_id_type = NMP_CACHE_ID_TYPE_DEFAULT_ROUTES; - return _L(lookup); -} - -const NMPLookup * -nmp_lookup_init_route_by_weak_id(NMPLookup *lookup, const NMPObject *obj) -{ - const NMPlatformIP4Route *r4; - const NMPlatformIP6Route *r6; - - nm_assert(lookup); - - switch (NMP_OBJECT_GET_TYPE(obj)) { - case NMP_OBJECT_TYPE_IP4_ROUTE: - r4 = NMP_OBJECT_CAST_IP4_ROUTE(obj); - return nmp_lookup_init_ip4_route_by_weak_id(lookup, - r4->network, - r4->plen, - r4->metric, - r4->tos); - case NMP_OBJECT_TYPE_IP6_ROUTE: - r6 = NMP_OBJECT_CAST_IP6_ROUTE(obj); - return nmp_lookup_init_ip6_route_by_weak_id(lookup, - &r6->network, - r6->plen, - r6->metric, - &r6->src, - r6->src_plen); - default: - nm_assert_not_reached(); - return NULL; - } -} - -const NMPLookup * -nmp_lookup_init_ip4_route_by_weak_id(NMPLookup *lookup, - in_addr_t network, - guint plen, - guint32 metric, - guint8 tos) -{ - NMPObject *o; - - nm_assert(lookup); - - o = _nmp_object_stackinit_from_type(&lookup->selector_obj, NMP_OBJECT_TYPE_IP4_ROUTE); - o->ip4_route.ifindex = 1; - o->ip4_route.plen = plen; - o->ip4_route.metric = metric; - if (network) - o->ip4_route.network = network; - o->ip4_route.tos = tos; - lookup->cache_id_type = NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID; - return _L(lookup); -} - -const NMPLookup * -nmp_lookup_init_ip6_route_by_weak_id(NMPLookup * lookup, - const struct in6_addr *network, - guint plen, - guint32 metric, - const struct in6_addr *src, - guint8 src_plen) -{ - NMPObject *o; - - nm_assert(lookup); - - o = _nmp_object_stackinit_from_type(&lookup->selector_obj, NMP_OBJECT_TYPE_IP6_ROUTE); - o->ip6_route.ifindex = 1; - o->ip6_route.plen = plen; - o->ip6_route.metric = metric; - if (network) - o->ip6_route.network = *network; - if (src) - o->ip6_route.src = *src; - o->ip6_route.src_plen = src_plen; - lookup->cache_id_type = NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID; - return _L(lookup); -} - -const NMPLookup * -nmp_lookup_init_object_by_addr_family(NMPLookup *lookup, NMPObjectType obj_type, int addr_family) -{ - NMPObject *o; - - nm_assert(lookup); - nm_assert(NM_IN_SET(obj_type, NMP_OBJECT_TYPE_ROUTING_RULE)); - - if (addr_family == AF_UNSPEC) - return nmp_lookup_init_obj_type(lookup, obj_type); - - nm_assert_addr_family(addr_family); - o = _nmp_object_stackinit_from_type(&lookup->selector_obj, obj_type); - NMP_OBJECT_CAST_ROUTING_RULE(o)->addr_family = addr_family; - lookup->cache_id_type = NMP_CACHE_ID_TYPE_OBJECT_BY_ADDR_FAMILY; - return _L(lookup); -} - -/*****************************************************************************/ - -GArray * -nmp_cache_lookup_to_array(const NMDedupMultiHeadEntry *head_entry, - NMPObjectType obj_type, - gboolean visible_only) -{ - const NMPClass * klass = nmp_class_from_type(obj_type); - NMDedupMultiIter iter; - const NMPObject *o; - GArray * array; - - g_return_val_if_fail(klass, NULL); - - array = g_array_sized_new(FALSE, FALSE, klass->sizeof_public, head_entry ? head_entry->len : 0); - nmp_cache_iter_for_each (&iter, head_entry, &o) { - nm_assert(NMP_OBJECT_GET_CLASS(o) == klass); - if (visible_only && !nmp_object_is_visible(o)) - continue; - g_array_append_vals(array, &o->object, 1); - } - return array; -} - -/*****************************************************************************/ - -const NMPObject * -nmp_cache_lookup_link_full(const NMPCache * cache, - int ifindex, - const char * ifname, - gboolean visible_only, - NMLinkType link_type, - NMPObjectMatchFn match_fn, - gpointer user_data) -{ - NMPObject obj_needle; - const NMPObject * obj; - NMDedupMultiIter iter; - const NMDedupMultiHeadEntry *head_entry; - const NMPlatformLink * link = NULL; - NMPLookup lookup; - - if (ifindex > 0) { - obj = nmp_cache_lookup_obj(cache, nmp_object_stackinit_id_link(&obj_needle, ifindex)); - - if (!obj || (visible_only && !nmp_object_is_visible(obj)) - || (link_type != NM_LINK_TYPE_NONE && obj->link.type != link_type) - || (ifname && strcmp(obj->link.name, ifname)) - || (match_fn && !match_fn(obj, user_data))) - return NULL; - return obj; - } else if (!ifname && !match_fn) - return NULL; - else { - const NMPObject *obj_best = NULL; - - if (ifname) { - if (strlen(ifname) >= IFNAMSIZ) - return NULL; - nmp_lookup_init_link_by_ifname(&lookup, ifname); - } else - nmp_lookup_init_obj_type(&lookup, NMP_OBJECT_TYPE_LINK); - - head_entry = nmp_cache_lookup(cache, &lookup); - nmp_cache_iter_for_each_link (&iter, head_entry, &link) { - obj = NMP_OBJECT_UP_CAST(link); - - if (link_type != NM_LINK_TYPE_NONE && obj->link.type != link_type) - continue; - if (visible_only && !nmp_object_is_visible(obj)) - continue; - if (match_fn && !match_fn(obj, user_data)) - continue; - - /* if there are multiple candidates, prefer the visible ones. */ - if (visible_only || nmp_object_is_visible(obj)) - return obj; - if (!obj_best) - obj_best = obj; - } - return obj_best; - } -} - -/*****************************************************************************/ - -static NMDedupMultiIdxMode -_obj_get_add_mode(const NMPObject *obj) -{ - /* new objects are usually appended to the list. Except for - * addresses, which are prepended during `ip address add`. - * - * Actually, for routes it is more complicated, because depending on - * `ip route append`, `ip route replace`, `ip route prepend`, the object - * will be added at the tail, at the front, or even replace an element - * in the list. However, that is handled separately by nmp_cache_update_netlink_route() - * and of no concern here. */ - if (NM_IN_SET(NMP_OBJECT_GET_TYPE(obj), - NMP_OBJECT_TYPE_IP4_ADDRESS, - NMP_OBJECT_TYPE_IP6_ADDRESS)) - return NM_DEDUP_MULTI_IDX_MODE_PREPEND; - return NM_DEDUP_MULTI_IDX_MODE_APPEND; -} - -static void -_idxcache_update_order_for_dump(NMPCache *cache, const NMDedupMultiEntry *entry) -{ - const NMPClass * klass; - const guint8 * i_idx_type; - const NMDedupMultiEntry *entry2; - - nm_dedup_multi_entry_reorder(entry, NULL, TRUE); - - klass = NMP_OBJECT_GET_CLASS(entry->obj); - for (i_idx_type = klass->supported_cache_ids; *i_idx_type; i_idx_type++) { - NMPCacheIdType id_type = *i_idx_type; - - if (id_type == NMP_CACHE_ID_TYPE_OBJECT_TYPE) - continue; - - entry2 = nm_dedup_multi_index_lookup_obj(cache->multi_idx, - _idx_type_get(cache, id_type), - entry->obj); - if (!entry2) - continue; - - nm_assert(entry2 != entry); - nm_assert(entry2->obj == entry->obj); - - nm_dedup_multi_entry_reorder(entry2, NULL, TRUE); - } -} - -static void -_idxcache_update_other_cache_ids(NMPCache * cache, - NMPCacheIdType cache_id_type, - const NMPObject *obj_old, - const NMPObject *obj_new, - gboolean is_dump) -{ - const NMDedupMultiEntry *entry_new; - const NMDedupMultiEntry *entry_old; - const NMDedupMultiEntry *entry_order; - NMDedupMultiIdxType * idx_type; - - nm_assert(obj_new || obj_old); - nm_assert(!obj_new || NMP_OBJECT_GET_TYPE(obj_new) != NMP_OBJECT_TYPE_UNKNOWN); - nm_assert(!obj_old || NMP_OBJECT_GET_TYPE(obj_old) != NMP_OBJECT_TYPE_UNKNOWN); - nm_assert(!obj_old || !obj_new - || NMP_OBJECT_GET_CLASS(obj_new) == NMP_OBJECT_GET_CLASS(obj_old)); - nm_assert(!obj_old || !obj_new || !nmp_object_equal(obj_new, obj_old)); - nm_assert(!obj_new || obj_new == nm_dedup_multi_index_obj_find(cache->multi_idx, obj_new)); - nm_assert(!obj_old || obj_old == nm_dedup_multi_index_obj_find(cache->multi_idx, obj_old)); - - idx_type = _idx_type_get(cache, cache_id_type); - - if (obj_old) { - entry_old = nm_dedup_multi_index_lookup_obj(cache->multi_idx, idx_type, obj_old); - if (!obj_new) { - if (entry_old) - nm_dedup_multi_index_remove_entry(cache->multi_idx, entry_old); - return; - } - } else - entry_old = NULL; - - if (obj_new) { - if (obj_old && nm_dedup_multi_idx_type_id_equal(idx_type, obj_old, obj_new) - && nm_dedup_multi_idx_type_partition_equal(idx_type, obj_old, obj_new)) { - /* optimize. We just looked up the @obj_old entry and @obj_new compares equal - * according to idx_obj_id_equal(). entry_new is the same as entry_old. */ - entry_new = entry_old; - } else { - entry_new = nm_dedup_multi_index_lookup_obj(cache->multi_idx, idx_type, obj_new); - } - - if (entry_new) - entry_order = entry_new; - else if (entry_old - && nm_dedup_multi_idx_type_partition_equal(idx_type, entry_old->obj, obj_new)) - entry_order = entry_old; - else - entry_order = NULL; - nm_dedup_multi_index_add_full( - cache->multi_idx, - idx_type, - obj_new, - is_dump ? NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE : _obj_get_add_mode(obj_new), - is_dump ? NULL : entry_order, - entry_new ?: NM_DEDUP_MULTI_ENTRY_MISSING, - entry_new ? entry_new->head : (entry_order ? entry_order->head : NULL), - &entry_new, - NULL); - -#if NM_MORE_ASSERTS - if (entry_new) { - nm_assert(idx_type->klass->idx_obj_partitionable); - nm_assert(idx_type->klass->idx_obj_partition_equal); - nm_assert(idx_type->klass->idx_obj_partitionable(idx_type, entry_new->obj)); - nm_assert(idx_type->klass->idx_obj_partition_equal(idx_type, - (gpointer) obj_new, - entry_new->obj)); - } -#endif - } else - entry_new = NULL; - - if (entry_old && entry_old != entry_new) - nm_dedup_multi_index_remove_entry(cache->multi_idx, entry_old); -} - -static void -_idxcache_update(NMPCache * cache, - const NMDedupMultiEntry * entry_old, - NMPObject * obj_new, - gboolean is_dump, - const NMDedupMultiEntry **out_entry_new) -{ - const NMPClass * klass; - const guint8 * i_idx_type; - NMDedupMultiIdxType * idx_type_o = _idx_type_get(cache, NMP_CACHE_ID_TYPE_OBJECT_TYPE); - const NMDedupMultiEntry *entry_new = NULL; - nm_auto_nmpobj const NMPObject *obj_old = NULL; - - /* we update an object in the cache. - * - * Note that @entry_old MUST be what is currently tracked in multi_idx, and it must - * have the same ID as @obj_new. */ - - nm_assert(cache); - nm_assert(entry_old || obj_new); - nm_assert(!obj_new || nmp_object_is_alive(obj_new)); - nm_assert( - !entry_old - || entry_old - == nm_dedup_multi_index_lookup_obj(cache->multi_idx, idx_type_o, entry_old->obj)); - nm_assert(!obj_new - || entry_old - == nm_dedup_multi_index_lookup_obj(cache->multi_idx, idx_type_o, obj_new)); - nm_assert(!entry_old || entry_old->head->idx_type == idx_type_o); - nm_assert(!entry_old || !obj_new - || nm_dedup_multi_idx_type_partition_equal(idx_type_o, entry_old->obj, obj_new)); - nm_assert(!entry_old || !obj_new - || nm_dedup_multi_idx_type_id_equal(idx_type_o, entry_old->obj, obj_new)); - nm_assert(!entry_old || !obj_new - || (obj_new->parent.klass == ((const NMPObject *) entry_old->obj)->parent.klass - && !obj_new->parent.klass->obj_full_equal((NMDedupMultiObj *) obj_new, - entry_old->obj))); - - /* keep a reference to the pre-existing entry */ - if (entry_old) - obj_old = nmp_object_ref(entry_old->obj); - - /* first update the main index NMP_CACHE_ID_TYPE_OBJECT_TYPE. - * We already know the pre-existing @entry old, so all that - * nm_dedup_multi_index_add_full() effectively does, is update the - * obj reference. - * - * We also get the new boxed object, which we need below. */ - if (obj_new) { - nm_auto_nmpobj NMPObject *obj_old2 = NULL; - - nm_dedup_multi_index_add_full(cache->multi_idx, - idx_type_o, - obj_new, - is_dump ? NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE - : _obj_get_add_mode(obj_new), - NULL, - entry_old ?: NM_DEDUP_MULTI_ENTRY_MISSING, - NULL, - &entry_new, - (const NMDedupMultiObj **) &obj_old2); - nm_assert(entry_new); - nm_assert(obj_old == obj_old2); - nm_assert(!entry_old || entry_old == entry_new); - } else - nm_dedup_multi_index_remove_entry(cache->multi_idx, entry_old); - - /* now update all other indexes. We know the previously boxed entry, and the - * newly boxed one. */ - klass = NMP_OBJECT_GET_CLASS(entry_new ? entry_new->obj : obj_old); - for (i_idx_type = klass->supported_cache_ids; *i_idx_type; i_idx_type++) { - NMPCacheIdType id_type = *i_idx_type; - - if (id_type == NMP_CACHE_ID_TYPE_OBJECT_TYPE) - continue; - _idxcache_update_other_cache_ids(cache, - id_type, - obj_old, - entry_new ? entry_new->obj : NULL, - is_dump); - } - - NM_SET_OUT(out_entry_new, entry_new); -} - -NMPCacheOpsType -nmp_cache_remove(NMPCache * cache, - const NMPObject * obj_needle, - gboolean equals_by_ptr, - gboolean only_dirty, - const NMPObject **out_obj_old) -{ - const NMDedupMultiEntry *entry_old; - const NMPObject * obj_old; - - entry_old = _lookup_entry(cache, obj_needle); - - if (!entry_old) { - NM_SET_OUT(out_obj_old, NULL); - return NMP_CACHE_OPS_UNCHANGED; - } - - obj_old = entry_old->obj; - - NM_SET_OUT(out_obj_old, nmp_object_ref(obj_old)); - - if (equals_by_ptr && obj_old != obj_needle) { - /* We found an identical object, but we only delete it if it's the same pointer as - * @obj_needle. */ - return NMP_CACHE_OPS_UNCHANGED; - } - if (only_dirty && !entry_old->dirty) { - /* the entry is not dirty. Skip. */ - return NMP_CACHE_OPS_UNCHANGED; - } - _idxcache_update(cache, entry_old, NULL, FALSE, NULL); - return NMP_CACHE_OPS_REMOVED; -} - -NMPCacheOpsType -nmp_cache_remove_netlink(NMPCache * cache, - const NMPObject * obj_needle, - const NMPObject **out_obj_old, - const NMPObject **out_obj_new) -{ - const NMDedupMultiEntry *entry_old; - const NMDedupMultiEntry *entry_new = NULL; - const NMPObject * obj_old; - nm_auto_nmpobj NMPObject *obj_new = NULL; - - entry_old = _lookup_entry(cache, obj_needle); - - if (!entry_old) { - NM_SET_OUT(out_obj_old, NULL); - NM_SET_OUT(out_obj_new, NULL); - return NMP_CACHE_OPS_UNCHANGED; - } - - obj_old = entry_old->obj; - - if (NMP_OBJECT_GET_TYPE(obj_needle) == NMP_OBJECT_TYPE_LINK) { - /* 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 - * have a udev-device. All we want to do in this case is clear the netlink.is_in_netlink - * flag. */ - - NM_SET_OUT(out_obj_old, nmp_object_ref(obj_old)); - - if (!obj_old->_link.netlink.is_in_netlink) { - nm_assert(obj_old->_link.udev.device); - NM_SET_OUT(out_obj_new, nmp_object_ref(obj_old)); - return NMP_CACHE_OPS_UNCHANGED; - } - - if (!obj_old->_link.udev.device) { - /* the update would make @obj_old invalid. Remove it. */ - _idxcache_update(cache, entry_old, NULL, FALSE, NULL); - NM_SET_OUT(out_obj_new, NULL); - return NMP_CACHE_OPS_REMOVED; - } - - obj_new = nmp_object_clone(obj_old, FALSE); - obj_new->_link.netlink.is_in_netlink = FALSE; - - _nmp_object_fixup_link_master_connected(&obj_new, NULL, cache); - _nmp_object_fixup_link_udev_fields(&obj_new, NULL, cache->use_udev); - - _idxcache_update(cache, entry_old, obj_new, FALSE, &entry_new); - NM_SET_OUT(out_obj_new, nmp_object_ref(entry_new->obj)); - return NMP_CACHE_OPS_UPDATED; - } - - NM_SET_OUT(out_obj_old, nmp_object_ref(obj_old)); - NM_SET_OUT(out_obj_new, NULL); - _idxcache_update(cache, entry_old, NULL, FALSE, NULL); - return NMP_CACHE_OPS_REMOVED; -} - -/** - * nmp_cache_update_netlink: - * @cache: the platform cache - * @obj_hand_over: a #NMPObject instance as received from netlink and created via - * nmp_object_from_nl(). Especially for link, it must not have the udev - * replated fields set. - * This instance will be modified and might be put into the cache. When - * calling nmp_cache_update_netlink() you hand @obj over to the cache. - * Except, that the cache will increment the ref count as appropriate. You - * must still unref the obj to release your part of the ownership. - * @is_dump: whether this update comes during a dump of object of the same kind. - * kernel dumps objects in a certain order, which matters especially for routes. - * Before a dump we mark all objects as dirty, and remove all untouched objects - * afterwards. Hence, during a dump, every update should move the object to the - * end of the list, to obtain the correct order. That means, to use NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE, - * instead of NM_DEDUP_MULTI_IDX_MODE_APPEND. - * @out_obj_old: (allow-none) (out): return the object with same ID as @obj_hand_over, - * that was in the cache before update. If an object is returned, the caller must - * unref it afterwards. - * @out_obj_new: (allow-none) (out): return the object from the cache after update. - * The caller must unref this object. - * - * Returns: how the cache changed. - * - * Even if there was no change in the cache (NMP_CACHE_OPS_UNCHANGED), @out_obj_old - * and @out_obj_new will be set accordingly. - **/ -NMPCacheOpsType -nmp_cache_update_netlink(NMPCache * cache, - NMPObject * obj_hand_over, - gboolean is_dump, - const NMPObject **out_obj_old, - const NMPObject **out_obj_new) -{ - const NMDedupMultiEntry *entry_old; - const NMDedupMultiEntry *entry_new; - const NMPObject * obj_old; - gboolean is_alive; - - nm_assert(cache); - nm_assert(NMP_OBJECT_IS_VALID(obj_hand_over)); - nm_assert(!NMP_OBJECT_IS_STACKINIT(obj_hand_over)); - /* A link object from netlink must have the udev related fields unset. - * We could implement to handle that, but there is no need to support such - * a use-case */ - nm_assert(NMP_OBJECT_GET_TYPE(obj_hand_over) != NMP_OBJECT_TYPE_LINK - || (!obj_hand_over->_link.udev.device && !obj_hand_over->link.driver)); - nm_assert(nm_dedup_multi_index_obj_find(cache->multi_idx, obj_hand_over) != obj_hand_over); - - entry_old = _lookup_entry(cache, obj_hand_over); - - if (!entry_old) { - NM_SET_OUT(out_obj_old, NULL); - - if (!nmp_object_is_alive(obj_hand_over)) { - NM_SET_OUT(out_obj_new, NULL); - return NMP_CACHE_OPS_UNCHANGED; - } - - if (NMP_OBJECT_GET_TYPE(obj_hand_over) == NMP_OBJECT_TYPE_LINK) { - _nmp_object_fixup_link_master_connected(&obj_hand_over, NULL, cache); - _nmp_object_fixup_link_udev_fields(&obj_hand_over, NULL, cache->use_udev); - } - - _idxcache_update(cache, entry_old, obj_hand_over, is_dump, &entry_new); - NM_SET_OUT(out_obj_new, nmp_object_ref(entry_new->obj)); - return NMP_CACHE_OPS_ADDED; - } - - obj_old = entry_old->obj; - - if (NMP_OBJECT_GET_TYPE(obj_hand_over) == NMP_OBJECT_TYPE_LINK) { - if (!obj_hand_over->_link.netlink.is_in_netlink) { - if (!obj_old->_link.netlink.is_in_netlink) { - nm_assert(obj_old->_link.udev.device); - NM_SET_OUT(out_obj_old, nmp_object_ref(obj_old)); - NM_SET_OUT(out_obj_new, nmp_object_ref(obj_old)); - return NMP_CACHE_OPS_UNCHANGED; - } - if (obj_old->_link.udev.device) { - /* @obj_hand_over is not in netlink. - * - * This is similar to nmp_cache_remove_netlink(), but there we preserve the - * preexisting netlink properties. The use case of that is when kernel_get_object() - * cannot load an object (based on the id of a needle). - * - * Here we keep the data provided from @obj_hand_over. The usecase is when receiving - * a valid @obj_hand_over instance from netlink with RTM_DELROUTE. - */ - is_alive = TRUE; - } else - is_alive = FALSE; - } else - is_alive = TRUE; - - if (is_alive) { - _nmp_object_fixup_link_master_connected(&obj_hand_over, NULL, cache); - - /* Merge the netlink parts with what we have from udev. */ - udev_device_unref(obj_hand_over->_link.udev.device); - obj_hand_over->_link.udev.device = - obj_old->_link.udev.device ? udev_device_ref(obj_old->_link.udev.device) : NULL; - _nmp_object_fixup_link_udev_fields(&obj_hand_over, NULL, cache->use_udev); - - if (obj_hand_over->_link.netlink.lnk) { - nm_auto_nmpobj const NMPObject *lnk_old = obj_hand_over->_link.netlink.lnk; - - /* let's dedup/intern the lnk object. */ - obj_hand_over->_link.netlink.lnk = - nm_dedup_multi_index_obj_intern(cache->multi_idx, lnk_old); - } - } - } else - is_alive = nmp_object_is_alive(obj_hand_over); - - NM_SET_OUT(out_obj_old, nmp_object_ref(obj_old)); - - if (!is_alive) { - /* the update would make @obj_old invalid. Remove it. */ - _idxcache_update(cache, entry_old, NULL, FALSE, NULL); - NM_SET_OUT(out_obj_new, NULL); - return NMP_CACHE_OPS_REMOVED; - } - - if (nmp_object_equal(obj_old, obj_hand_over)) { - if (is_dump) - _idxcache_update_order_for_dump(cache, entry_old); - nm_dedup_multi_entry_set_dirty(entry_old, FALSE); - NM_SET_OUT(out_obj_new, nmp_object_ref(obj_old)); - return NMP_CACHE_OPS_UNCHANGED; - } - - _idxcache_update(cache, entry_old, obj_hand_over, is_dump, &entry_new); - NM_SET_OUT(out_obj_new, nmp_object_ref(entry_new->obj)); - return NMP_CACHE_OPS_UPDATED; -} - -NMPCacheOpsType -nmp_cache_update_netlink_route(NMPCache * cache, - NMPObject * obj_hand_over, - gboolean is_dump, - guint16 nlmsgflags, - const NMPObject **out_obj_old, - const NMPObject **out_obj_new, - const NMPObject **out_obj_replace, - gboolean * out_resync_required) -{ - NMDedupMultiIter iter; - const NMDedupMultiEntry * entry_old; - const NMDedupMultiEntry * entry_new; - const NMDedupMultiEntry * entry_cur; - const NMDedupMultiEntry * entry_replace; - const NMDedupMultiHeadEntry *head_entry; - gboolean is_alive; - NMPCacheOpsType ops_type = NMP_CACHE_OPS_UNCHANGED; - gboolean resync_required; - - nm_assert(cache); - nm_assert(NMP_OBJECT_IS_VALID(obj_hand_over)); - nm_assert(!NMP_OBJECT_IS_STACKINIT(obj_hand_over)); - /* A link object from netlink must have the udev related fields unset. - * We could implement to handle that, but there is no need to support such - * a use-case */ - nm_assert(NM_IN_SET(NMP_OBJECT_GET_TYPE(obj_hand_over), - NMP_OBJECT_TYPE_IP4_ROUTE, - NMP_OBJECT_TYPE_IP6_ROUTE)); - nm_assert(nm_dedup_multi_index_obj_find(cache->multi_idx, obj_hand_over) != obj_hand_over); - - entry_old = _lookup_entry(cache, obj_hand_over); - entry_new = NULL; - - NM_SET_OUT(out_obj_old, nmp_object_ref(nm_dedup_multi_entry_get_obj(entry_old))); - - if (!entry_old) { - if (!nmp_object_is_alive(obj_hand_over)) - goto update_done; - - _idxcache_update(cache, NULL, obj_hand_over, is_dump, &entry_new); - ops_type = NMP_CACHE_OPS_ADDED; - goto update_done; - } - - is_alive = nmp_object_is_alive(obj_hand_over); - - if (!is_alive) { - /* the update would make @entry_old invalid. Remove it. */ - _idxcache_update(cache, entry_old, NULL, FALSE, NULL); - ops_type = NMP_CACHE_OPS_REMOVED; - goto update_done; - } - - if (nmp_object_equal(entry_old->obj, obj_hand_over)) { - if (is_dump) - _idxcache_update_order_for_dump(cache, entry_old); - nm_dedup_multi_entry_set_dirty(entry_old, FALSE); - goto update_done; - } - - _idxcache_update(cache, entry_old, obj_hand_over, is_dump, &entry_new); - ops_type = NMP_CACHE_OPS_UPDATED; - -update_done: - NM_SET_OUT(out_obj_new, nmp_object_ref(nm_dedup_multi_entry_get_obj(entry_new))); - - /* a RTM_GETROUTE event may signal that another object was replaced. - * Find out whether that is the case and return it as @obj_replaced. - * - * Also, fixup the order of @entry_new within NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID - * index. For most parts, we don't care about the order of objects (including routes). - * But NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID we must keep in the correct order, to - * properly find @obj_replaced. */ - resync_required = FALSE; - entry_replace = NULL; - if (is_dump) - goto out; - - if (!entry_new) { - if (NM_FLAGS_HAS(nlmsgflags, NLM_F_REPLACE) - && nmp_cache_lookup_all(cache, NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID, obj_hand_over)) { - /* hm. @obj_hand_over was not added, meaning it was not alive. - * However, we track some other objects with the same weak-id. - * It's unclear what that means. To be sure, resync. */ - resync_required = TRUE; - } - goto out; - } - - /* FIXME: for routes, we only maintain the order correctly for the BY_WEAK_ID - * index. For all other indexes their order becomes messed up. */ - entry_cur = - _lookup_entry_with_idx_type(cache, NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID, entry_new->obj); - if (!entry_cur) { - nm_assert_not_reached(); - goto out; - } - nm_assert(entry_cur->obj == entry_new->obj); - - head_entry = entry_cur->head; - nm_assert(head_entry - == nmp_cache_lookup_all(cache, NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID, entry_cur->obj)); - - if (head_entry->len == 1) { - /* there is only one object, and we expect it to be @obj_new. */ - nm_assert(nm_dedup_multi_head_entry_get_idx(head_entry, 0) == entry_cur); - goto out; - } - - switch (nlmsgflags & (NLM_F_REPLACE | NLM_F_EXCL | NLM_F_CREATE | NLM_F_APPEND)) { - case NLM_F_REPLACE: - /* ip route change */ - - /* get the first element (but skip @obj_new). */ - nm_dedup_multi_iter_init(&iter, head_entry); - if (!nm_dedup_multi_iter_next(&iter)) - nm_assert_not_reached(); - if (iter.current == entry_cur) { - if (!nm_dedup_multi_iter_next(&iter)) - nm_assert_not_reached(); - } - entry_replace = iter.current; - - nm_assert(entry_replace && entry_cur != entry_replace); - - nm_dedup_multi_entry_reorder(entry_cur, entry_replace, FALSE); - break; - case NLM_F_CREATE | NLM_F_APPEND: - /* ip route append */ - nm_dedup_multi_entry_reorder(entry_cur, NULL, TRUE); - break; - case NLM_F_CREATE: - /* ip route prepend */ - nm_dedup_multi_entry_reorder(entry_cur, NULL, FALSE); - break; - default: - /* this is an unexpected case, probably a bug that we need to handle better. */ - resync_required = TRUE; - break; - } - -out: - NM_SET_OUT(out_obj_replace, nmp_object_ref(nm_dedup_multi_entry_get_obj(entry_replace))); - NM_SET_OUT(out_resync_required, resync_required); - return ops_type; -} - -NMPCacheOpsType -nmp_cache_update_link_udev(NMPCache * cache, - int ifindex, - struct udev_device *udevice, - const NMPObject ** out_obj_old, - const NMPObject ** out_obj_new) -{ - const NMPObject *obj_old; - nm_auto_nmpobj NMPObject *obj_new = NULL; - const NMDedupMultiEntry * entry_old; - const NMDedupMultiEntry * entry_new; - - entry_old = nmp_cache_lookup_entry_link(cache, ifindex); - - if (!entry_old) { - if (!udevice) { - NM_SET_OUT(out_obj_old, NULL); - NM_SET_OUT(out_obj_new, NULL); - return NMP_CACHE_OPS_UNCHANGED; - } - - obj_new = nmp_object_new(NMP_OBJECT_TYPE_LINK, NULL); - obj_new->link.ifindex = ifindex; - obj_new->_link.udev.device = udev_device_ref(udevice); - - _nmp_object_fixup_link_udev_fields(&obj_new, NULL, cache->use_udev); - - _idxcache_update(cache, NULL, obj_new, FALSE, &entry_new); - NM_SET_OUT(out_obj_old, NULL); - NM_SET_OUT(out_obj_new, nmp_object_ref(entry_new->obj)); - return NMP_CACHE_OPS_ADDED; - } else { - obj_old = entry_old->obj; - NM_SET_OUT(out_obj_old, nmp_object_ref(obj_old)); - - if (obj_old->_link.udev.device == udevice) { - NM_SET_OUT(out_obj_new, nmp_object_ref(obj_old)); - return NMP_CACHE_OPS_UNCHANGED; - } - - if (!udevice && !obj_old->_link.netlink.is_in_netlink) { - /* the update would make @obj_old invalid. Remove it. */ - _idxcache_update(cache, entry_old, NULL, FALSE, NULL); - NM_SET_OUT(out_obj_new, NULL); - return NMP_CACHE_OPS_REMOVED; - } - - obj_new = nmp_object_clone(obj_old, FALSE); - - udev_device_unref(obj_new->_link.udev.device); - obj_new->_link.udev.device = udevice ? udev_device_ref(udevice) : NULL; - - _nmp_object_fixup_link_udev_fields(&obj_new, NULL, cache->use_udev); - - _idxcache_update(cache, entry_old, obj_new, FALSE, &entry_new); - NM_SET_OUT(out_obj_new, nmp_object_ref(entry_new->obj)); - return NMP_CACHE_OPS_UPDATED; - } -} - -NMPCacheOpsType -nmp_cache_update_link_master_connected(NMPCache * cache, - int ifindex, - const NMPObject **out_obj_old, - const NMPObject **out_obj_new) -{ - const NMDedupMultiEntry *entry_old; - const NMDedupMultiEntry *entry_new = NULL; - const NMPObject * obj_old; - nm_auto_nmpobj NMPObject *obj_new = NULL; - - entry_old = nmp_cache_lookup_entry_link(cache, ifindex); - - if (!entry_old) { - NM_SET_OUT(out_obj_old, NULL); - NM_SET_OUT(out_obj_new, NULL); - return NMP_CACHE_OPS_UNCHANGED; - } - - obj_old = entry_old->obj; - - if (!nmp_cache_link_connected_needs_toggle(cache, obj_old, NULL, NULL)) { - NM_SET_OUT(out_obj_old, nmp_object_ref(obj_old)); - NM_SET_OUT(out_obj_new, nmp_object_ref(obj_old)); - return NMP_CACHE_OPS_UNCHANGED; - } - - obj_new = nmp_object_clone(obj_old, FALSE); - obj_new->link.connected = !obj_old->link.connected; - - NM_SET_OUT(out_obj_old, nmp_object_ref(obj_old)); - _idxcache_update(cache, entry_old, obj_new, FALSE, &entry_new); - NM_SET_OUT(out_obj_new, nmp_object_ref(entry_new->obj)); - return NMP_CACHE_OPS_UPDATED; -} - -/*****************************************************************************/ - -void -nmp_cache_dirty_set_all_main(NMPCache *cache, const NMPLookup *lookup) -{ - const NMDedupMultiHeadEntry *head_entry; - NMDedupMultiIter iter; - - nm_assert(cache); - nm_assert(lookup); - - head_entry = nmp_cache_lookup(cache, lookup); - - nm_dedup_multi_iter_init(&iter, head_entry); - while (nm_dedup_multi_iter_next(&iter)) { - const NMDedupMultiEntry *main_entry; - - main_entry = nmp_cache_reresolve_main_entry(cache, iter.current, lookup); - - nm_dedup_multi_entry_set_dirty(main_entry, TRUE); - } -} - -/*****************************************************************************/ - -NMPCache * -nmp_cache_new(NMDedupMultiIndex *multi_idx, gboolean use_udev) -{ - NMPCache *cache = g_slice_new0(NMPCache); - guint i; - - for (i = NMP_CACHE_ID_TYPE_NONE + 1; i <= NMP_CACHE_ID_TYPE_MAX; i++) - _dedup_multi_idx_type_init((DedupMultiIdxType *) _idx_type_get(cache, i), i); - - cache->multi_idx = nm_dedup_multi_index_ref(multi_idx); - - cache->use_udev = !!use_udev; - return cache; -} - -void -nmp_cache_free(NMPCache *cache) -{ - guint i; - - for (i = NMP_CACHE_ID_TYPE_NONE + 1; i <= NMP_CACHE_ID_TYPE_MAX; i++) - nm_dedup_multi_index_remove_idx(cache->multi_idx, _idx_type_get(cache, i)); - - nm_dedup_multi_index_unref(cache->multi_idx); - - g_slice_free(NMPCache, cache); -} - -/*****************************************************************************/ - -void -nmtst_assert_nmp_cache_is_consistent(const NMPCache *cache) -{} - -/*****************************************************************************/ - -/* below, ensure that addr_family get's automatically initialize to AF_UNSPEC. */ -G_STATIC_ASSERT(AF_UNSPEC == 0); - -typedef const char *(*CmdPlobjToStringFunc)(const NMPlatformObject *obj, char *buf, gsize len); -typedef const char *(*CmdPlobjToStringIdFunc)(const NMPlatformObject *obj, char *buf, gsize len); -typedef void (*CmdPlobjHashUpdateFunc)(const NMPlatformObject *obj, NMHashState *h); -typedef int (*CmdPlobjCmpFunc)(const NMPlatformObject *obj1, const NMPlatformObject *obj2); - -const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { - [NMP_OBJECT_TYPE_LINK - 1] = - { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .obj_type = NMP_OBJECT_TYPE_LINK, - .sizeof_data = sizeof(NMPObjectLink), - .sizeof_public = sizeof(NMPlatformLink), - .obj_type_name = "link", - .rtm_gettype = RTM_GETLINK, - .signal_type_id = NM_PLATFORM_SIGNAL_ID_LINK, - .signal_type = NM_PLATFORM_SIGNAL_LINK_CHANGED, - .supported_cache_ids = _supported_cache_ids_link, - .cmd_obj_hash_update = _vt_cmd_obj_hash_update_link, - .cmd_obj_cmp = _vt_cmd_obj_cmp_link, - .cmd_obj_copy = _vt_cmd_obj_copy_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_obj_to_string = _vt_cmd_obj_to_string_link, - .cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_link, - .cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_link, - .cmd_plobj_id_hash_update = _vt_cmd_plobj_id_hash_update_link, - .cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_link, - .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_link_to_string, - .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_link_hash_update, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_link_cmp, - }, - [NMP_OBJECT_TYPE_IP4_ADDRESS - 1] = - { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .obj_type = NMP_OBJECT_TYPE_IP4_ADDRESS, - .sizeof_data = sizeof(NMPObjectIP4Address), - .sizeof_public = sizeof(NMPlatformIP4Address), - .obj_type_name = "ip4-address", - .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, - .supported_cache_ids = _supported_cache_ids_ipx_address, - .cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_address, - .cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip4_address, - .cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_ip4_address, - .cmd_plobj_id_hash_update = _vt_cmd_plobj_id_hash_update_ip4_address, - .cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_ip4_address, - .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_ip4_address_to_string, - .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_ip4_address_hash_update, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_ip4_address_cmp, - }, - [NMP_OBJECT_TYPE_IP6_ADDRESS - - 1] = {.parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .obj_type = NMP_OBJECT_TYPE_IP6_ADDRESS, - .sizeof_data = sizeof(NMPObjectIP6Address), - .sizeof_public = sizeof(NMPlatformIP6Address), - .obj_type_name = "ip6-address", - .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, - .supported_cache_ids = _supported_cache_ids_ipx_address, - .cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_address, - .cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip6_address, - .cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_ip6_address, - .cmd_plobj_id_hash_update = _vt_cmd_plobj_id_hash_update_ip6_address, - .cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_ip6_address, - .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_ip6_address_to_string, - .cmd_plobj_hash_update = - (CmdPlobjHashUpdateFunc) nm_platform_ip6_address_hash_update, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_ip6_address_cmp}, - [NMP_OBJECT_TYPE_IP4_ROUTE - 1] = - { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .obj_type = NMP_OBJECT_TYPE_IP4_ROUTE, - .sizeof_data = sizeof(NMPObjectIP4Route), - .sizeof_public = sizeof(NMPlatformIP4Route), - .obj_type_name = "ip4-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, - .supported_cache_ids = _supported_cache_ids_ipx_route, - .cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_route, - .cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip4_route, - .cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_ip4_route, - .cmd_plobj_id_hash_update = _vt_cmd_plobj_id_hash_update_ip4_route, - .cmd_plobj_to_string_id = (CmdPlobjToStringIdFunc) nm_platform_ip4_route_to_string, - .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_ip4_route_to_string, - .cmd_plobj_hash_update = _vt_cmd_plobj_hash_update_ip4_route, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_ip4_route_cmp_full, - }, - [NMP_OBJECT_TYPE_IP6_ROUTE - 1] = - { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .obj_type = NMP_OBJECT_TYPE_IP6_ROUTE, - .sizeof_data = sizeof(NMPObjectIP6Route), - .sizeof_public = sizeof(NMPlatformIP6Route), - .obj_type_name = "ip6-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, - .supported_cache_ids = _supported_cache_ids_ipx_route, - .cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_route, - .cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip6_route, - .cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_ip6_route, - .cmd_plobj_id_hash_update = _vt_cmd_plobj_id_hash_update_ip6_route, - .cmd_plobj_to_string_id = (CmdPlobjToStringIdFunc) nm_platform_ip6_route_to_string, - .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_ip6_route_to_string, - .cmd_plobj_hash_update = _vt_cmd_plobj_hash_update_ip6_route, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_ip6_route_cmp_full, - }, - [NMP_OBJECT_TYPE_ROUTING_RULE - 1] = - { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .obj_type = NMP_OBJECT_TYPE_ROUTING_RULE, - .sizeof_data = sizeof(NMPObjectRoutingRule), - .sizeof_public = sizeof(NMPlatformRoutingRule), - .obj_type_name = "routing-rule", - .rtm_gettype = RTM_GETRULE, - .signal_type_id = NM_PLATFORM_SIGNAL_ID_ROUTING_RULE, - .signal_type = NM_PLATFORM_SIGNAL_ROUTING_RULE_CHANGED, - .supported_cache_ids = _supported_cache_ids_routing_rules, - .cmd_obj_is_alive = _vt_cmd_obj_is_alive_routing_rule, - .cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_routing_rule, - .cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_routing_rule, - .cmd_plobj_id_hash_update = _vt_cmd_plobj_id_hash_update_routing_rule, - .cmd_plobj_to_string_id = (CmdPlobjToStringIdFunc) nm_platform_routing_rule_to_string, - .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_routing_rule_to_string, - .cmd_plobj_hash_update = _vt_cmd_plobj_hash_update_routing_rule, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_routing_rule_cmp_full, - }, - [NMP_OBJECT_TYPE_QDISC - 1] = - { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .obj_type = NMP_OBJECT_TYPE_QDISC, - .sizeof_data = sizeof(NMPObjectQdisc), - .sizeof_public = sizeof(NMPlatformQdisc), - .obj_type_name = "qdisc", - .rtm_gettype = RTM_GETQDISC, - .signal_type_id = NM_PLATFORM_SIGNAL_ID_QDISC, - .signal_type = NM_PLATFORM_SIGNAL_QDISC_CHANGED, - .supported_cache_ids = _supported_cache_ids_object, - .cmd_obj_is_alive = _vt_cmd_obj_is_alive_qdisc, - .cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_qdisc, - .cmd_plobj_id_hash_update = _vt_cmd_plobj_id_hash_update_qdisc, - .cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_qdisc, - .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_qdisc_to_string, - .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_qdisc_hash_update, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_qdisc_cmp, - }, - [NMP_OBJECT_TYPE_TFILTER - 1] = - { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .obj_type = NMP_OBJECT_TYPE_TFILTER, - .sizeof_data = sizeof(NMPObjectTfilter), - .sizeof_public = sizeof(NMPlatformTfilter), - .obj_type_name = "tfilter", - .rtm_gettype = RTM_GETTFILTER, - .signal_type_id = NM_PLATFORM_SIGNAL_ID_TFILTER, - .signal_type = NM_PLATFORM_SIGNAL_TFILTER_CHANGED, - .supported_cache_ids = _supported_cache_ids_object, - .cmd_obj_is_alive = _vt_cmd_obj_is_alive_tfilter, - .cmd_plobj_id_cmp = _vt_cmd_plobj_id_cmp_tfilter, - .cmd_plobj_id_hash_update = _vt_cmd_plobj_id_hash_update_tfilter, - .cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_tfilter, - .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_tfilter_to_string, - .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_tfilter_hash_update, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_tfilter_cmp, - }, - [NMP_OBJECT_TYPE_LNK_BRIDGE - 1] = - { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .obj_type = NMP_OBJECT_TYPE_LNK_BRIDGE, - .sizeof_data = sizeof(NMPObjectLnkBridge), - .sizeof_public = sizeof(NMPlatformLnkBridge), - .obj_type_name = "bridge", - .lnk_link_type = NM_LINK_TYPE_BRIDGE, - .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_lnk_bridge_to_string, - .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_bridge_hash_update, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_bridge_cmp, - }, - [NMP_OBJECT_TYPE_LNK_GRE - 1] = - { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .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 = (CmdPlobjToStringFunc) nm_platform_lnk_gre_to_string, - .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_gre_hash_update, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_gre_cmp, - }, - [NMP_OBJECT_TYPE_LNK_GRETAP - 1] = - { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .obj_type = NMP_OBJECT_TYPE_LNK_GRETAP, - .sizeof_data = sizeof(NMPObjectLnkGre), - .sizeof_public = sizeof(NMPlatformLnkGre), - .obj_type_name = "gretap", - .lnk_link_type = NM_LINK_TYPE_GRETAP, - .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_lnk_gre_to_string, - .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_gre_hash_update, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_gre_cmp, - }, - [NMP_OBJECT_TYPE_LNK_INFINIBAND - 1] = - { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .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 = (CmdPlobjToStringFunc) nm_platform_lnk_infiniband_to_string, - .cmd_plobj_hash_update = - (CmdPlobjHashUpdateFunc) nm_platform_lnk_infiniband_hash_update, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_infiniband_cmp, - }, - [NMP_OBJECT_TYPE_LNK_IP6TNL - 1] = - { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .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 = (CmdPlobjToStringFunc) nm_platform_lnk_ip6tnl_to_string, - .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_ip6tnl_hash_update, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_ip6tnl_cmp, - }, - [NMP_OBJECT_TYPE_LNK_IP6GRE - 1] = - { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .obj_type = NMP_OBJECT_TYPE_LNK_IP6GRE, - .sizeof_data = sizeof(NMPObjectLnkIp6Tnl), - .sizeof_public = sizeof(NMPlatformLnkIp6Tnl), - .obj_type_name = "ip6gre", - .lnk_link_type = NM_LINK_TYPE_IP6GRE, - .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_lnk_ip6tnl_to_string, - .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_ip6tnl_hash_update, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_ip6tnl_cmp, - }, - [NMP_OBJECT_TYPE_LNK_IP6GRETAP - 1] = - { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .obj_type = NMP_OBJECT_TYPE_LNK_IP6GRETAP, - .sizeof_data = sizeof(NMPObjectLnkIp6Tnl), - .sizeof_public = sizeof(NMPlatformLnkIp6Tnl), - .obj_type_name = "ip6gretap", - .lnk_link_type = NM_LINK_TYPE_IP6GRETAP, - .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_lnk_ip6tnl_to_string, - .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_ip6tnl_hash_update, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_ip6tnl_cmp, - }, - [NMP_OBJECT_TYPE_LNK_IPIP - 1] = - { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .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 = (CmdPlobjToStringFunc) nm_platform_lnk_ipip_to_string, - .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_ipip_hash_update, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_ipip_cmp, - }, - [NMP_OBJECT_TYPE_LNK_MACSEC - 1] = - { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .obj_type = NMP_OBJECT_TYPE_LNK_MACSEC, - .sizeof_data = sizeof(NMPObjectLnkMacsec), - .sizeof_public = sizeof(NMPlatformLnkMacsec), - .obj_type_name = "macsec", - .lnk_link_type = NM_LINK_TYPE_MACSEC, - .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_lnk_macsec_to_string, - .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_macsec_hash_update, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_macsec_cmp, - }, - [NMP_OBJECT_TYPE_LNK_MACVLAN - 1] = - { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .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 = (CmdPlobjToStringFunc) nm_platform_lnk_macvlan_to_string, - .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_macvlan_hash_update, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_macvlan_cmp, - }, - [NMP_OBJECT_TYPE_LNK_MACVTAP - 1] = - { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .obj_type = NMP_OBJECT_TYPE_LNK_MACVTAP, - .sizeof_data = sizeof(NMPObjectLnkMacvtap), - .sizeof_public = sizeof(NMPlatformLnkMacvlan), - .obj_type_name = "macvtap", - .lnk_link_type = NM_LINK_TYPE_MACVTAP, - .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_lnk_macvlan_to_string, - .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_macvlan_hash_update, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_macvlan_cmp, - }, - [NMP_OBJECT_TYPE_LNK_SIT - 1] = - { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .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 = (CmdPlobjToStringFunc) nm_platform_lnk_sit_to_string, - .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_sit_hash_update, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_sit_cmp, - }, - [NMP_OBJECT_TYPE_LNK_TUN - 1] = - { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .obj_type = NMP_OBJECT_TYPE_LNK_TUN, - .sizeof_data = sizeof(NMPObjectLnkTun), - .sizeof_public = sizeof(NMPlatformLnkTun), - .obj_type_name = "tun", - .lnk_link_type = NM_LINK_TYPE_TUN, - .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_lnk_tun_to_string, - .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_tun_hash_update, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_tun_cmp, - }, - [NMP_OBJECT_TYPE_LNK_VLAN - 1] = - { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .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_hash_update = _vt_cmd_obj_hash_update_lnk_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 = (CmdPlobjToStringFunc) nm_platform_lnk_vlan_to_string, - .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_vlan_hash_update, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_vlan_cmp, - }, - [NMP_OBJECT_TYPE_LNK_VRF - 1] = - { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .obj_type = NMP_OBJECT_TYPE_LNK_VRF, - .sizeof_data = sizeof(NMPObjectLnkVrf), - .sizeof_public = sizeof(NMPlatformLnkVrf), - .obj_type_name = "vrf", - .lnk_link_type = NM_LINK_TYPE_VRF, - .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_lnk_vrf_to_string, - .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_vrf_hash_update, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_vrf_cmp, - }, - [NMP_OBJECT_TYPE_LNK_VXLAN - 1] = - { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .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 = (CmdPlobjToStringFunc) nm_platform_lnk_vxlan_to_string, - .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_vxlan_hash_update, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_vxlan_cmp, - }, - [NMP_OBJECT_TYPE_LNK_WIREGUARD - 1] = - { - .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), - .obj_type = NMP_OBJECT_TYPE_LNK_WIREGUARD, - .sizeof_data = sizeof(NMPObjectLnkWireGuard), - .sizeof_public = sizeof(NMPlatformLnkWireGuard), - .obj_type_name = "wireguard", - .lnk_link_type = NM_LINK_TYPE_WIREGUARD, - .cmd_obj_hash_update = _vt_cmd_obj_hash_update_lnk_wireguard, - .cmd_obj_cmp = _vt_cmd_obj_cmp_lnk_wireguard, - .cmd_obj_copy = _vt_cmd_obj_copy_lnk_wireguard, - .cmd_obj_dispose = _vt_cmd_obj_dispose_lnk_wireguard, - .cmd_obj_to_string = _vt_cmd_obj_to_string_lnk_wireguard, - .cmd_plobj_to_string = (CmdPlobjToStringFunc) nm_platform_lnk_wireguard_to_string, - .cmd_plobj_hash_update = (CmdPlobjHashUpdateFunc) nm_platform_lnk_wireguard_hash_update, - .cmd_plobj_cmp = (CmdPlobjCmpFunc) nm_platform_lnk_wireguard_cmp, - }, -}; diff --git a/src/core/platform/nmp-object.h b/src/core/platform/nmp-object.h deleted file mode 100644 index 19f6bcd7..00000000 --- a/src/core/platform/nmp-object.h +++ /dev/null @@ -1,1144 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2015 - 2018 Red Hat, Inc. - */ - -#ifndef __NMP_OBJECT_H__ -#define __NMP_OBJECT_H__ - -#include - -#include "nm-glib-aux/nm-obj.h" -#include "nm-glib-aux/nm-dedup-multi.h" -#include "nm-platform.h" - -struct udev_device; - -/*****************************************************************************/ - -/* "struct __kernel_timespec" uses "long long", but we use gint64. In practice, - * these are the same types. */ -G_STATIC_ASSERT(sizeof(long long) == sizeof(gint64)); - -typedef struct { - /* like "struct __kernel_timespec". */ - gint64 tv_sec; - gint64 tv_nsec; -} NMPTimespec64; - -/*****************************************************************************/ - -typedef union { - struct sockaddr sa; - struct sockaddr_in in; - struct sockaddr_in6 in6; -} NMSockAddrUnion; - -G_STATIC_ASSERT(sizeof(NMSockAddrUnion) == sizeof(((NMSockAddrUnion *) NULL)->in6)); - -/* we initialize the largest union member, to ensure that all fields are initialized. */ - -#define NM_SOCK_ADDR_UNION_INIT_UNSPEC \ - { \ - .in6 = { \ - .sin6_family = AF_UNSPEC, \ - }, \ - } - -int nm_sock_addr_union_cmp(const NMSockAddrUnion *a, const NMSockAddrUnion *b); - -void nm_sock_addr_union_hash_update(const NMSockAddrUnion *a, NMHashState *h); - -void nm_sock_addr_union_cpy(NMSockAddrUnion *dst, - gconstpointer src /* unaligned (const NMSockAddrUnion *) */); - -void nm_sock_addr_union_cpy_untrusted(NMSockAddrUnion *dst, - gconstpointer src /* unaligned (const NMSockAddrUnion *) */, - gsize src_len); - -const char *nm_sock_addr_union_to_string(const NMSockAddrUnion *sa, char *buf, gsize len); - -/*****************************************************************************/ - -typedef struct { - NMIPAddr addr; - guint8 family; - guint8 mask; -} NMPWireGuardAllowedIP; - -typedef struct _NMPWireGuardPeer { - NMSockAddrUnion endpoint; - - NMPTimespec64 last_handshake_time; - - guint64 rx_bytes; - guint64 tx_bytes; - - union { - const NMPWireGuardAllowedIP *allowed_ips; - guint _construct_idx_start; - }; - union { - guint allowed_ips_len; - guint _construct_idx_end; - }; - - guint16 persistent_keepalive_interval; - - guint8 public_key[NMP_WIREGUARD_PUBLIC_KEY_LEN]; - guint8 preshared_key[NMP_WIREGUARD_SYMMETRIC_KEY_LEN]; -} NMPWireGuardPeer; - -/*****************************************************************************/ - -typedef enum { /*< skip >*/ - NMP_OBJECT_TO_STRING_ID, - NMP_OBJECT_TO_STRING_PUBLIC, - NMP_OBJECT_TO_STRING_ALL, -} NMPObjectToStringMode; - -typedef enum { /*< skip >*/ - NMP_CACHE_OPS_UNCHANGED = NM_PLATFORM_SIGNAL_NONE, - NMP_CACHE_OPS_ADDED = NM_PLATFORM_SIGNAL_ADDED, - NMP_CACHE_OPS_UPDATED = NM_PLATFORM_SIGNAL_CHANGED, - NMP_CACHE_OPS_REMOVED = NM_PLATFORM_SIGNAL_REMOVED, -} NMPCacheOpsType; - -/* The NMPCacheIdType are the different index types. - * - * An object of a certain object-type, can be candidate to being - * indexed by a certain NMPCacheIdType or not. For example, all - * objects are indexed via an index of type NMP_CACHE_ID_TYPE_OBJECT_TYPE, - * but only route objects can be indexed by NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_NO_DEFAULT. - * - * Of one index type, there can be multiple indexes or not. - * For example, of the index type NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX there - * are multiple instances (for different route/addresses, v4/v6, per-ifindex). - * - * But one object, can only be indexed by one particular index of a - * type. For example, a certain address instance is only indexed by - * the index NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX with - * matching v4/v6 and ifindex -- or maybe not at all if it isn't visible. - * */ -typedef enum { /*< skip >*/ - NMP_CACHE_ID_TYPE_NONE, - - /* all the objects of a certain type. - * - * This index is special. It is the only one that contains *all* object. - * Other indexes may consider some object as non "partitionable", hence - * they don't track all objects. - * - * Hence, this index type is used when looking at all objects (still - * partitioned by type). - * - * Also, note that links may be considered invisible. This index type - * expose all links, even invisible ones. For addresses/routes, this - * distinction doesn't exist, as all addresses/routes that are alive - * are visible as well. */ - NMP_CACHE_ID_TYPE_OBJECT_TYPE, - - /* index for the link objects by ifname. */ - NMP_CACHE_ID_TYPE_LINK_BY_IFNAME, - - /* indices for the visible default-routes, ignoring ifindex. - * This index only contains two partitions: all visible default-routes, - * separate for IPv4 and IPv6. */ - NMP_CACHE_ID_TYPE_DEFAULT_ROUTES, - - /* all the objects that have an ifindex (by object-type) for an ifindex. */ - NMP_CACHE_ID_TYPE_OBJECT_BY_IFINDEX, - - /* Consider all the destination fields of a route, that is, the ID without the ifindex - * and gateway (meaning: network/plen,metric). - * The reason for this is that `ip route change` can replace an existing route - * and modify its ifindex/gateway. Effectively, that means it deletes an existing - * route and adds a different one (as the ID of the route changes). However, it only - * sends one RTM_NEWADDR notification without notifying about the deletion. We detect - * that by having this index to contain overlapping routes which require special - * cache-resync. */ - NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID, - - /* a filter for objects that track an explicit address family. - * - * Note that currently on NMPObjectRoutingRule is indexed by this filter. */ - NMP_CACHE_ID_TYPE_OBJECT_BY_ADDR_FAMILY, - - __NMP_CACHE_ID_TYPE_MAX, - NMP_CACHE_ID_TYPE_MAX = __NMP_CACHE_ID_TYPE_MAX - 1, -} NMPCacheIdType; - -typedef struct { - NMDedupMultiObjClass parent; - const char * obj_type_name; - const char * signal_type; - const guint8 * supported_cache_ids; - int sizeof_data; - int sizeof_public; - int addr_family; - int rtm_gettype; - NMPObjectType obj_type; - NMPlatformSignalIdType signal_type_id; - - /* Only for NMPObjectLnk* types. */ - NMLinkType lnk_link_type; - - void (*cmd_obj_hash_update)(const NMPObject *obj, NMHashState *h); - int (*cmd_obj_cmp)(const NMPObject *obj1, const NMPObject *obj2); - void (*cmd_obj_copy)(NMPObject *dst, 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 */ - void (*cmd_plobj_id_copy)(NMPlatformObject *dst, const NMPlatformObject *src); - int (*cmd_plobj_id_cmp)(const NMPlatformObject *obj1, const NMPlatformObject *obj2); - void (*cmd_plobj_id_hash_update)(const NMPlatformObject *obj, NMHashState *h); - const char *(*cmd_plobj_to_string_id)(const NMPlatformObject *obj, char *buf, gsize buf_size); - const char *(*cmd_plobj_to_string)(const NMPlatformObject *obj, char *buf, gsize len); - void (*cmd_plobj_hash_update)(const NMPlatformObject *obj, NMHashState *h); - int (*cmd_plobj_cmp)(const NMPlatformObject *obj1, const NMPlatformObject *obj2); -} NMPClass; - -extern const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX]; - -typedef struct { - NMPlatformLink _public; - - struct { - bool is_in_netlink; - - /* Additional data that depends on the link-type (IFLA_INFO_DATA) */ - const NMPObject *lnk; - } netlink; - - struct { - /* note that "struct udev_device" references the library context - * "struct udev", but doesn't own it. - * - * Hence, the udev.device shall not be used after the library - * context is destroyed. - * - * In case of NMPObjectLink instances that you obtained from the - * platform cache, that means that you shall no keep references - * to those instances that outlife the NMPlatform instance. - * - * In practice, the requirement is less strict and you'll be even - * fine if the platform instance (and the "struct udev" instance) - * are already destroyed while you still hold onto a reference to - * the NMPObjectLink instance. Just don't make use of udev functions - * that cause access to the udev library context. - */ - struct udev_device *device; - } udev; - - /* Auxiliary data object for Wi-Fi and WPAN */ - GObject *ext_data; - - /* FIXME: not every NMPObjectLink should pay the price for tracking - * the wireguard family id. This should be tracked via ext_data, which - * would be exactly the right place. */ - int wireguard_family_id; -} NMPObjectLink; - -typedef struct { - NMPlatformLnkBridge _public; -} NMPObjectLnkBridge; - -typedef struct { - NMPlatformLnkGre _public; -} NMPObjectLnkGre; - -typedef struct { - NMPlatformLnkInfiniband _public; -} NMPObjectLnkInfiniband; - -typedef struct { - NMPlatformLnkIp6Tnl _public; -} NMPObjectLnkIp6Tnl; - -typedef struct { - NMPlatformLnkIpIp _public; -} NMPObjectLnkIpIp; - -typedef struct { - NMPlatformLnkMacsec _public; -} NMPObjectLnkMacsec; - -typedef struct { - NMPlatformLnkMacvlan _public; -} NMPObjectLnkMacvlan; - -typedef NMPObjectLnkMacvlan NMPObjectLnkMacvtap; - -typedef struct { - NMPlatformLnkSit _public; -} NMPObjectLnkSit; - -typedef struct { - NMPlatformLnkTun _public; -} NMPObjectLnkTun; - -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 { - NMPlatformLnkVrf _public; -} NMPObjectLnkVrf; - -typedef struct { - NMPlatformLnkVxlan _public; -} NMPObjectLnkVxlan; - -typedef struct { - NMPlatformLnkWireGuard _public; - const NMPWireGuardPeer * peers; - const NMPWireGuardAllowedIP *_allowed_ips_buf; - guint peers_len; - guint _allowed_ips_buf_len; -} NMPObjectLnkWireGuard; - -typedef struct { - NMPlatformIP4Address _public; -} NMPObjectIP4Address; - -typedef struct { - NMPlatformIP4Route _public; -} NMPObjectIP4Route; - -typedef struct { - NMPlatformIP6Address _public; -} NMPObjectIP6Address; - -typedef struct { - NMPlatformIP6Route _public; -} NMPObjectIP6Route; - -typedef struct { - NMPlatformRoutingRule _public; -} NMPObjectRoutingRule; - -typedef struct { - NMPlatformQdisc _public; -} NMPObjectQdisc; - -typedef struct { - NMPlatformTfilter _public; -} NMPObjectTfilter; - -struct _NMPObject { - union { - NMDedupMultiObj parent; - const NMPClass *_class; - }; - union { - NMPlatformObject object; - - NMPlatformObjWithIfindex obj_with_ifindex; - - NMPlatformLink link; - NMPObjectLink _link; - - NMPlatformLnkBridge lnk_bridge; - NMPObjectLnkBridge _lnk_bridge; - - NMPlatformLnkGre lnk_gre; - NMPObjectLnkGre _lnk_gre; - - NMPlatformLnkInfiniband lnk_infiniband; - NMPObjectLnkInfiniband _lnk_infiniband; - - NMPlatformLnkIpIp lnk_ipip; - NMPObjectLnkIpIp _lnk_ipip; - - NMPlatformLnkIp6Tnl lnk_ip6tnl; - NMPObjectLnkIp6Tnl _lnk_ip6tnl; - - NMPlatformLnkMacsec lnk_macsec; - NMPObjectLnkMacsec _lnk_macsec; - - NMPlatformLnkMacvlan lnk_macvlan; - NMPObjectLnkMacvlan _lnk_macvlan; - - NMPlatformLnkSit lnk_sit; - NMPObjectLnkSit _lnk_sit; - - NMPlatformLnkTun lnk_tun; - NMPObjectLnkTun _lnk_tun; - - NMPlatformLnkVlan lnk_vlan; - NMPObjectLnkVlan _lnk_vlan; - - NMPlatformLnkVrf lnk_vrf; - NMPObjectLnkVrf _lnk_vrf; - - NMPlatformLnkVxlan lnk_vxlan; - NMPObjectLnkVxlan _lnk_vxlan; - - NMPlatformLnkWireGuard lnk_wireguard; - NMPObjectLnkWireGuard _lnk_wireguard; - - NMPlatformIPAddress ip_address; - NMPlatformIPXAddress ipx_address; - NMPlatformIP4Address ip4_address; - NMPlatformIP6Address ip6_address; - NMPObjectIP4Address _ip4_address; - NMPObjectIP6Address _ip6_address; - - NMPlatformIPRoute ip_route; - NMPlatformIPXRoute ipx_route; - NMPlatformIP4Route ip4_route; - NMPlatformIP6Route ip6_route; - NMPObjectIP4Route _ip4_route; - NMPObjectIP6Route _ip6_route; - - NMPlatformRoutingRule routing_rule; - NMPObjectRoutingRule _routing_rule; - - NMPlatformQdisc qdisc; - NMPObjectQdisc _qdisc; - NMPlatformTfilter tfilter; - NMPObjectTfilter _tfilter; - }; -}; - -/*****************************************************************************/ - -static inline gboolean -NMP_CLASS_IS_VALID(const NMPClass *klass) -{ - return klass >= &_nmp_classes[0] && klass <= &_nmp_classes[G_N_ELEMENTS(_nmp_classes)] - && ((((char *) klass) - ((char *) _nmp_classes)) % (sizeof(_nmp_classes[0]))) == 0; -} - -static inline const NMPClass * -nmp_class_from_type(NMPObjectType obj_type) -{ - nm_assert(obj_type > 0); - nm_assert(obj_type <= G_N_ELEMENTS(_nmp_classes)); - nm_assert(_nmp_classes[obj_type - 1].obj_type == obj_type); - nm_assert(NMP_CLASS_IS_VALID(&_nmp_classes[obj_type - 1])); - - return &_nmp_classes[obj_type - 1]; -} - -static inline NMPObject * -NMP_OBJECT_UP_CAST(const NMPlatformObject *plobj) -{ - NMPObject *obj; - - obj = plobj ? (NMPObject *) (&(((char *) plobj)[-((int) G_STRUCT_OFFSET(NMPObject, object))])) - : NULL; - nm_assert(!obj || (obj->parent._ref_count > 0 && NMP_CLASS_IS_VALID(obj->_class))); - return obj; -} -#define NMP_OBJECT_UP_CAST(plobj) (NMP_OBJECT_UP_CAST((const NMPlatformObject *) (plobj))) - -static inline gboolean -NMP_OBJECT_IS_VALID(const NMPObject *obj) -{ - nm_assert(!obj || (obj && obj->parent._ref_count > 0 && NMP_CLASS_IS_VALID(obj->_class))); - - /* There isn't really much to check. Either @obj is NULL, or we must - * assume that it points to valid memory. */ - return obj != NULL; -} - -static inline gboolean -NMP_OBJECT_IS_STACKINIT(const NMPObject *obj) -{ - nm_assert(!obj || NMP_OBJECT_IS_VALID(obj)); - - return obj && obj->parent._ref_count == NM_OBJ_REF_COUNT_STACKINIT; -} - -static inline const NMPClass * -NMP_OBJECT_GET_CLASS(const NMPObject *obj) -{ - nm_assert(NMP_OBJECT_IS_VALID(obj)); - - return obj->_class; -} - -static inline NMPObjectType -NMP_OBJECT_GET_TYPE(const NMPObject *obj) -{ - nm_assert(!obj || NMP_OBJECT_IS_VALID(obj)); - - return obj ? obj->_class->obj_type : NMP_OBJECT_TYPE_UNKNOWN; -} - -static inline gboolean -_NMP_OBJECT_TYPE_IS_OBJ_WITH_IFINDEX(NMPObjectType obj_type) -{ - switch (obj_type) { - case NMP_OBJECT_TYPE_LINK: - case NMP_OBJECT_TYPE_IP4_ADDRESS: - case NMP_OBJECT_TYPE_IP6_ADDRESS: - case NMP_OBJECT_TYPE_IP4_ROUTE: - case NMP_OBJECT_TYPE_IP6_ROUTE: - - case NMP_OBJECT_TYPE_QDISC: - - case NMP_OBJECT_TYPE_TFILTER: - - case NMP_OBJECT_TYPE_LNK_BRIDGE: - case NMP_OBJECT_TYPE_LNK_GRE: - case NMP_OBJECT_TYPE_LNK_GRETAP: - case NMP_OBJECT_TYPE_LNK_INFINIBAND: - case NMP_OBJECT_TYPE_LNK_IP6TNL: - case NMP_OBJECT_TYPE_LNK_IP6GRE: - case NMP_OBJECT_TYPE_LNK_IP6GRETAP: - case NMP_OBJECT_TYPE_LNK_IPIP: - case NMP_OBJECT_TYPE_LNK_MACSEC: - case NMP_OBJECT_TYPE_LNK_MACVLAN: - case NMP_OBJECT_TYPE_LNK_MACVTAP: - case NMP_OBJECT_TYPE_LNK_SIT: - case NMP_OBJECT_TYPE_LNK_TUN: - case NMP_OBJECT_TYPE_LNK_VLAN: - case NMP_OBJECT_TYPE_LNK_VRF: - case NMP_OBJECT_TYPE_LNK_VXLAN: - case NMP_OBJECT_TYPE_LNK_WIREGUARD: - return TRUE; - - case NMP_OBJECT_TYPE_ROUTING_RULE: - return FALSE; - - case NMP_OBJECT_TYPE_UNKNOWN: - case __NMP_OBJECT_TYPE_LAST: - break; - } - nm_assert_not_reached(); - return FALSE; -} - -#define NMP_OBJECT_CAST_OBJECT(obj) \ - ({ \ - typeof(obj) _obj = (obj); \ - \ - nm_assert ( !_obj \ - || nmp_class_from_type (NMP_OBJECT_GET_TYPE (_obj)))); \ - _obj ? &NM_CONSTCAST(NMPObject, _obj)->object : NULL; \ - }) - -#define NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj) \ - ({ \ - typeof(obj) _obj = (obj); \ - \ - nm_assert(!_obj || _NMP_OBJECT_TYPE_IS_OBJ_WITH_IFINDEX(NMP_OBJECT_GET_TYPE(_obj))); \ - _obj ? &NM_CONSTCAST(NMPObject, _obj)->obj_with_ifindex : NULL; \ - }) - -#define _NMP_OBJECT_CAST(obj, field, ...) \ - ({ \ - typeof(obj) _obj = (obj); \ - \ - nm_assert(!_obj || NM_IN_SET(NMP_OBJECT_GET_TYPE(_obj), __VA_ARGS__)); \ - _obj ? &NM_CONSTCAST(NMPObject, _obj)->field : NULL; \ - }) - -#define NMP_OBJECT_CAST_LINK(obj) _NMP_OBJECT_CAST(obj, link, NMP_OBJECT_TYPE_LINK) -#define NMP_OBJECT_CAST_IP_ADDRESS(obj) \ - _NMP_OBJECT_CAST(obj, ip_address, NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS) -#define NMP_OBJECT_CAST_IPX_ADDRESS(obj) \ - _NMP_OBJECT_CAST(obj, ipx_address, NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS) -#define NMP_OBJECT_CAST_IP4_ADDRESS(obj) \ - _NMP_OBJECT_CAST(obj, ip4_address, NMP_OBJECT_TYPE_IP4_ADDRESS) -#define NMP_OBJECT_CAST_IP6_ADDRESS(obj) \ - _NMP_OBJECT_CAST(obj, ip6_address, NMP_OBJECT_TYPE_IP6_ADDRESS) -#define NMP_OBJECT_CAST_IP_ROUTE(obj) \ - _NMP_OBJECT_CAST(obj, ip_route, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE) -#define NMP_OBJECT_CAST_IPX_ROUTE(obj) \ - _NMP_OBJECT_CAST(obj, ipx_route, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE) -#define NMP_OBJECT_CAST_IP4_ROUTE(obj) _NMP_OBJECT_CAST(obj, ip4_route, NMP_OBJECT_TYPE_IP4_ROUTE) -#define NMP_OBJECT_CAST_IP6_ROUTE(obj) _NMP_OBJECT_CAST(obj, ip6_route, NMP_OBJECT_TYPE_IP6_ROUTE) -#define NMP_OBJECT_CAST_ROUTING_RULE(obj) \ - _NMP_OBJECT_CAST(obj, routing_rule, NMP_OBJECT_TYPE_ROUTING_RULE) -#define NMP_OBJECT_CAST_QDISC(obj) _NMP_OBJECT_CAST(obj, qdisc, NMP_OBJECT_TYPE_QDISC) -#define NMP_OBJECT_CAST_TFILTER(obj) _NMP_OBJECT_CAST(obj, tfilter, NMP_OBJECT_TYPE_TFILTER) -#define NMP_OBJECT_CAST_LNK_WIREGUARD(obj) \ - _NMP_OBJECT_CAST(obj, lnk_wireguard, NMP_OBJECT_TYPE_LNK_WIREGUARD) -#define NMP_OBJECT_CAST_LNK_BRIDGE(obj) \ - _NMP_OBJECT_CAST(obj, lnk_bridge, NMP_OBJECT_TYPE_LNK_BRIDGE) - -static inline int -NMP_OBJECT_TYPE_TO_ADDR_FAMILY(NMPObjectType obj_type) -{ - return nmp_class_from_type(obj_type)->addr_family; -} - -static inline int -NMP_OBJECT_GET_ADDR_FAMILY(const NMPObject *obj) -{ - return NMP_OBJECT_GET_CLASS(obj)->addr_family; -} - -static inline const NMPObject * -nmp_object_ref(const NMPObject *obj) -{ - if (!obj) { - /* for convenience, allow NULL. */ - return NULL; - } - - /* ref and unref accept const pointers. NMPObject is supposed to be shared - * and kept immutable. Disallowing to take/return a reference to a const - * NMPObject is cumbersome, because callers are precisely expected to - * keep a ref on the otherwise immutable object. */ - g_return_val_if_fail(NMP_OBJECT_IS_VALID(obj), NULL); - g_return_val_if_fail(obj->parent._ref_count != NM_OBJ_REF_COUNT_STACKINIT, NULL); - - return (const NMPObject *) nm_dedup_multi_obj_ref((const NMDedupMultiObj *) obj); -} - -static inline void -nmp_object_unref(const NMPObject *obj) -{ - if (obj) { - nm_assert(NMP_OBJECT_IS_VALID(obj)); - - nm_dedup_multi_obj_unref((const NMDedupMultiObj *) obj); - } -} - -#define nm_clear_nmp_object(ptr) \ - ({ \ - typeof(ptr) _ptr = (ptr); \ - typeof(*_ptr) _pptr; \ - gboolean _changed = FALSE; \ - \ - if (_ptr && (_pptr = *_ptr)) { \ - *_ptr = NULL; \ - nmp_object_unref(_pptr); \ - _changed = TRUE; \ - } \ - _changed; \ - }) - -static inline gboolean -nmp_object_ref_set(const NMPObject **pp, const NMPObject *obj) -{ - gboolean _changed = FALSE; - const NMPObject *p; - - nm_assert(!pp || !*pp || NMP_OBJECT_IS_VALID(*pp)); - nm_assert(!obj || NMP_OBJECT_IS_VALID(obj)); - - if (pp && ((p = *pp) != obj)) { - nmp_object_ref(obj); - *pp = obj; - nmp_object_unref(p); - _changed = TRUE; - } - return _changed; -} - -NMPObject *nmp_object_new(NMPObjectType obj_type, gconstpointer plobj); -NMPObject *nmp_object_new_link(int ifindex); - -const NMPObject *nmp_object_stackinit(NMPObject *obj, NMPObjectType obj_type, gconstpointer plobj); - -static inline NMPObject * -nmp_object_stackinit_obj(NMPObject *obj, const NMPObject *src) -{ - return obj == src - ? obj - : (NMPObject *) nmp_object_stackinit(obj, NMP_OBJECT_GET_TYPE(src), &src->object); -} - -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, - guint8 plen, - guint32 peer_address); -const NMPObject * -nmp_object_stackinit_id_ip6_address(NMPObject *obj, int ifindex, const struct in6_addr *address); - -const char *nmp_object_to_string(const NMPObject * obj, - NMPObjectToStringMode to_string_mode, - char * buf, - gsize buf_size); -void nmp_object_hash_update(const NMPObject *obj, NMHashState *h); -int nmp_object_cmp(const NMPObject *obj1, const NMPObject *obj2); - -static inline gboolean -nmp_object_equal(const NMPObject *obj1, const NMPObject *obj2) -{ - return nmp_object_cmp(obj1, obj2) == 0; -} - -void nmp_object_copy(NMPObject *dst, const NMPObject *src, gboolean id_only); -NMPObject *nmp_object_clone(const NMPObject *obj, gboolean id_only); - -int nmp_object_id_cmp(const NMPObject *obj1, const NMPObject *obj2); -void nmp_object_id_hash_update(const NMPObject *obj, NMHashState *h); -guint nmp_object_id_hash(const NMPObject *obj); - -static inline gboolean -nmp_object_id_equal(const NMPObject *obj1, const NMPObject *obj2) -{ - return nmp_object_id_cmp(obj1, obj2) == 0; -} - -guint nmp_object_indirect_id_hash(gconstpointer a); -gboolean nmp_object_indirect_id_equal(gconstpointer a, gconstpointer b); - -gboolean nmp_object_is_alive(const NMPObject *obj); -gboolean nmp_object_is_visible(const NMPObject *obj); - -void -_nmp_object_fixup_link_udev_fields(NMPObject **obj_new, NMPObject *obj_orig, gboolean use_udev); - -static inline void -_nm_auto_nmpobj_cleanup(gpointer p) -{ - nmp_object_unref(*((const NMPObject **) p)); -} -#define nm_auto_nmpobj nm_auto(_nm_auto_nmpobj_cleanup) - -typedef struct _NMPCache NMPCache; - -typedef void (*NMPCachePreHook)(NMPCache * cache, - const NMPObject *old, - const NMPObject *new, - NMPCacheOpsType ops_type, - gpointer user_data); -typedef gboolean (*NMPObjectMatchFn)(const NMPObject *obj, gpointer user_data); - -const NMDedupMultiEntry *nmp_cache_lookup_entry(const NMPCache *cache, const NMPObject *obj); -const NMDedupMultiEntry *nmp_cache_lookup_entry_with_idx_type(const NMPCache * cache, - NMPCacheIdType cache_id_type, - const NMPObject *obj); -const NMDedupMultiEntry *nmp_cache_lookup_entry_link(const NMPCache *cache, int ifindex); -const NMPObject * nmp_cache_lookup_obj(const NMPCache *cache, const NMPObject *obj); -const NMPObject * nmp_cache_lookup_link(const NMPCache *cache, int ifindex); - -typedef struct _NMPLookup NMPLookup; - -struct _NMPLookup { - NMPCacheIdType cache_id_type; - NMPObject selector_obj; -}; - -const NMDedupMultiHeadEntry *nmp_cache_lookup_all(const NMPCache * cache, - NMPCacheIdType cache_id_type, - const NMPObject *select_obj); - -static inline const NMDedupMultiHeadEntry * -nmp_cache_lookup(const NMPCache *cache, const NMPLookup *lookup) -{ - return nmp_cache_lookup_all(cache, lookup->cache_id_type, &lookup->selector_obj); -} - -const NMPLookup *nmp_lookup_init_obj_type(NMPLookup *lookup, NMPObjectType obj_type); -const NMPLookup *nmp_lookup_init_link_by_ifname(NMPLookup *lookup, const char *ifname); -const NMPLookup *nmp_lookup_init_object(NMPLookup *lookup, NMPObjectType obj_type, int ifindex); -const NMPLookup *nmp_lookup_init_route_default(NMPLookup *lookup, NMPObjectType obj_type); -const NMPLookup *nmp_lookup_init_route_by_weak_id(NMPLookup *lookup, const NMPObject *obj); -const NMPLookup *nmp_lookup_init_ip4_route_by_weak_id(NMPLookup *lookup, - in_addr_t network, - guint plen, - guint32 metric, - guint8 tos); -const NMPLookup *nmp_lookup_init_ip6_route_by_weak_id(NMPLookup * lookup, - const struct in6_addr *network, - guint plen, - guint32 metric, - const struct in6_addr *src, - guint8 src_plen); -const NMPLookup * -nmp_lookup_init_object_by_addr_family(NMPLookup *lookup, NMPObjectType obj_type, int addr_family); - -GArray *nmp_cache_lookup_to_array(const NMDedupMultiHeadEntry *head_entry, - NMPObjectType obj_type, - gboolean visible_only); - -static inline gboolean -nmp_cache_iter_next(NMDedupMultiIter *iter, const NMPObject **out_obj) -{ - gboolean has_next; - - has_next = nm_dedup_multi_iter_next(iter); - nm_assert(!has_next || NMP_OBJECT_IS_VALID(iter->current->obj)); - if (out_obj) - *out_obj = has_next ? iter->current->obj : NULL; - return has_next; -} - -static inline gboolean -nmp_cache_iter_next_link(NMDedupMultiIter *iter, const NMPlatformLink **out_obj) -{ - gboolean has_next; - - has_next = nm_dedup_multi_iter_next(iter); - nm_assert(!has_next || NMP_OBJECT_GET_TYPE(iter->current->obj) == NMP_OBJECT_TYPE_LINK); - if (out_obj) - *out_obj = has_next ? &(((const NMPObject *) iter->current->obj)->link) : NULL; - return has_next; -} - -#define nmp_cache_iter_for_each(iter, head, obj) \ - for (nm_dedup_multi_iter_init((iter), (head)); nmp_cache_iter_next((iter), (obj));) - -#define nmp_cache_iter_for_each_link(iter, head, obj) \ - for (nm_dedup_multi_iter_init((iter), (head)); nmp_cache_iter_next_link((iter), (obj));) - -const NMPObject *nmp_cache_lookup_link_full(const NMPCache * cache, - int ifindex, - const char * ifname, - gboolean visible_only, - NMLinkType link_type, - NMPObjectMatchFn match_fn, - gpointer user_data); - -gboolean nmp_cache_link_connected_for_slave(int ifindex_master, const NMPObject *slave); -gboolean nmp_cache_link_connected_needs_toggle(const NMPCache * cache, - const NMPObject *master, - const NMPObject *potential_slave, - const NMPObject *ignore_slave); -const NMPObject *nmp_cache_link_connected_needs_toggle_by_ifindex(const NMPCache * cache, - int master_ifindex, - const NMPObject *potential_slave, - const NMPObject *ignore_slave); - -gboolean nmp_cache_use_udev_get(const NMPCache *cache); - -void nmtst_assert_nmp_cache_is_consistent(const NMPCache *cache); - -NMPCacheOpsType nmp_cache_remove(NMPCache * cache, - const NMPObject * obj_needle, - gboolean equals_by_ptr, - gboolean only_dirty, - const NMPObject **out_obj_old); -NMPCacheOpsType nmp_cache_remove_netlink(NMPCache * cache, - const NMPObject * obj_needle, - const NMPObject **out_obj_old, - const NMPObject **out_obj_new); -NMPCacheOpsType nmp_cache_update_netlink(NMPCache * cache, - NMPObject * obj_hand_over, - gboolean is_dump, - const NMPObject **out_obj_old, - const NMPObject **out_obj_new); -NMPCacheOpsType nmp_cache_update_netlink_route(NMPCache * cache, - NMPObject * obj_hand_over, - gboolean is_dump, - guint16 nlmsgflags, - const NMPObject **out_obj_old, - const NMPObject **out_obj_new, - const NMPObject **out_obj_replace, - gboolean * out_resync_required); -NMPCacheOpsType nmp_cache_update_link_udev(NMPCache * cache, - int ifindex, - struct udev_device *udevice, - const NMPObject ** out_obj_old, - const NMPObject ** out_obj_new); -NMPCacheOpsType nmp_cache_update_link_master_connected(NMPCache * cache, - int ifindex, - const NMPObject **out_obj_old, - const NMPObject **out_obj_new); - -static inline const NMDedupMultiEntry * -nmp_cache_reresolve_main_entry(NMPCache * cache, - const NMDedupMultiEntry *entry, - const NMPLookup * lookup) -{ - const NMDedupMultiEntry *main_entry; - - nm_assert(cache); - nm_assert(entry); - nm_assert(lookup); - - if (lookup->cache_id_type == NMP_CACHE_ID_TYPE_OBJECT_TYPE) { - nm_assert(entry == nmp_cache_lookup_entry(cache, entry->obj)); - return entry; - } - - /* we only track the dirty flag for the OBJECT-TYPE index. That means, - * for other lookup types we need to check the dirty flag of the main-entry. */ - main_entry = nmp_cache_lookup_entry(cache, entry->obj); - - nm_assert(main_entry); - nm_assert(main_entry->obj == entry->obj); - - return main_entry; -} - -void nmp_cache_dirty_set_all_main(NMPCache *cache, const NMPLookup *lookup); - -NMPCache *nmp_cache_new(NMDedupMultiIndex *multi_idx, gboolean use_udev); -void nmp_cache_free(NMPCache *cache); - -static inline void -ASSERT_nmp_cache_ops(const NMPCache * cache, - NMPCacheOpsType ops_type, - const NMPObject *obj_old, - const NMPObject *obj_new) -{ -#if NM_MORE_ASSERTS - nm_assert(cache); - nm_assert(obj_old || obj_new); - nm_assert(!obj_old - || (NMP_OBJECT_IS_VALID(obj_old) && !NMP_OBJECT_IS_STACKINIT(obj_old) - && nmp_object_is_alive(obj_old))); - nm_assert(!obj_new - || (NMP_OBJECT_IS_VALID(obj_new) && !NMP_OBJECT_IS_STACKINIT(obj_new) - && nmp_object_is_alive(obj_new))); - - switch (ops_type) { - case NMP_CACHE_OPS_UNCHANGED: - nm_assert(obj_old == obj_new); - break; - case NMP_CACHE_OPS_ADDED: - nm_assert(!obj_old && obj_new); - break; - case NMP_CACHE_OPS_UPDATED: - nm_assert(obj_old && obj_new && obj_old != obj_new); - break; - case NMP_CACHE_OPS_REMOVED: - nm_assert(obj_old && !obj_new); - break; - default: - nm_assert_not_reached(); - } - - nm_assert(obj_new == NULL || obj_old == NULL || nmp_object_id_equal(obj_new, obj_old)); - nm_assert(!obj_old || !obj_new - || NMP_OBJECT_GET_CLASS(obj_old) == NMP_OBJECT_GET_CLASS(obj_new)); - - nm_assert(obj_new == nmp_cache_lookup_obj(cache, obj_new ?: obj_old)); -#endif -} - -const NMDedupMultiHeadEntry * -nm_platform_lookup_all(NMPlatform *platform, NMPCacheIdType cache_id_type, const NMPObject *obj); - -const NMDedupMultiEntry * -nm_platform_lookup_entry(NMPlatform *platform, NMPCacheIdType cache_id_type, const NMPObject *obj); - -static inline const NMPObject * -nm_platform_lookup_obj(NMPlatform *platform, NMPCacheIdType cache_id_type, const NMPObject *obj) -{ - return nm_dedup_multi_entry_get_obj(nm_platform_lookup_entry(platform, cache_id_type, obj)); -} - -static inline const NMDedupMultiHeadEntry * -nm_platform_lookup_obj_type(NMPlatform *platform, NMPObjectType obj_type) -{ - NMPLookup lookup; - - nmp_lookup_init_obj_type(&lookup, obj_type); - return nm_platform_lookup(platform, &lookup); -} - -static inline const NMDedupMultiHeadEntry * -nm_platform_lookup_link_by_ifname(NMPlatform *platform, const char *ifname) -{ - NMPLookup lookup; - - nmp_lookup_init_link_by_ifname(&lookup, ifname); - return nm_platform_lookup(platform, &lookup); -} - -static inline const NMDedupMultiHeadEntry * -nm_platform_lookup_object(NMPlatform *platform, NMPObjectType obj_type, int ifindex) -{ - NMPLookup lookup; - - nmp_lookup_init_object(&lookup, obj_type, ifindex); - return nm_platform_lookup(platform, &lookup); -} - -static inline GPtrArray * -nm_platform_lookup_object_clone(NMPlatform * platform, - NMPObjectType obj_type, - int ifindex, - NMPObjectPredicateFunc predicate, - gpointer user_data) -{ - NMPLookup lookup; - - nmp_lookup_init_object(&lookup, obj_type, ifindex); - return nm_platform_lookup_clone(platform, &lookup, predicate, user_data); -} - -static inline const NMDedupMultiHeadEntry * -nm_platform_lookup_route_default(NMPlatform *platform, NMPObjectType obj_type) -{ - NMPLookup lookup; - - nmp_lookup_init_route_default(&lookup, obj_type); - return nm_platform_lookup(platform, &lookup); -} - -static inline GPtrArray * -nm_platform_lookup_route_default_clone(NMPlatform * platform, - NMPObjectType obj_type, - NMPObjectPredicateFunc predicate, - gpointer user_data) -{ - NMPLookup lookup; - - nmp_lookup_init_route_default(&lookup, obj_type); - return nm_platform_lookup_clone(platform, &lookup, predicate, user_data); -} - -static inline const NMDedupMultiHeadEntry * -nm_platform_lookup_ip4_route_by_weak_id(NMPlatform *platform, - in_addr_t network, - guint plen, - guint32 metric, - guint8 tos) -{ - NMPLookup lookup; - - nmp_lookup_init_ip4_route_by_weak_id(&lookup, network, plen, metric, tos); - return nm_platform_lookup(platform, &lookup); -} - -static inline const NMDedupMultiHeadEntry * -nm_platform_lookup_ip6_route_by_weak_id(NMPlatform * platform, - const struct in6_addr *network, - guint plen, - guint32 metric, - const struct in6_addr *src, - guint8 src_plen) -{ - NMPLookup lookup; - - nmp_lookup_init_ip6_route_by_weak_id(&lookup, network, plen, metric, src, src_plen); - return nm_platform_lookup(platform, &lookup); -} - -static inline const NMDedupMultiHeadEntry * -nm_platform_lookup_object_by_addr_family(NMPlatform * platform, - NMPObjectType obj_type, - int addr_family) -{ - NMPLookup lookup; - - nmp_lookup_init_object_by_addr_family(&lookup, obj_type, addr_family); - return nm_platform_lookup(platform, &lookup); -} - -/*****************************************************************************/ - -static inline const char * -nmp_object_link_get_ifname(const NMPObject *obj) -{ - if (!obj) - return NULL; - return NMP_OBJECT_CAST_LINK(obj)->name; -} - -static inline gboolean -nmp_object_ip_route_is_best_defaut_route(const NMPObject *obj) -{ - const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE(obj); - - /* return whether @obj is considered a default-route. - * - * NMIP4Config/NMIP6Config tracks the (best) default-route explicitly, because - * at various places we act differently depending on whether there is a default-route - * configured. - * - * Note that this only considers the main routing table. */ - return r && NM_PLATFORM_IP_ROUTE_IS_DEFAULT(r) - && nm_platform_route_table_is_main(r->table_coerced) - && r->type_coerced == nm_platform_route_type_coerce(1 /* RTN_UNICAST */); -} - -static inline gboolean -nmp_object_ip6_address_is_not_link_local(const NMPObject *obj) -{ - return !IN6_IS_ADDR_LINKLOCAL(&NMP_OBJECT_CAST_IP6_ADDRESS(obj)->address); -} - -/*****************************************************************************/ - -static inline gboolean -nm_platform_dedup_multi_iter_next_obj(NMDedupMultiIter *ipconf_iter, - const NMPObject **out_obj, - NMPObjectType assert_obj_type) -{ - gboolean has_next; - - has_next = nm_dedup_multi_iter_next(ipconf_iter); - nm_assert(assert_obj_type == NMP_OBJECT_TYPE_UNKNOWN || !has_next - || NMP_OBJECT_GET_TYPE(ipconf_iter->current->obj) == assert_obj_type); - NM_SET_OUT(out_obj, has_next ? ipconf_iter->current->obj : NULL); - return has_next; -} - -#define _nm_platform_dedup_multi_iter_next(ipconf_iter, out_obj, field, ...) \ - ({ \ - NMDedupMultiIter *const _ipconf_iter = (ipconf_iter); \ - const typeof(((NMPObject *) NULL)->field) **const _out_obj = (out_obj); \ - gboolean _has_next; \ - \ - if (G_LIKELY(nm_dedup_multi_iter_next(_ipconf_iter))) { \ - if (_out_obj) { \ - *_out_obj = _NMP_OBJECT_CAST(_ipconf_iter->current->obj, field, __VA_ARGS__); \ - } else { \ - nm_assert( \ - NM_IN_SET(NMP_OBJECT_GET_TYPE(_ipconf_iter->current->obj), __VA_ARGS__)); \ - } \ - _has_next = TRUE; \ - } else { \ - if (_out_obj) \ - *_out_obj = NULL; \ - _has_next = FALSE; \ - } \ - _has_next; \ - }) - -#define nm_platform_dedup_multi_iter_next_ip_address(ipconf_iter, out_obj) \ - _nm_platform_dedup_multi_iter_next((ipconf_iter), \ - (out_obj), \ - ip_address, \ - NMP_OBJECT_TYPE_IP4_ADDRESS, \ - NMP_OBJECT_TYPE_IP6_ADDRESS) - -#define nm_platform_dedup_multi_iter_next_ip4_address(ipconf_iter, out_obj) \ - _nm_platform_dedup_multi_iter_next((ipconf_iter), \ - (out_obj), \ - ip4_address, \ - NMP_OBJECT_TYPE_IP4_ADDRESS) - -#define nm_platform_dedup_multi_iter_next_ip6_address(ipconf_iter, out_obj) \ - _nm_platform_dedup_multi_iter_next((ipconf_iter), \ - (out_obj), \ - ip6_address, \ - NMP_OBJECT_TYPE_IP6_ADDRESS) - -#define nm_platform_dedup_multi_iter_next_ip_route(ipconf_iter, out_obj) \ - _nm_platform_dedup_multi_iter_next((ipconf_iter), \ - (out_obj), \ - ip_route, \ - NMP_OBJECT_TYPE_IP4_ROUTE, \ - NMP_OBJECT_TYPE_IP6_ROUTE) - -#define nm_platform_dedup_multi_iter_next_ip4_route(ipconf_iter, out_obj) \ - _nm_platform_dedup_multi_iter_next((ipconf_iter), \ - (out_obj), \ - ip4_route, \ - NMP_OBJECT_TYPE_IP4_ROUTE) - -#define nm_platform_dedup_multi_iter_next_ip6_route(ipconf_iter, out_obj) \ - _nm_platform_dedup_multi_iter_next((ipconf_iter), \ - (out_obj), \ - ip6_route, \ - NMP_OBJECT_TYPE_IP6_ROUTE) - -#endif /* __NMP_OBJECT_H__ */ diff --git a/src/core/platform/nmp-rules-manager.c b/src/core/platform/nmp-rules-manager.c deleted file mode 100644 index 0c617b80..00000000 --- a/src/core/platform/nmp-rules-manager.c +++ /dev/null @@ -1,808 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include "src/core/nm-default-daemon.h" - -#include "nmp-rules-manager.h" - -#include -#include - -#include "nm-std-aux/c-list-util.h" -#include "nmp-object.h" - -/*****************************************************************************/ - -struct _NMPRulesManager { - NMPlatform *platform; - GHashTable *by_obj; - GHashTable *by_user_tag; - GHashTable *by_data; - guint ref_count; -}; - -/*****************************************************************************/ - -static void _rules_init(NMPRulesManager *self); - -/*****************************************************************************/ - -#define _NMLOG_DOMAIN LOGD_PLATFORM -#define _NMLOG_PREFIX_NAME "rules-manager" - -#define _NMLOG(level, ...) \ - G_STMT_START \ - { \ - const NMLogLevel __level = (level); \ - \ - if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) { \ - _nm_log(__level, \ - _NMLOG_DOMAIN, \ - 0, \ - NULL, \ - NULL, \ - "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - _NMLOG_PREFIX_NAME _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } \ - G_STMT_END - -/*****************************************************************************/ - -static gboolean -NMP_IS_RULES_MANAGER(gpointer self) -{ - return self && ((NMPRulesManager *) self)->ref_count > 0 - && NM_IS_PLATFORM(((NMPRulesManager *) self)->platform); -} - -#define _USER_TAG_LOG(user_tag) nm_hash_obfuscate_ptr(1240261787u, (user_tag)) - -/*****************************************************************************/ - -typedef struct { - const NMPObject *obj; - gconstpointer user_tag; - CList obj_lst; - CList user_tag_lst; - - /* track_priority_val zero is special: those are weakly tracked rules. - * That means: NetworkManager will restore them only if it removed them earlier. - * But it will not remove or add them otherwise. - * - * Otherwise, the track_priority_val goes together with track_priority_present. - * In case of one rule being tracked multiple times (with different priorities), - * the one with higher priority wins. See _rules_obj_get_best_data(). - * Then, the winning present state either enforces that the rule is present - * or absent. - * - * If a rules is not tracked at all, it is ignored by NetworkManager. Assuming - * that it was added externally by the user. But unlike weakly tracked rules, - * NM will *not* restore such rules if NetworkManager themself removed them. */ - guint32 track_priority_val; - bool track_priority_present : 1; - - bool dirty : 1; -} RulesData; - -typedef enum { - CONFIG_STATE_NONE = 0, - CONFIG_STATE_ADDED_BY_US = 1, - CONFIG_STATE_REMOVED_BY_US = 2, - - /* ConfigState encodes whether the rule was touched by us at all (CONFIG_STATE_NONE). - * - * Maybe we would only need to track whether we touched the rule at all. But we - * track it more in detail what we did: did we add it (CONFIG_STATE_ADDED_BY_US) - * or did we remove it (CONFIG_STATE_REMOVED_BY_US)? - * Finally, we need CONFIG_STATE_OWNED_BY_US, which means that we didn't actively - * add/remove it, but whenever we are about to undo the add/remove, we need to do it. - * In that sense, CONFIG_STATE_OWNED_BY_US is really just a flag that we unconditionally - * force the state next time when necessary. */ - CONFIG_STATE_OWNED_BY_US = 3, -} ConfigState; - -typedef struct { - const NMPObject *obj; - CList obj_lst_head; - - /* indicates whether we configured/removed the rule (during sync()). We need that, so - * if the rule gets untracked, that we know to remove/restore it. - * - * This makes NMPRulesManager stateful (beyond the configuration that indicates - * which rules are tracked). - * After a restart, NetworkManager would no longer remember which rules were added - * by us. - * - * That is partially fixed by NetworkManager taking over the rules that it - * actively configures (see %NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG). */ - ConfigState config_state; -} RulesObjData; - -typedef struct { - gconstpointer user_tag; - CList user_tag_lst_head; -} RulesUserTagData; - -/*****************************************************************************/ - -static void _rules_data_untrack(NMPRulesManager *self, - RulesData * rules_data, - gboolean remove_user_tag_data, - gboolean make_owned_by_us); - -/*****************************************************************************/ - -static void -_rules_data_assert(const RulesData *rules_data, gboolean linked) -{ - nm_assert(rules_data); - nm_assert(NMP_OBJECT_GET_TYPE(rules_data->obj) == NMP_OBJECT_TYPE_ROUTING_RULE); - nm_assert(nmp_object_is_visible(rules_data->obj)); - nm_assert(rules_data->user_tag); - nm_assert(!linked || !c_list_is_empty(&rules_data->obj_lst)); - nm_assert(!linked || !c_list_is_empty(&rules_data->user_tag_lst)); -} - -static guint -_rules_data_hash(gconstpointer data) -{ - const RulesData *rules_data = data; - NMHashState h; - - _rules_data_assert(rules_data, FALSE); - - nm_hash_init(&h, 269297543u); - nm_platform_routing_rule_hash_update(NMP_OBJECT_CAST_ROUTING_RULE(rules_data->obj), - NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID, - &h); - nm_hash_update_val(&h, rules_data->user_tag); - return nm_hash_complete(&h); -} - -static gboolean -_rules_data_equal(gconstpointer data_a, gconstpointer data_b) -{ - const RulesData *rules_data_a = data_a; - const RulesData *rules_data_b = data_b; - - _rules_data_assert(rules_data_a, FALSE); - _rules_data_assert(rules_data_b, FALSE); - - return rules_data_a->user_tag == rules_data_b->user_tag - && (nm_platform_routing_rule_cmp(NMP_OBJECT_CAST_ROUTING_RULE(rules_data_a->obj), - NMP_OBJECT_CAST_ROUTING_RULE(rules_data_b->obj), - NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID) - == 0); -} - -static void -_rules_data_destroy(gpointer data) -{ - RulesData *rules_data = data; - - _rules_data_assert(rules_data, FALSE); - - c_list_unlink_stale(&rules_data->obj_lst); - c_list_unlink_stale(&rules_data->user_tag_lst); - nmp_object_unref(rules_data->obj); - g_slice_free(RulesData, rules_data); -} - -static const RulesData * -_rules_obj_get_best_data(RulesObjData *obj_data) -{ - RulesData * rules_data; - const RulesData *rd_best = NULL; - - c_list_for_each_entry (rules_data, &obj_data->obj_lst_head, obj_lst) { - _rules_data_assert(rules_data, TRUE); - - if (rd_best) { - if (rd_best->track_priority_val > rules_data->track_priority_val) - continue; - if (rd_best->track_priority_val == rules_data->track_priority_val) { - if (rd_best->track_priority_present || !rules_data->track_priority_present) { - /* if the priorities are identical, then "present" wins over - * "!present" (absent). */ - continue; - } - } - } - - rd_best = rules_data; - } - - return rd_best; -} - -static guint -_rules_obj_hash(gconstpointer data) -{ - const RulesObjData *obj_data = data; - NMHashState h; - - nm_hash_init(&h, 432817559u); - nm_platform_routing_rule_hash_update(NMP_OBJECT_CAST_ROUTING_RULE(obj_data->obj), - NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID, - &h); - return nm_hash_complete(&h); -} - -static gboolean -_rules_obj_equal(gconstpointer data_a, gconstpointer data_b) -{ - const RulesObjData *obj_data_a = data_a; - const RulesObjData *obj_data_b = data_b; - - return (nm_platform_routing_rule_cmp(NMP_OBJECT_CAST_ROUTING_RULE(obj_data_a->obj), - NMP_OBJECT_CAST_ROUTING_RULE(obj_data_b->obj), - NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID) - == 0); -} - -static void -_rules_obj_destroy(gpointer data) -{ - RulesObjData *obj_data = data; - - c_list_unlink_stale(&obj_data->obj_lst_head); - nmp_object_unref(obj_data->obj); - g_slice_free(RulesObjData, obj_data); -} - -static guint -_rules_user_tag_hash(gconstpointer data) -{ - const RulesUserTagData *user_tag_data = data; - - return nm_hash_val(644693447u, user_tag_data->user_tag); -} - -static gboolean -_rules_user_tag_equal(gconstpointer data_a, gconstpointer data_b) -{ - const RulesUserTagData *user_tag_data_a = data_a; - const RulesUserTagData *user_tag_data_b = data_b; - - return user_tag_data_a->user_tag == user_tag_data_b->user_tag; -} - -static void -_rules_user_tag_destroy(gpointer data) -{ - RulesUserTagData *user_tag_data = data; - - c_list_unlink_stale(&user_tag_data->user_tag_lst_head); - g_slice_free(RulesUserTagData, user_tag_data); -} - -static RulesData * -_rules_data_lookup(GHashTable *by_data, const NMPObject *obj, gconstpointer user_tag) -{ - RulesData rules_data_needle = { - .obj = obj, - .user_tag = user_tag, - }; - - return g_hash_table_lookup(by_data, &rules_data_needle); -} - -/** - * nmp_rules_manager_track: - * @self: the #NMPRulesManager instance - * @routing_rule: the #NMPlatformRoutingRule to track or untrack - * @track_priority: the priority for tracking the rule. Note that - * negative values indicate a forced absence of the rule. Priorities - * are compared with their absolute values (with higher absolute - * value being more important). For example, if you track the same - * rule twice, once with priority -5 and +10, then the rule is - * present (because the positive number is more important). - * The special value 0 indicates weakly-tracked rules. - * @user_tag: the tag associated with tracking this rule. The same tag - * must be used to untrack the rule later. - * @user_tag_untrack: if not %NULL, at the same time untrack this user-tag - * for the same rule. Note that this is different from a plain nmp_rules_manager_untrack(), - * because it enforces ownership of the now tracked rule. On the other hand, - * a plain nmp_rules_manager_untrack() merely forgets about the tracking. - * The purpose here is to set this to %NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG. - */ -void -nmp_rules_manager_track(NMPRulesManager * self, - const NMPlatformRoutingRule *routing_rule, - gint32 track_priority, - gconstpointer user_tag, - gconstpointer user_tag_untrack) -{ - NMPObject obj_stack; - const NMPObject * p_obj_stack; - RulesData * rules_data; - RulesObjData * obj_data; - RulesUserTagData *user_tag_data; - gboolean changed = FALSE; - guint32 track_priority_val; - gboolean track_priority_present; - - g_return_if_fail(NMP_IS_RULES_MANAGER(self)); - g_return_if_fail(routing_rule); - g_return_if_fail(user_tag); - nm_assert(track_priority != G_MININT32); - - _rules_init(self); - - p_obj_stack = nmp_object_stackinit(&obj_stack, NMP_OBJECT_TYPE_ROUTING_RULE, routing_rule); - - nm_assert(nmp_object_is_visible(p_obj_stack)); - - if (track_priority >= 0) { - track_priority_val = track_priority; - track_priority_present = TRUE; - } else { - track_priority_val = -track_priority; - track_priority_present = FALSE; - } - - rules_data = _rules_data_lookup(self->by_data, p_obj_stack, user_tag); - - if (!rules_data) { - rules_data = g_slice_new(RulesData); - *rules_data = (RulesData){ - .obj = nm_dedup_multi_index_obj_intern(nm_platform_get_multi_idx(self->platform), - p_obj_stack), - .user_tag = user_tag, - .track_priority_val = track_priority_val, - .track_priority_present = track_priority_present, - .dirty = FALSE, - }; - g_hash_table_add(self->by_data, rules_data); - - obj_data = g_hash_table_lookup(self->by_obj, &rules_data->obj); - if (!obj_data) { - obj_data = g_slice_new(RulesObjData); - *obj_data = (RulesObjData){ - .obj = nmp_object_ref(rules_data->obj), - .obj_lst_head = C_LIST_INIT(obj_data->obj_lst_head), - .config_state = CONFIG_STATE_NONE, - }; - g_hash_table_add(self->by_obj, obj_data); - } - c_list_link_tail(&obj_data->obj_lst_head, &rules_data->obj_lst); - - user_tag_data = g_hash_table_lookup(self->by_user_tag, &rules_data->user_tag); - if (!user_tag_data) { - user_tag_data = g_slice_new(RulesUserTagData); - *user_tag_data = (RulesUserTagData){ - .user_tag = user_tag, - .user_tag_lst_head = C_LIST_INIT(user_tag_data->user_tag_lst_head), - }; - g_hash_table_add(self->by_user_tag, user_tag_data); - } - c_list_link_tail(&user_tag_data->user_tag_lst_head, &rules_data->user_tag_lst); - changed = TRUE; - } else { - rules_data->dirty = FALSE; - if (rules_data->track_priority_val != track_priority_val - || rules_data->track_priority_present != track_priority_present) { - rules_data->track_priority_val = track_priority_val; - rules_data->track_priority_present = track_priority_present; - changed = TRUE; - } - } - - if (user_tag_untrack) { - if (user_tag != user_tag_untrack) { - RulesData *rules_data_untrack; - - rules_data_untrack = _rules_data_lookup(self->by_data, p_obj_stack, user_tag_untrack); - if (rules_data_untrack) - _rules_data_untrack(self, rules_data_untrack, FALSE, TRUE); - } else - nm_assert_not_reached(); - } - - _rules_data_assert(rules_data, TRUE); - - if (changed) { - _LOGD("routing-rule: track [" NM_HASH_OBFUSCATE_PTR_FMT ",%s%u] \"%s\")", - _USER_TAG_LOG(rules_data->user_tag), - (rules_data->track_priority_val == 0 - ? "" - : (rules_data->track_priority_present ? "+" : "-")), - (guint) rules_data->track_priority_val, - nmp_object_to_string(rules_data->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - } -} - -static void -_rules_data_untrack(NMPRulesManager *self, - RulesData * rules_data, - gboolean remove_user_tag_data, - gboolean make_owned_by_us) -{ - RulesObjData *obj_data; - - nm_assert(NMP_IS_RULES_MANAGER(self)); - _rules_data_assert(rules_data, TRUE); - nm_assert(self->by_data); - nm_assert(g_hash_table_lookup(self->by_data, rules_data) == rules_data); - - _LOGD("routing-rule: untrack [" NM_HASH_OBFUSCATE_PTR_FMT "] \"%s\"", - _USER_TAG_LOG(rules_data->user_tag), - nmp_object_to_string(rules_data->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - -#if NM_MORE_ASSERTS - { - RulesUserTagData *user_tag_data; - - user_tag_data = g_hash_table_lookup(self->by_user_tag, &rules_data->user_tag); - nm_assert(user_tag_data); - nm_assert(c_list_contains(&user_tag_data->user_tag_lst_head, &rules_data->user_tag_lst)); - } -#endif - - nm_assert(!c_list_is_empty(&rules_data->user_tag_lst)); - - obj_data = g_hash_table_lookup(self->by_obj, &rules_data->obj); - nm_assert(obj_data); - nm_assert(c_list_contains(&obj_data->obj_lst_head, &rules_data->obj_lst)); - nm_assert(obj_data == g_hash_table_lookup(self->by_obj, &rules_data->obj)); - - if (make_owned_by_us) { - if (obj_data->config_state == CONFIG_STATE_NONE) { - /* we need to mark this entry that it requires a touch on the next - * sync. */ - obj_data->config_state = CONFIG_STATE_OWNED_BY_US; - } - } else if (remove_user_tag_data && c_list_length_is(&rules_data->user_tag_lst, 1)) - g_hash_table_remove(self->by_user_tag, &rules_data->user_tag); - - /* if obj_data is marked to be "added_by_us" or "removed_by_us", we need to keep this entry - * around for the next sync -- so that we can undo what we did earlier. */ - if (obj_data->config_state == CONFIG_STATE_NONE && c_list_length_is(&rules_data->obj_lst, 1)) - g_hash_table_remove(self->by_obj, &rules_data->obj); - - g_hash_table_remove(self->by_data, rules_data); -} - -void -nmp_rules_manager_untrack(NMPRulesManager * self, - const NMPlatformRoutingRule *routing_rule, - gconstpointer user_tag) -{ - NMPObject obj_stack; - const NMPObject *p_obj_stack; - RulesData * rules_data; - - g_return_if_fail(NMP_IS_RULES_MANAGER(self)); - g_return_if_fail(routing_rule); - g_return_if_fail(user_tag); - - _rules_init(self); - - p_obj_stack = nmp_object_stackinit(&obj_stack, NMP_OBJECT_TYPE_ROUTING_RULE, routing_rule); - - nm_assert(nmp_object_is_visible(p_obj_stack)); - - rules_data = _rules_data_lookup(self->by_data, p_obj_stack, user_tag); - if (rules_data) - _rules_data_untrack(self, rules_data, TRUE, FALSE); -} - -void -nmp_rules_manager_set_dirty(NMPRulesManager *self, gconstpointer user_tag) -{ - RulesData * rules_data; - RulesUserTagData *user_tag_data; - - g_return_if_fail(NMP_IS_RULES_MANAGER(self)); - g_return_if_fail(user_tag); - - if (!self->by_data) - return; - - user_tag_data = g_hash_table_lookup(self->by_user_tag, &user_tag); - if (!user_tag_data) - return; - - c_list_for_each_entry (rules_data, &user_tag_data->user_tag_lst_head, user_tag_lst) - rules_data->dirty = TRUE; -} - -void -nmp_rules_manager_untrack_all(NMPRulesManager *self, - gconstpointer user_tag, - gboolean all /* or only dirty */) -{ - RulesData * rules_data; - RulesData * rules_data_safe; - RulesUserTagData *user_tag_data; - - g_return_if_fail(NMP_IS_RULES_MANAGER(self)); - g_return_if_fail(user_tag); - - if (!self->by_data) - return; - - user_tag_data = g_hash_table_lookup(self->by_user_tag, &user_tag); - if (!user_tag_data) - return; - - c_list_for_each_entry_safe (rules_data, - rules_data_safe, - &user_tag_data->user_tag_lst_head, - user_tag_lst) { - if (all || rules_data->dirty) - _rules_data_untrack(self, rules_data, FALSE, FALSE); - } - if (c_list_is_empty(&user_tag_data->user_tag_lst_head)) - g_hash_table_remove(self->by_user_tag, user_tag_data); -} - -void -nmp_rules_manager_sync(NMPRulesManager *self, gboolean keep_deleted_rules) -{ - const NMDedupMultiHeadEntry *pl_head_entry; - NMDedupMultiIter pl_iter; - const NMPObject * plobj; - gs_unref_ptrarray GPtrArray *rules_to_delete = NULL; - RulesObjData * obj_data; - GHashTableIter h_iter; - guint i; - const RulesData * rd_best; - - g_return_if_fail(NMP_IS_RULES_MANAGER(self)); - - if (!self->by_data) - return; - - _LOGD("sync%s", keep_deleted_rules ? " (don't remove any rules)" : ""); - - pl_head_entry = nm_platform_lookup_obj_type(self->platform, NMP_OBJECT_TYPE_ROUTING_RULE); - if (pl_head_entry) { - nmp_cache_iter_for_each (&pl_iter, pl_head_entry, &plobj) { - obj_data = g_hash_table_lookup(self->by_obj, &plobj); - - if (!obj_data) { - /* this rule is not tracked. It was externally added, hence we - * ignore it. */ - continue; - } - - rd_best = _rules_obj_get_best_data(obj_data); - if (rd_best) { - if (rd_best->track_priority_present) { - if (obj_data->config_state == CONFIG_STATE_OWNED_BY_US) - obj_data->config_state = CONFIG_STATE_ADDED_BY_US; - continue; - } - if (rd_best->track_priority_val == 0) { - if (!NM_IN_SET(obj_data->config_state, - CONFIG_STATE_ADDED_BY_US, - CONFIG_STATE_OWNED_BY_US)) { - obj_data->config_state = CONFIG_STATE_NONE; - continue; - } - obj_data->config_state = CONFIG_STATE_NONE; - } - } - - if (keep_deleted_rules) { - _LOGD("forget/leak rule added by us: %s", - nmp_object_to_string(plobj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - continue; - } - - if (!rules_to_delete) - rules_to_delete = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref); - - g_ptr_array_add(rules_to_delete, (gpointer) nmp_object_ref(plobj)); - - obj_data->config_state = CONFIG_STATE_REMOVED_BY_US; - } - } - - if (rules_to_delete) { - for (i = 0; i < rules_to_delete->len; i++) - nm_platform_object_delete(self->platform, rules_to_delete->pdata[i]); - } - - g_hash_table_iter_init(&h_iter, self->by_obj); - while (g_hash_table_iter_next(&h_iter, (gpointer *) &obj_data, NULL)) { - rd_best = _rules_obj_get_best_data(obj_data); - - if (!rd_best) { - g_hash_table_iter_remove(&h_iter); - continue; - } - - if (!rd_best->track_priority_present) { - if (obj_data->config_state == CONFIG_STATE_OWNED_BY_US) - obj_data->config_state = CONFIG_STATE_REMOVED_BY_US; - continue; - } - if (rd_best->track_priority_val == 0) { - if (!NM_IN_SET(obj_data->config_state, - CONFIG_STATE_REMOVED_BY_US, - CONFIG_STATE_OWNED_BY_US)) { - obj_data->config_state = CONFIG_STATE_NONE; - continue; - } - obj_data->config_state = CONFIG_STATE_NONE; - } - - plobj = - nm_platform_lookup_obj(self->platform, NMP_CACHE_ID_TYPE_OBJECT_TYPE, obj_data->obj); - if (plobj) - continue; - - obj_data->config_state = CONFIG_STATE_ADDED_BY_US; - nm_platform_routing_rule_add(self->platform, - NMP_NLM_FLAG_ADD, - NMP_OBJECT_CAST_ROUTING_RULE(obj_data->obj)); - } -} - -void -nmp_rules_manager_track_from_platform(NMPRulesManager *self, - NMPlatform * platform, - int addr_family, - gint32 tracking_priority, - gconstpointer user_tag) -{ - NMPLookup lookup; - const NMDedupMultiHeadEntry *head_entry; - NMDedupMultiIter iter; - const NMPObject * o; - - g_return_if_fail(NMP_IS_RULES_MANAGER(self)); - - if (!platform) - platform = self->platform; - else - g_return_if_fail(NM_IS_PLATFORM(platform)); - - nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6)); - - nmp_lookup_init_obj_type(&lookup, NMP_OBJECT_TYPE_ROUTING_RULE); - head_entry = nm_platform_lookup(platform, &lookup); - nmp_cache_iter_for_each (&iter, head_entry, &o) { - const NMPlatformRoutingRule *rr = NMP_OBJECT_CAST_ROUTING_RULE(o); - - if (addr_family != AF_UNSPEC && rr->addr_family != addr_family) - continue; - - nmp_rules_manager_track(self, rr, tracking_priority, user_tag, NULL); - } -} - -/*****************************************************************************/ - -void -nmp_rules_manager_track_default(NMPRulesManager *self, - int addr_family, - gint32 track_priority, - gconstpointer user_tag) -{ - g_return_if_fail(NMP_IS_RULES_MANAGER(self)); - - nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6)); - - /* track the default rules. See also `man ip-rule`. */ - - if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET)) { - nmp_rules_manager_track(self, - &((NMPlatformRoutingRule){ - .addr_family = AF_INET, - .priority = 0, - .table = RT_TABLE_LOCAL, - .action = FR_ACT_TO_TBL, - .protocol = RTPROT_KERNEL, - }), - track_priority, - user_tag, - NULL); - nmp_rules_manager_track(self, - &((NMPlatformRoutingRule){ - .addr_family = AF_INET, - .priority = 32766, - .table = RT_TABLE_MAIN, - .action = FR_ACT_TO_TBL, - .protocol = RTPROT_KERNEL, - }), - track_priority, - user_tag, - NULL); - nmp_rules_manager_track(self, - &((NMPlatformRoutingRule){ - .addr_family = AF_INET, - .priority = 32767, - .table = RT_TABLE_DEFAULT, - .action = FR_ACT_TO_TBL, - .protocol = RTPROT_KERNEL, - }), - track_priority, - user_tag, - NULL); - } - if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET6)) { - nmp_rules_manager_track(self, - &((NMPlatformRoutingRule){ - .addr_family = AF_INET6, - .priority = 0, - .table = RT_TABLE_LOCAL, - .action = FR_ACT_TO_TBL, - .protocol = RTPROT_KERNEL, - }), - track_priority, - user_tag, - NULL); - nmp_rules_manager_track(self, - &((NMPlatformRoutingRule){ - .addr_family = AF_INET6, - .priority = 32766, - .table = RT_TABLE_MAIN, - .action = FR_ACT_TO_TBL, - .protocol = RTPROT_KERNEL, - }), - track_priority, - user_tag, - NULL); - } -} - -static void -_rules_init(NMPRulesManager *self) -{ - if (self->by_data) - return; - - self->by_data = - g_hash_table_new_full(_rules_data_hash, _rules_data_equal, NULL, _rules_data_destroy); - self->by_obj = - g_hash_table_new_full(_rules_obj_hash, _rules_obj_equal, NULL, _rules_obj_destroy); - self->by_user_tag = g_hash_table_new_full(_rules_user_tag_hash, - _rules_user_tag_equal, - NULL, - _rules_user_tag_destroy); -} - -/*****************************************************************************/ - -NMPRulesManager * -nmp_rules_manager_new(NMPlatform *platform) -{ - NMPRulesManager *self; - - g_return_val_if_fail(NM_IS_PLATFORM(platform), NULL); - - self = g_slice_new(NMPRulesManager); - *self = (NMPRulesManager){ - .ref_count = 1, - .platform = g_object_ref(platform), - }; - return self; -} - -void -nmp_rules_manager_ref(NMPRulesManager *self) -{ - g_return_if_fail(NMP_IS_RULES_MANAGER(self)); - - self->ref_count++; -} - -void -nmp_rules_manager_unref(NMPRulesManager *self) -{ - g_return_if_fail(NMP_IS_RULES_MANAGER(self)); - - if (--self->ref_count > 0) - return; - - if (self->by_data) { - g_hash_table_destroy(self->by_user_tag); - g_hash_table_destroy(self->by_obj); - g_hash_table_destroy(self->by_data); - } - g_object_unref(self->platform); - g_slice_free(NMPRulesManager, self); -} diff --git a/src/core/platform/nmp-rules-manager.h b/src/core/platform/nmp-rules-manager.h deleted file mode 100644 index 69cf9075..00000000 --- a/src/core/platform/nmp-rules-manager.h +++ /dev/null @@ -1,53 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#ifndef __NMP_RULES_MANAGER_H__ -#define __NMP_RULES_MANAGER_H__ - -#include "nm-platform.h" - -/*****************************************************************************/ - -#define NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG ((const void *) nmp_rules_manager_new) - -typedef struct _NMPRulesManager NMPRulesManager; - -NMPRulesManager *nmp_rules_manager_new(NMPlatform *platform); - -void nmp_rules_manager_ref(NMPRulesManager *self); -void nmp_rules_manager_unref(NMPRulesManager *self); - -#define nm_auto_unref_rules_manager nm_auto(_nmp_rules_manager_unref) -NM_AUTO_DEFINE_FCN0(NMPRulesManager *, _nmp_rules_manager_unref, nmp_rules_manager_unref); - -void nmp_rules_manager_track(NMPRulesManager * self, - const NMPlatformRoutingRule *routing_rule, - gint32 track_priority, - gconstpointer user_tag, - gconstpointer user_tag_untrack); - -void nmp_rules_manager_track_default(NMPRulesManager *self, - int addr_family, - gint32 track_priority, - gconstpointer user_tag); - -void nmp_rules_manager_track_from_platform(NMPRulesManager *self, - NMPlatform * platform, - int addr_family, - gint32 tracking_priority, - gconstpointer user_tag); - -void nmp_rules_manager_untrack(NMPRulesManager * self, - const NMPlatformRoutingRule *routing_rule, - gconstpointer user_tag); - -void nmp_rules_manager_set_dirty(NMPRulesManager *self, gconstpointer user_tag); - -void nmp_rules_manager_untrack_all(NMPRulesManager *self, - gconstpointer user_tag, - gboolean all /* or only dirty */); - -void nmp_rules_manager_sync(NMPRulesManager *self, gboolean keep_deleted_rules); - -/*****************************************************************************/ - -#endif /* __NMP_RULES_MANAGER_H__ */ diff --git a/src/core/platform/tests/monitor.c b/src/core/platform/tests/monitor.c index abdf2cd5..ff6fae65 100644 --- a/src/core/platform/tests/monitor.c +++ b/src/core/platform/tests/monitor.c @@ -8,7 +8,7 @@ #include #include -#include "platform/nm-linux-platform.h" +#include "libnm-platform/nm-linux-platform.h" #include "nm-test-utils-core.h" diff --git a/src/core/platform/tests/test-address.c b/src/core/platform/tests/test-address.c index d4d67105..4e1d1d6e 100644 --- a/src/core/platform/tests/test-address.c +++ b/src/core/platform/tests/test-address.c @@ -235,7 +235,7 @@ test_ip4_address_general_2(void) /* Looks like addresses are not announced by kernel when the interface * is down. Link-local IPv6 address is automatically added. */ - g_assert(nm_platform_link_set_up(NM_PLATFORM_GET, DEVICE_IFINDEX, NULL)); + g_assert(nm_platform_link_change_flags(NM_PLATFORM_GET, DEVICE_IFINDEX, IFF_UP, TRUE) >= 0); /* Add/delete notification */ nmtstp_ip4_address_add(NULL, EX, ifindex, addr, IP4_PLEN, addr, lifetime, preferred, 0, NULL); @@ -325,7 +325,7 @@ test_ip4_address_peer(void) g_assert(addr != addr_peer); - g_assert(nm_platform_link_set_up(NM_PLATFORM_GET, ifindex, NULL)); + g_assert(nm_platform_link_change_flags(NM_PLATFORM_GET, ifindex, IFF_UP, TRUE) >= 0); accept_signals(address_removed, 0, G_MAXINT); accept_signals(address_added, 0, G_MAXINT); @@ -397,7 +397,7 @@ test_ip4_address_peer_zero(void) peers[1] = addr_peer; peers[2] = 0; - g_assert(nm_platform_link_set_up(NM_PLATFORM_GET, ifindex, NULL)); + g_assert(nm_platform_link_change_flags(NM_PLATFORM_GET, ifindex, IFF_UP, TRUE) >= 0); nmtst_rand_perm(NULL, r_peers, peers, sizeof(peers[0]), G_N_ELEMENTS(peers)); for (i = 0; i < G_N_ELEMENTS(peers); i++) { diff --git a/src/core/platform/tests/test-cleanup.c b/src/core/platform/tests/test-cleanup.c index b54eca34..e13bb8c8 100644 --- a/src/core/platform/tests/test-cleanup.c +++ b/src/core/platform/tests/test-cleanup.c @@ -44,9 +44,12 @@ test_cleanup_internal(void) g_assert(NMTST_NM_ERR_SUCCESS(nm_platform_link_dummy_add(NM_PLATFORM_GET, DEVICE_NAME, NULL))); 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)); + g_assert( + nm_platform_link_change_flags(NM_PLATFORM_GET, + nm_platform_link_get_ifindex(NM_PLATFORM_GET, DEVICE_NAME), + IFF_UP, + TRUE) + >= 0); ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, DEVICE_NAME); g_assert(ifindex > 0); diff --git a/src/core/platform/tests/test-common.c b/src/core/platform/tests/test-common.c index 4a117d59..f9a141bc 100644 --- a/src/core/platform/tests/test-common.c +++ b/src/core/platform/tests/test-common.c @@ -1413,6 +1413,44 @@ nmtstp_ip6_address_del(NMPlatform * platform, } \ G_STMT_END +/* Due to rounding errors with clock_t_to_jiffies()/jiffies_to_clock_t(), kernel cannot + * store all requested values. That means, when we try to configure a bridge with + * the @requested values, the actually configured settings are slightly off, as + * @kernel. + * + * This function takes @requested and returns it as @dst output. All fields + * that might be mangled by kernel (according to @kernel) are adjusted. The + * result is almost identical to @requested, but some fields might be adjusted + * to their @kernel value. */ +const NMPlatformLnkBridge * +nmtstp_link_bridge_normalize_jiffies_time(const NMPlatformLnkBridge *requested, + const NMPlatformLnkBridge *kernel, + NMPlatformLnkBridge * dst) +{ + if (dst != requested) + *dst = *requested; + +#define _normalize_field(dst, kernel, field) \ + G_STMT_START \ + { \ + (dst)->field = nmtstp_normalize_jiffies_time((dst)->field, (kernel)->field); \ + } \ + G_STMT_END + + _normalize_field(dst, kernel, forward_delay); + _normalize_field(dst, kernel, hello_time); + _normalize_field(dst, kernel, max_age); + _normalize_field(dst, kernel, ageing_time); + _normalize_field(dst, kernel, mcast_last_member_interval); + _normalize_field(dst, kernel, mcast_membership_interval); + _normalize_field(dst, kernel, mcast_querier_interval); + _normalize_field(dst, kernel, mcast_query_interval); + _normalize_field(dst, kernel, mcast_query_response_interval); + _normalize_field(dst, kernel, mcast_startup_query_interval); + + return dst; +} + const NMPlatformLink * nmtstp_link_bridge_add(NMPlatform * platform, gboolean external_command, @@ -1421,7 +1459,8 @@ nmtstp_link_bridge_add(NMPlatform * platform, { const NMPlatformLink * pllink = NULL; const NMPlatformLnkBridge *ll = NULL; - int r = 0; + NMPlatformLnkBridge lnk_normalized; + int r = 0; g_assert(nm_utils_ifname_valid_kernel(name, NULL)); @@ -1542,6 +1581,8 @@ nmtstp_link_bridge_add(NMPlatform * platform, ll = NMP_OBJECT_CAST_LNK_BRIDGE(NMP_OBJECT_UP_CAST(pllink)->_link.netlink.lnk); + lnk = nmtstp_link_bridge_normalize_jiffies_time(lnk, ll, &lnk_normalized); + g_assert_cmpint(lnk->forward_delay, ==, ll->forward_delay); g_assert_cmpint(lnk->hello_time, ==, ll->hello_time); g_assert_cmpint(lnk->max_age, ==, ll->max_age); @@ -2243,9 +2284,9 @@ nmtstp_link_set_updown(NMPlatform *platform, gboolean external_command, int ifin nmtstp_run_command_check("ip link set %s %s", ifname, up ? "up" : "down"); } else { if (up) - g_assert(nm_platform_link_set_up(platform, ifindex, NULL)); + g_assert(nm_platform_link_change_flags(platform, ifindex, IFF_UP, TRUE) >= 0); else - g_assert(nm_platform_link_set_down(platform, ifindex)); + g_assert(nm_platform_link_change_flags(platform, ifindex, IFF_UP, FALSE) >= 0); } /* Let's wait until we get the result */ diff --git a/src/core/platform/tests/test-common.h b/src/core/platform/tests/test-common.h index 618645fe..1fb97d24 100644 --- a/src/core/platform/tests/test-common.h +++ b/src/core/platform/tests/test-common.h @@ -11,10 +11,10 @@ #include #include -#include "platform/nm-platform.h" -#include "platform/nmp-object.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-platform/nmp-object.h" #include "platform/nm-fake-platform.h" -#include "platform/nm-linux-platform.h" +#include "libnm-platform/nm-linux-platform.h" #include "nm-test-utils-core.h" @@ -22,6 +22,24 @@ /*****************************************************************************/ +#define nmtstp_normalize_jiffies_time(requested_value, kernel_value) \ + ({ \ + typeof(kernel_value) _kernel_value = (kernel_value); \ + typeof(_kernel_value) _requested_value = (requested_value); \ + \ + /* kernel stores some values (like bridge's forward_delay) in jiffies. When converting + * back and forth (clock_t_to_jiffies()/jiffies_to_clock_t()), the value reported back + * to user space may have rounding errors (of +/- 1), depending on CONFIG_HZ setting. + * + * Normalize the requested_value to the kernel_value, if it look as if a rounding + * error happens. If the difference is larger than +/- 1, no normalization happens! */ \ + \ + ((_requested_value >= (NM_MAX(_kernel_value, 1) - 1)) \ + && (_requested_value <= (NM_MIN(_kernel_value, ~((typeof(_kernel_value)) 0) - 1) + 1))) \ + ? _kernel_value \ + : _requested_value; \ + }) + #define _NMLOG_PREFIX_NAME "platform-test" #define _NMLOG_DOMAIN LOGD_PLATFORM #define _NMLOG(level, ...) _LOG(level, _NMLOG_DOMAIN, __VA_ARGS__) @@ -437,6 +455,11 @@ gboolean nmtstp_kernel_support_get(NMPlatformKernelSupportType type); void nmtstp_link_set_updown(NMPlatform *platform, gboolean external_command, int ifindex, gboolean up); +const NMPlatformLnkBridge * +nmtstp_link_bridge_normalize_jiffies_time(const NMPlatformLnkBridge *requested, + const NMPlatformLnkBridge *kernel, + NMPlatformLnkBridge * dst); + const NMPlatformLink *nmtstp_link_bridge_add(NMPlatform * platform, gboolean external_command, const char * name, @@ -519,7 +542,7 @@ _nmtstp_env1_wrapper_setup(const NmtstTestData *test_data) g_assert_cmpint(NMTSTP_ENV1_IFINDEX, ==, -1); if (GPOINTER_TO_INT(p_ifup)) - g_assert(nm_platform_link_set_up(NM_PLATFORM_GET, *p_ifindex, NULL)); + g_assert(nm_platform_link_change_flags(NM_PLATFORM_GET, *p_ifindex, IFF_UP, TRUE) >= 0); nm_platform_process_events(NM_PLATFORM_GET); diff --git a/src/core/platform/tests/test-link.c b/src/core/platform/tests/test-link.c index 3aaa3759..f6c3841e 100644 --- a/src/core/platform/tests/test-link.c +++ b/src/core/platform/tests/test-link.c @@ -11,11 +11,11 @@ #include #include -#include "nm-glib-aux/nm-io-utils.h" -#include "nm-base/nm-ethtool-base.h" -#include "platform/nmp-object.h" -#include "nm-platform/nmp-netns.h" -#include "nm-platform/nm-platform-utils.h" +#include "libnm-glib-aux/nm-io-utils.h" +#include "libnm-base/nm-ethtool-base.h" +#include "libnm-platform/nmp-object.h" +#include "libnm-platform/nmp-netns.h" +#include "libnm-platform/nm-platform-utils.h" #include "test-common.h" #include "nm-test-utils-core.h" @@ -48,13 +48,15 @@ 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_assert(!nm_platform_link_set_up(NM_PLATFORM_GET, BOGUS_IFINDEX, NULL)); + g_assert(!(nm_platform_link_change_flags(NM_PLATFORM_GET, BOGUS_IFINDEX, IFF_UP, TRUE) >= 0)); - g_assert(!nm_platform_link_set_down(NM_PLATFORM_GET, BOGUS_IFINDEX)); + g_assert(!(nm_platform_link_change_flags(NM_PLATFORM_GET, BOGUS_IFINDEX, IFF_UP, FALSE) >= 0)); - g_assert(!nm_platform_link_set_arp(NM_PLATFORM_GET, BOGUS_IFINDEX)); + g_assert( + !(nm_platform_link_change_flags(NM_PLATFORM_GET, BOGUS_IFINDEX, IFF_NOARP, TRUE) >= 0)); - g_assert(!nm_platform_link_set_noarp(NM_PLATFORM_GET, BOGUS_IFINDEX)); + g_assert( + !(nm_platform_link_change_flags(NM_PLATFORM_GET, BOGUS_IFINDEX, IFF_NOARP, FALSE) >= 0)); g_assert(!nm_platform_link_is_up(NM_PLATFORM_GET, BOGUS_IFINDEX)); g_assert(!nm_platform_link_is_connected(NM_PLATFORM_GET, BOGUS_IFINDEX)); @@ -147,7 +149,8 @@ software_add(NMLinkType link_type, const char *name) NM_PLATFORM_SIGNAL_CHANGED, link_callback, parent_ifindex); - g_assert(nm_platform_link_set_up(NM_PLATFORM_GET, parent_ifindex, NULL)); + g_assert(nm_platform_link_change_flags(NM_PLATFORM_GET, parent_ifindex, IFF_UP, TRUE) + >= 0); if (was_up) { /* when NM is running in the background, it will mess with addrgenmode which might cause additional signals. */ accept_signals(parent_changed, 0, 1); @@ -233,7 +236,7 @@ test_slave(int master, int type, SignalData *master_changed) * See https://bugzilla.redhat.com/show_bug.cgi?id=910348 */ g_assert(!nm_platform_link_is_up(NM_PLATFORM_GET, ifindex)); - g_assert(nm_platform_link_set_down(NM_PLATFORM_GET, ifindex)); + g_assert(nm_platform_link_change_flags(NM_PLATFORM_GET, ifindex, IFF_UP, FALSE) >= 0); g_assert(!nm_platform_link_is_up(NM_PLATFORM_GET, ifindex)); ensure_no_signal(link_changed); @@ -263,7 +266,7 @@ test_slave(int master, int type, SignalData *master_changed) &test_link_changed_signal_arg2); /* Set master up */ - g_assert(nm_platform_link_set_up(NM_PLATFORM_GET, master, NULL)); + g_assert(nm_platform_link_change_flags(NM_PLATFORM_GET, master, IFF_UP, TRUE) >= 0); g_assert(nm_platform_link_is_up(NM_PLATFORM_GET, master)); accept_signals(master_changed, 1, 3); @@ -284,7 +287,7 @@ test_slave(int master, int type, SignalData *master_changed) switch (nm_platform_link_get_type(NM_PLATFORM_GET, master)) { case NM_LINK_TYPE_BOND: case NM_LINK_TYPE_TEAM: - g_assert(nm_platform_link_set_down(NM_PLATFORM_GET, ifindex)); + g_assert(nm_platform_link_change_flags(NM_PLATFORM_GET, ifindex, IFF_UP, FALSE) >= 0); accept_signal(link_changed); accept_signals(master_changed, 0, 3); break; @@ -317,7 +320,7 @@ test_slave(int master, int type, SignalData *master_changed) } /* Set slave up and see if master gets up too */ - g_assert(nm_platform_link_set_up(NM_PLATFORM_GET, ifindex, NULL)); + g_assert(nm_platform_link_change_flags(NM_PLATFORM_GET, ifindex, IFF_UP, TRUE) >= 0); g_assert(nm_platform_link_is_connected(NM_PLATFORM_GET, ifindex)); g_assert(nm_platform_link_is_connected(NM_PLATFORM_GET, master)); accept_signals(link_changed, 1, 3); @@ -439,10 +442,10 @@ test_software(NMLinkType link_type, const char *link_typename) /* Set ARP/NOARP */ g_assert(nm_platform_link_uses_arp(NM_PLATFORM_GET, ifindex)); - g_assert(nm_platform_link_set_noarp(NM_PLATFORM_GET, ifindex)); + g_assert(nm_platform_link_change_flags(NM_PLATFORM_GET, ifindex, IFF_NOARP, TRUE) >= 0); g_assert(!nm_platform_link_uses_arp(NM_PLATFORM_GET, ifindex)); accept_signals(link_changed, 1, 2); - g_assert(nm_platform_link_set_arp(NM_PLATFORM_GET, ifindex)); + g_assert(nm_platform_link_change_flags(NM_PLATFORM_GET, ifindex, IFF_NOARP, FALSE) >= 0); g_assert(nm_platform_link_uses_arp(NM_PLATFORM_GET, ifindex)); accept_signal(link_changed); @@ -672,21 +675,21 @@ test_internal(void) /* Up/connected */ g_assert(!nm_platform_link_is_up(NM_PLATFORM_GET, ifindex)); g_assert(!nm_platform_link_is_connected(NM_PLATFORM_GET, ifindex)); - g_assert(nm_platform_link_set_up(NM_PLATFORM_GET, ifindex, NULL)); + g_assert(nm_platform_link_change_flags(NM_PLATFORM_GET, ifindex, IFF_UP, TRUE) >= 0); g_assert(nm_platform_link_is_up(NM_PLATFORM_GET, ifindex)); g_assert(nm_platform_link_is_connected(NM_PLATFORM_GET, ifindex)); accept_signals(link_changed, 1, 2); - g_assert(nm_platform_link_set_down(NM_PLATFORM_GET, ifindex)); + g_assert(nm_platform_link_change_flags(NM_PLATFORM_GET, ifindex, IFF_UP, FALSE) >= 0); g_assert(!nm_platform_link_is_up(NM_PLATFORM_GET, ifindex)); g_assert(!nm_platform_link_is_connected(NM_PLATFORM_GET, ifindex)); accept_signal(link_changed); /* arp/noarp */ g_assert(!nm_platform_link_uses_arp(NM_PLATFORM_GET, ifindex)); - g_assert(nm_platform_link_set_arp(NM_PLATFORM_GET, ifindex)); + g_assert(nm_platform_link_change_flags(NM_PLATFORM_GET, ifindex, IFF_NOARP, FALSE) >= 0); g_assert(nm_platform_link_uses_arp(NM_PLATFORM_GET, ifindex)); accept_signal(link_changed); - g_assert(nm_platform_link_set_noarp(NM_PLATFORM_GET, ifindex)); + g_assert(nm_platform_link_change_flags(NM_PLATFORM_GET, ifindex, IFF_NOARP, TRUE) >= 0); g_assert(!nm_platform_link_uses_arp(NM_PLATFORM_GET, ifindex)); accept_signal(link_changed); @@ -1303,7 +1306,7 @@ test_software_detect(gconstpointer user_data) 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; + gracefully_skip = nmp_utils_modprobe(NULL, TRUE, "ip_gre", NULL) != 0; } if (!nmtstp_link_gre_add(NULL, ext, DEVICE_NAME, &lnk_gre)) { @@ -1330,7 +1333,7 @@ test_software_detect(gconstpointer user_data) if (!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "gretap0")) { /* Seems that the ip_gre module is not loaded... try to load it. */ - gracefully_skip = nm_utils_modprobe(NULL, TRUE, "ip_gre", NULL) != 0; + gracefully_skip = nmp_utils_modprobe(NULL, TRUE, "ip_gre", NULL) != 0; } if (!nmtstp_link_gre_add(NULL, ext, DEVICE_NAME, &lnk_gre)) { @@ -1350,7 +1353,7 @@ test_software_detect(gconstpointer user_data) 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; + gracefully_skip = nmp_utils_modprobe(NULL, TRUE, "ipip", NULL) != 0; } lnk_ipip.local = nmtst_inet4_from_string("1.2.3.4"); @@ -1376,7 +1379,7 @@ test_software_detect(gconstpointer user_data) 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; + gracefully_skip = nmp_utils_modprobe(NULL, TRUE, "ip6_tunnel", NULL) != 0; } switch (test_data->test_mode) { @@ -1418,7 +1421,7 @@ test_software_detect(gconstpointer user_data) if (!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "ip6gre0")) { /* Seems that the ip6_tunnel module is not loaded... try to load it. */ - gracefully_skip = nm_utils_modprobe(NULL, TRUE, "ip6_gre", NULL) != 0; + gracefully_skip = nmp_utils_modprobe(NULL, TRUE, "ip6_gre", NULL) != 0; } lnk_ip6tnl.local = *nmtst_inet6_from_string("fd01::42"); @@ -1445,7 +1448,7 @@ test_software_detect(gconstpointer user_data) if (!nm_platform_link_get_by_ifname(NM_PLATFORM_GET, "ip6gre0")) { /* Seems that the ip6_tunnel module is not loaded... try to load it. */ - gracefully_skip = nm_utils_modprobe(NULL, TRUE, "ip6_gre", NULL) != 0; + gracefully_skip = nmp_utils_modprobe(NULL, TRUE, "ip6_gre", NULL) != 0; } lnk_ip6tnl.local = *nmtst_inet6_from_string("fe80::abcd"); @@ -1526,7 +1529,7 @@ test_software_detect(gconstpointer user_data) 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; + gracefully_skip = nmp_utils_modprobe(NULL, TRUE, "sit", NULL) != 0; } if (!nmtstp_link_sit_add(NULL, ext, DEVICE_NAME, &lnk_sit)) { @@ -1679,17 +1682,25 @@ test_software_detect(gconstpointer user_data) case NM_LINK_TYPE_BRIDGE: { const NMPlatformLnkBridge *plnk = &lnk->lnk_bridge; + NMPlatformLnkBridge lnk_bridge_norm_stack; + const NMPlatformLnkBridge *lnk_bridge_norm; g_assert(plnk == nm_platform_link_get_lnk_bridge(NM_PLATFORM_GET, ifindex, NULL)); - g_assert_cmpint(nm_platform_lnk_bridge_cmp(&lnk_bridge, plnk), ==, 0); - g_assert_cmpint(plnk->forward_delay, ==, 1560); - g_assert_cmpint(plnk->hello_time, ==, 150); - g_assert_cmpint(plnk->max_age, ==, 2100); - g_assert_cmpint(plnk->ageing_time, ==, 2200); + + lnk_bridge_norm = nmtstp_link_bridge_normalize_jiffies_time(&lnk_bridge, + plnk, + &lnk_bridge_norm_stack); + + g_assert_cmpint(nm_platform_lnk_bridge_cmp(lnk_bridge_norm, plnk), ==, 0); + + g_assert_cmpint(plnk->forward_delay, ==, lnk_bridge_norm->forward_delay); + g_assert_cmpint(plnk->hello_time, ==, lnk_bridge_norm->hello_time); + g_assert_cmpint(plnk->max_age, ==, lnk_bridge_norm->max_age); + g_assert_cmpint(plnk->ageing_time, ==, lnk_bridge_norm->ageing_time); g_assert_cmpint(plnk->stp_state, ==, TRUE); g_assert_cmpint(plnk->priority, ==, 22); g_assert_cmpint(plnk->vlan_protocol, ==, 0x8100); - g_assert_cmpint(plnk->vlan_stats_enabled, ==, lnk_bridge.vlan_stats_enabled); + g_assert_cmpint(plnk->vlan_stats_enabled, ==, lnk_bridge_norm->vlan_stats_enabled); g_assert_cmpint(plnk->group_fwd_mask, ==, 8); g_assert_cmpint(plnk->mcast_snooping, ==, TRUE); g_assert_cmpint(plnk->mcast_router, ==, 1); @@ -1698,13 +1709,22 @@ test_software_detect(gconstpointer user_data) g_assert_cmpint(plnk->mcast_hash_max, ==, 1024); g_assert_cmpint(plnk->mcast_last_member_count, ==, 2); g_assert_cmpint(plnk->mcast_startup_query_count, ==, 3); - g_assert_cmpint(plnk->mcast_last_member_interval, ==, 5000); - g_assert_cmpint(plnk->mcast_membership_interval, ==, 25000); - g_assert_cmpint(plnk->mcast_querier_interval, ==, 26000); - g_assert_cmpint(plnk->mcast_query_interval, ==, 12000); - g_assert_cmpint(plnk->mcast_query_response_interval, ==, 5200); - g_assert_cmpint(plnk->mcast_startup_query_interval, ==, 3000); - g_assert_cmpint(nm_platform_lnk_bridge_cmp(&lnk_bridge, plnk), ==, 0); + g_assert_cmpint(plnk->mcast_last_member_interval, + ==, + lnk_bridge_norm->mcast_last_member_interval); + g_assert_cmpint(plnk->mcast_membership_interval, + ==, + lnk_bridge_norm->mcast_membership_interval); + g_assert_cmpint(plnk->mcast_querier_interval, + ==, + lnk_bridge_norm->mcast_querier_interval); + g_assert_cmpint(plnk->mcast_query_interval, ==, lnk_bridge_norm->mcast_query_interval); + g_assert_cmpint(plnk->mcast_query_response_interval, + ==, + lnk_bridge_norm->mcast_query_response_interval); + g_assert_cmpint(plnk->mcast_startup_query_interval, + ==, + lnk_bridge_norm->mcast_startup_query_interval); break; } case NM_LINK_TYPE_GRE: @@ -2049,7 +2069,7 @@ _assert_xgress_qos_mappings_impl(int ifindex, gboolean is_ingress_map, int n_ent _assert_xgress_qos_mappings(ifindex, FALSE, n_entries, __VA_ARGS__) static void -_assert_vlan_flags(int ifindex, NMVlanFlags flags) +_assert_vlan_flags(int ifindex, _NMVlanFlags flags) { const NMPlatformLnkVlan *plnk; @@ -2362,8 +2382,8 @@ test_vlan_set_xgress(void) 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, + _NM_VLAN_FLAG_REORDER_HEADERS | _NM_VLAN_FLAG_GVRP, + _NM_VLAN_FLAG_REORDER_HEADERS, TRUE, ingress_map, G_N_ELEMENTS(ingress_map), @@ -2372,7 +2392,7 @@ test_vlan_set_xgress(void) 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); + _assert_vlan_flags(ifindex, _NM_VLAN_FLAG_REORDER_HEADERS); } { @@ -2393,8 +2413,8 @@ test_vlan_set_xgress(void) g_assert(nm_platform_link_vlan_change(NM_PLATFORM_GET, ifindex, - NM_VLAN_FLAG_GVRP, - NM_VLAN_FLAG_GVRP, + _NM_VLAN_FLAG_GVRP, + _NM_VLAN_FLAG_GVRP, FALSE, ingress_map, G_N_ELEMENTS(ingress_map), @@ -2403,7 +2423,7 @@ test_vlan_set_xgress(void) 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); + _assert_vlan_flags(ifindex, _NM_VLAN_FLAG_REORDER_HEADERS | _NM_VLAN_FLAG_GVRP); } nmtstp_link_delete(NULL, -1, ifindex, DEVICE_NAME, TRUE); diff --git a/src/core/platform/tests/test-nmp-object.c b/src/core/platform/tests/test-nmp-object.c index 310611ee..6d2236ec 100644 --- a/src/core/platform/tests/test-nmp-object.c +++ b/src/core/platform/tests/test-nmp-object.c @@ -8,8 +8,8 @@ #include #include -#include "platform/nmp-object.h" -#include "nm-udev-aux/nm-udev-utils.h" +#include "libnm-platform/nmp-object.h" +#include "libnm-udev-aux/nm-udev-utils.h" #include "nm-test-utils-core.h" diff --git a/src/core/platform/tests/test-platform-general.c b/src/core/platform/tests/test-platform-general.c index b426cc65..05158228 100644 --- a/src/core/platform/tests/test-platform-general.c +++ b/src/core/platform/tests/test-platform-general.c @@ -7,8 +7,8 @@ #include -#include "nm-platform/nm-platform-utils.h" -#include "platform/nm-linux-platform.h" +#include "libnm-platform/nm-platform-utils.h" +#include "libnm-platform/nm-linux-platform.h" #include "nm-test-utils-core.h" @@ -584,7 +584,7 @@ test_platform_ip_address_pretty_sort_cmp(gconstpointer test_data) nmtst_stable_rand(710086081, rand_map, sizeof(rand_map[0]) * N_ADDRESSES); for (i = 0; i < N_ADDRESSES; i++) { - NMPlatformIPXAddress *a = (gpointer)(&addresses[i * ELM_SIZE]); + NMPlatformIPXAddress *a = (gpointer) (&addresses[i * ELM_SIZE]); guint64 r = rand_map[i]; struct in6_addr * a6; @@ -684,10 +684,10 @@ test_platform_ip_address_pretty_sort_cmp(gconstpointer test_data) (gpointer) test_data); for (i = 0; i < N_ADDRESSES; i++) { - const NMPlatformIPXAddress *a = (gconstpointer)(&addresses[i * ELM_SIZE]); + const NMPlatformIPXAddress *a = (gconstpointer) (&addresses[i * ELM_SIZE]); for (j = i + 1; j < N_ADDRESSES; j++) { - const NMPlatformIPXAddress *b = (gconstpointer)(&addresses[j * ELM_SIZE]); + const NMPlatformIPXAddress *b = (gconstpointer) (&addresses[j * ELM_SIZE]); int c1; int c2; diff --git a/src/core/platform/tests/test-route.c b/src/core/platform/tests/test-route.c index 645bb5b1..2b9b2f8f 100644 --- a/src/core/platform/tests/test-route.c +++ b/src/core/platform/tests/test-route.c @@ -9,8 +9,8 @@ #include #include "nm-core-utils.h" -#include "nm-platform/nm-platform-utils.h" -#include "platform/nmp-rules-manager.h" +#include "libnm-platform/nm-platform-utils.h" +#include "libnm-platform/nmp-rules-manager.h" #include "test-common.h" diff --git a/src/core/platform/tests/test-tc.c b/src/core/platform/tests/test-tc.c index d15c3d76..cd9536cc 100644 --- a/src/core/platform/tests/test-tc.c +++ b/src/core/platform/tests/test-tc.c @@ -5,9 +5,9 @@ #include #include "nm-test-utils-core.h" -#include "platform/nmp-object.h" -#include "nm-platform/nmp-netns.h" -#include "nm-platform/nm-platform-utils.h" +#include "libnm-platform/nmp-object.h" +#include "libnm-platform/nmp-netns.h" +#include "libnm-platform/nm-platform-utils.h" #include "test-common.h" static NMPObject * diff --git a/src/core/platform/wifi/nm-wifi-utils-nl80211.c b/src/core/platform/wifi/nm-wifi-utils-nl80211.c deleted file mode 100644 index ad067248..00000000 --- a/src/core/platform/wifi/nm-wifi-utils-nl80211.c +++ /dev/null @@ -1,909 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2005 - 2018 Red Hat, Inc. - * Copyright (C) 2006 - 2008 Novell, Inc. - * Copyright (C) 2011 Intel Corporation. All rights reserved. - */ - -#include "src/core/nm-default-daemon.h" - -#include "nm-wifi-utils-nl80211.h" - -#include -#include -#include -#include -#include - -#include "nm-platform/nm-netlink.h" -#include "nm-wifi-utils-private.h" -#include "platform/nm-platform.h" -#include "nm-platform/nm-platform-utils.h" -#include "nm-utils.h" - -#define _NMLOG_PREFIX_NAME "wifi-nl80211" -#define _NMLOG_DOMAIN LOGD_PLATFORM | LOGD_WIFI -#define _NMLOG(level, ...) \ - G_STMT_START \ - { \ - char _ifname_buf[IFNAMSIZ]; \ - const char *_ifname = \ - self ? nmp_utils_if_indextoname(self->parent.ifindex, _ifname_buf) : NULL; \ - \ - nm_log((level), \ - _NMLOG_DOMAIN, \ - _ifname ?: NULL, \ - NULL, \ - "%s%s%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - _NMLOG_PREFIX_NAME, \ - NM_PRINT_FMT_QUOTED(_ifname, " (", _ifname, ")", "") \ - _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - G_STMT_END - -typedef struct { - NMWifiUtils parent; - struct nl_sock *nl_sock; - guint32 * freqs; - int id; - int num_freqs; - int phy; - bool can_wowlan : 1; -} NMWifiUtilsNl80211; - -typedef struct { - NMWifiUtilsClass parent; -} NMWifiUtilsNl80211Class; - -G_DEFINE_TYPE(NMWifiUtilsNl80211, nm_wifi_utils_nl80211, NM_TYPE_WIFI_UTILS) - -static int -ack_handler(struct nl_msg *msg, void *arg) -{ - int *done = arg; - *done = 1; - return NL_STOP; -} - -static int -finish_handler(struct nl_msg *msg, void *arg) -{ - int *done = arg; - *done = 1; - return NL_SKIP; -} - -static int -error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) -{ - int *done = arg; - *done = err->error; - return NL_SKIP; -} - -static struct nl_msg * -_nl80211_alloc_msg(int id, int ifindex, int phy, guint32 cmd, guint32 flags) -{ - nm_auto_nlmsg struct nl_msg *msg = NULL; - - msg = nlmsg_alloc(); - genlmsg_put(msg, 0, 0, id, 0, flags, cmd, 0); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex); - if (phy != -1) - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, phy); - return g_steal_pointer(&msg); - -nla_put_failure: - g_return_val_if_reached(NULL); -} - -static struct nl_msg * -nl80211_alloc_msg(NMWifiUtilsNl80211 *self, guint32 cmd, guint32 flags) -{ - return _nl80211_alloc_msg(self->id, self->parent.ifindex, self->phy, cmd, flags); -} - -static int -nl80211_send_and_recv(NMWifiUtilsNl80211 *self, - struct nl_msg * msg, - int (*valid_handler)(struct nl_msg *, void *), - void *valid_data) -{ - int err; - int done = 0; - const struct nl_cb cb = { - .err_cb = error_handler, - .err_arg = &done, - .finish_cb = finish_handler, - .finish_arg = &done, - .ack_cb = ack_handler, - .ack_arg = &done, - .valid_cb = valid_handler, - .valid_arg = valid_data, - }; - - g_return_val_if_fail(msg != NULL, -ENOMEM); - - err = nl_send_auto(self->nl_sock, msg); - if (err < 0) - return err; - - /* Loop until one of our NL callbacks says we're done; on success - * done will be 1, on error it will be < 0. - */ - while (!done) { - err = nl_recvmsgs(self->nl_sock, &cb); - if (err < 0 && err != -EAGAIN) { - /* Kernel scan list can change while we are dumping it, as new scan - * results from H/W can arrive. BSS info is assured to be consistent - * and we don't need consistent view of whole scan list. Hence do - * not warn on DUMP_INTR error for get scan command. - */ - if (err == -NME_NL_DUMP_INTR - && genlmsg_hdr(nlmsg_hdr(msg))->cmd == NL80211_CMD_GET_SCAN) - break; - - _LOGW("nl_recvmsgs() error: (%d) %s", err, nm_strerror(err)); - break; - } - } - - if (err >= 0 && done < 0) - err = done; - return err; -} - -static void -dispose(GObject *object) -{ - NMWifiUtilsNl80211 *self = NM_WIFI_UTILS_NL80211(object); - - nm_clear_g_free(&self->freqs); -} - -struct nl80211_iface_info { - NM80211Mode mode; - uint32_t freq; -}; - -static int -nl80211_iface_info_handler(struct nl_msg *msg, void *arg) -{ - struct nl80211_iface_info *info = arg; - struct genlmsghdr * gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct nlattr * tb[NL80211_ATTR_MAX + 1]; - - if (nla_parse_arr(tb, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL) < 0) - return NL_SKIP; - - if (!tb[NL80211_ATTR_IFTYPE]) - return NL_SKIP; - - switch (nla_get_u32(tb[NL80211_ATTR_IFTYPE])) { - case NL80211_IFTYPE_ADHOC: - info->mode = NM_802_11_MODE_ADHOC; - break; - case NL80211_IFTYPE_AP: - info->mode = NM_802_11_MODE_AP; - break; - case NL80211_IFTYPE_STATION: - info->mode = NM_802_11_MODE_INFRA; - break; - case NL80211_IFTYPE_MESH_POINT: - info->mode = NM_802_11_MODE_MESH; - break; - } - - if (tb[NL80211_ATTR_WIPHY_FREQ] != NULL) - info->freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); - - return NL_SKIP; -} - -static NM80211Mode -wifi_nl80211_get_mode(NMWifiUtils *data) -{ - NMWifiUtilsNl80211 * self = (NMWifiUtilsNl80211 *) data; - struct nl80211_iface_info iface_info = { - .mode = NM_802_11_MODE_UNKNOWN, - }; - nm_auto_nlmsg struct nl_msg *msg = NULL; - - msg = nl80211_alloc_msg(self, NL80211_CMD_GET_INTERFACE, 0); - - if (nl80211_send_and_recv(self, msg, nl80211_iface_info_handler, &iface_info) < 0) - return NM_802_11_MODE_UNKNOWN; - - return iface_info.mode; -} - -static gboolean -wifi_nl80211_set_mode(NMWifiUtils *data, const NM80211Mode mode) -{ - NMWifiUtilsNl80211 * self = (NMWifiUtilsNl80211 *) data; - nm_auto_nlmsg struct nl_msg *msg = NULL; - int err; - - msg = nl80211_alloc_msg(self, NL80211_CMD_SET_INTERFACE, 0); - - switch (mode) { - case NM_802_11_MODE_INFRA: - NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_STATION); - break; - case NM_802_11_MODE_ADHOC: - NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_ADHOC); - break; - case NM_802_11_MODE_AP: - NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_AP); - break; - case NM_802_11_MODE_MESH: - NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MESH_POINT); - break; - default: - g_assert_not_reached(); - } - - err = nl80211_send_and_recv(self, msg, NULL, NULL); - return err >= 0; - -nla_put_failure: - g_return_val_if_reached(FALSE); -} - -static gboolean -wifi_nl80211_set_powersave(NMWifiUtils *data, guint32 powersave) -{ - NMWifiUtilsNl80211 * self = (NMWifiUtilsNl80211 *) data; - nm_auto_nlmsg struct nl_msg *msg = NULL; - int err; - - msg = nl80211_alloc_msg(self, 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(self, msg, NULL, NULL); - return err >= 0; - -nla_put_failure: - g_return_val_if_reached(FALSE); -} - -static int -nl80211_get_wake_on_wlan_handler(struct nl_msg *msg, void *arg) -{ - NMSettingWirelessWakeOnWLan *wowl = arg; - struct nlattr * attrs[NL80211_ATTR_MAX + 1]; - struct nlattr * trig[NUM_NL80211_WOWLAN_TRIG]; - struct genlmsghdr * gnlh = nlmsg_data(nlmsg_hdr(msg)); - - nla_parse_arr(attrs, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); - - if (!attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) - return NL_SKIP; - - nla_parse_arr(trig, - nla_data(attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), - nla_len(attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), - NULL); - - *wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_NONE; - if (trig[NL80211_WOWLAN_TRIG_ANY]) - *wowl |= NM_SETTING_WIRELESS_WAKE_ON_WLAN_ANY; - if (trig[NL80211_WOWLAN_TRIG_DISCONNECT]) - *wowl |= NM_SETTING_WIRELESS_WAKE_ON_WLAN_DISCONNECT; - if (trig[NL80211_WOWLAN_TRIG_MAGIC_PKT]) - *wowl |= NM_SETTING_WIRELESS_WAKE_ON_WLAN_MAGIC; - if (trig[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE]) - *wowl |= NM_SETTING_WIRELESS_WAKE_ON_WLAN_GTK_REKEY_FAILURE; - if (trig[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) - *wowl |= NM_SETTING_WIRELESS_WAKE_ON_WLAN_EAP_IDENTITY_REQUEST; - if (trig[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) - *wowl |= NM_SETTING_WIRELESS_WAKE_ON_WLAN_4WAY_HANDSHAKE; - if (trig[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) - *wowl |= NM_SETTING_WIRELESS_WAKE_ON_WLAN_RFKILL_RELEASE; - if (trig[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) - *wowl |= NM_SETTING_WIRELESS_WAKE_ON_WLAN_TCP; - - return NL_SKIP; -} - -static NMSettingWirelessWakeOnWLan -wifi_nl80211_get_wake_on_wlan(NMWifiUtils *data) -{ - NMWifiUtilsNl80211 * self = (NMWifiUtilsNl80211 *) data; - NMSettingWirelessWakeOnWLan wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE; - nm_auto_nlmsg struct nl_msg *msg = NULL; - - msg = nl80211_alloc_msg(self, NL80211_CMD_GET_WOWLAN, 0); - - nl80211_send_and_recv(self, msg, nl80211_get_wake_on_wlan_handler, &wowl); - - return wowl; -} - -static gboolean -wifi_nl80211_set_wake_on_wlan(NMWifiUtils *data, NMSettingWirelessWakeOnWLan wowl) -{ - NMWifiUtilsNl80211 * self = (NMWifiUtilsNl80211 *) data; - nm_auto_nlmsg struct nl_msg *msg = NULL; - struct nlattr * triggers; - int err; - - if (wowl == NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE) - return TRUE; - - msg = nl80211_alloc_msg(self, NL80211_CMD_SET_WOWLAN, 0); - - triggers = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS); - if (!triggers) - goto nla_put_failure; - - if (NM_FLAGS_HAS(wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_ANY)) - NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY); - if (NM_FLAGS_HAS(wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_DISCONNECT)) - NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT); - if (NM_FLAGS_HAS(wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_MAGIC)) - NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); - if (NM_FLAGS_HAS(wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_GTK_REKEY_FAILURE)) - NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE); - if (NM_FLAGS_HAS(wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_EAP_IDENTITY_REQUEST)) - NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST); - if (NM_FLAGS_HAS(wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_4WAY_HANDSHAKE)) - NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE); - if (NM_FLAGS_HAS(wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_RFKILL_RELEASE)) - NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE); - - nla_nest_end(msg, triggers); - - err = nl80211_send_and_recv(self, msg, NULL, NULL); - - return err >= 0; - -nla_put_failure: - g_return_val_if_reached(FALSE); -} - -static guint32 -wifi_nl80211_get_freq(NMWifiUtils *data) -{ - NMWifiUtilsNl80211 * self = (NMWifiUtilsNl80211 *) data; - struct nl80211_iface_info iface_info = {}; - nm_auto_nlmsg struct nl_msg *msg = NULL; - - msg = nl80211_alloc_msg(self, NL80211_CMD_GET_INTERFACE, 0); - - if (nl80211_send_and_recv(self, msg, nl80211_iface_info_handler, &iface_info) < 0) - return 0; - - return iface_info.freq; -} - -static guint32 -wifi_nl80211_find_freq(NMWifiUtils *data, const guint32 *freqs) -{ - NMWifiUtilsNl80211 *self = (NMWifiUtilsNl80211 *) data; - int i; - - for (i = 0; i < self->num_freqs; i++) { - while (*freqs) { - if (self->freqs[i] == *freqs) - return *freqs; - freqs++; - } - } - return 0; -} - -/* @divisor: pass what value @xbm should be divided by to get dBm */ -static guint32 -nl80211_xbm_to_percent(gint32 xbm, guint32 divisor) -{ -#define NOISE_FLOOR_DBM -90 -#define SIGNAL_MAX_DBM -20 - - xbm /= divisor; - xbm = CLAMP(xbm, NOISE_FLOOR_DBM, SIGNAL_MAX_DBM); - - return 100 - - 70 - * (((float) SIGNAL_MAX_DBM - (float) xbm) - / ((float) SIGNAL_MAX_DBM - (float) NOISE_FLOOR_DBM)); -} - -struct nl80211_station_info { - gboolean valid; - guint8 bssid[ETH_ALEN]; - guint32 txrate; - gboolean txrate_valid; - guint8 signal; - gboolean signal_valid; -}; - -static int -nl80211_station_dump_handler(struct nl_msg *msg, void *arg) -{ - static const struct nla_policy stats_policy[] = { - [NL80211_STA_INFO_INACTIVE_TIME] = {.type = NLA_U32}, - [NL80211_STA_INFO_RX_BYTES] = {.type = NLA_U32}, - [NL80211_STA_INFO_TX_BYTES] = {.type = NLA_U32}, - [NL80211_STA_INFO_RX_PACKETS] = {.type = NLA_U32}, - [NL80211_STA_INFO_TX_PACKETS] = {.type = NLA_U32}, - [NL80211_STA_INFO_SIGNAL] = {.type = NLA_U8}, - [NL80211_STA_INFO_TX_BITRATE] = {.type = NLA_NESTED}, - [NL80211_STA_INFO_LLID] = {.type = NLA_U16}, - [NL80211_STA_INFO_PLID] = {.type = NLA_U16}, - [NL80211_STA_INFO_PLINK_STATE] = {.type = NLA_U8}, - [NL80211_STA_INFO_STA_FLAGS] = {.minlen = sizeof(struct nl80211_sta_flag_update)}, - [NL80211_STA_INFO_BEACON_SIGNAL_AVG] = {.type = NLA_U8}, - }; - static const struct nla_policy rate_policy[] = { - [NL80211_RATE_INFO_BITRATE] = {.type = NLA_U16}, - [NL80211_RATE_INFO_MCS] = {.type = NLA_U8}, - [NL80211_RATE_INFO_40_MHZ_WIDTH] = {.type = NLA_FLAG}, - [NL80211_RATE_INFO_SHORT_GI] = {.type = NLA_FLAG}, - }; - struct nlattr * rinfo[G_N_ELEMENTS(rate_policy)]; - struct nlattr * sinfo[G_N_ELEMENTS(stats_policy)]; - struct nl80211_station_info *info = arg; - struct nlattr * tb[NL80211_ATTR_MAX + 1]; - struct genlmsghdr * gnlh = nlmsg_data(nlmsg_hdr(msg)); - - if (nla_parse_arr(tb, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL) < 0) - return NL_SKIP; - - if (tb[NL80211_ATTR_MAC] == NULL) - return NL_SKIP; - - if (tb[NL80211_ATTR_STA_INFO] == NULL) - return NL_SKIP; - - if (nla_parse_nested_arr(sinfo, tb[NL80211_ATTR_STA_INFO], stats_policy)) - return NL_SKIP; - - if (sinfo[NL80211_STA_INFO_STA_FLAGS] != NULL) { - const struct nl80211_sta_flag_update *flags = nla_data(sinfo[NL80211_STA_INFO_STA_FLAGS]); - - if (flags->mask & ~flags->set & (1 << NL80211_STA_FLAG_ASSOCIATED)) - return NL_SKIP; - } - - memcpy(info->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); - info->valid = TRUE; - - if (sinfo[NL80211_STA_INFO_TX_BITRATE] != NULL - && !nla_parse_nested_arr(rinfo, sinfo[NL80211_STA_INFO_TX_BITRATE], rate_policy) - && rinfo[NL80211_RATE_INFO_BITRATE] != NULL) { - /* convert from nl80211's units of 100kbps to NM's kbps */ - info->txrate = nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]) * 100; - info->txrate_valid = TRUE; - } - - if (sinfo[NL80211_STA_INFO_SIGNAL] != NULL) { - info->signal = - nl80211_xbm_to_percent((gint8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]), 1); - info->signal_valid = TRUE; - } else if (sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG] != NULL) { - /* Fall back to beacon signal strength */ - info->signal = - nl80211_xbm_to_percent((gint8) nla_get_u8(sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG]), - 1); - info->signal_valid = TRUE; - } - - return NL_SKIP; -} - -static gboolean -wifi_nl80211_get_station(NMWifiUtils *data, - NMEtherAddr *out_bssid, - int * out_quality, - guint32 * out_rate) -{ - NMWifiUtilsNl80211 * self = (NMWifiUtilsNl80211 *) data; - nm_auto_nlmsg struct nl_msg *msg = NULL; - struct nl80211_station_info sta_info = {}; - - msg = nl80211_alloc_msg(self, NL80211_CMD_GET_STATION, NLM_F_DUMP); - - nl80211_send_and_recv(self, msg, nl80211_station_dump_handler, &sta_info); - - if (!sta_info.valid || (out_quality && !sta_info.signal_valid) - || (out_rate && !sta_info.txrate_valid)) - return FALSE; - - if (out_bssid) - memcpy(out_bssid, sta_info.bssid, ETH_ALEN); - - if (out_quality) - *out_quality = sta_info.signal; - - if (out_rate) - *out_rate = sta_info.txrate; - - return TRUE; -} - -static gboolean -wifi_nl80211_indicate_addressing_running(NMWifiUtils *data, gboolean running) -{ - NMWifiUtilsNl80211 * self = (NMWifiUtilsNl80211 *) data; - nm_auto_nlmsg struct nl_msg *msg = NULL; - int err; - - msg = nl80211_alloc_msg(self, - running ? 98 /* NL80211_CMD_CRIT_PROTOCOL_START */ - : 99 /* NL80211_CMD_CRIT_PROTOCOL_STOP */, - 0); - /* Despite the DHCP name, we're using this for any type of IP addressing, - * DHCPv4, DHCPv6, and IPv6 SLAAC. - */ - NLA_PUT_U16(msg, 179 /* NL80211_ATTR_CRIT_PROT_ID */, 1 /* NL80211_CRIT_PROTO_DHCP */); - if (running) { - /* Give DHCP 5 seconds to complete */ - NLA_PUT_U16(msg, 180 /* NL80211_ATTR_MAX_CRIT_PROT_DURATION */, 5000); - } - - err = nl80211_send_and_recv(self, msg, NULL, NULL); - return err >= 0; - -nla_put_failure: - g_return_val_if_reached(FALSE); -} - -struct nl80211_device_info { - NMWifiUtilsNl80211 *self; - int phy; - guint32 * freqs; - int num_freqs; - guint32 freq; - guint32 caps; - gboolean can_scan; - gboolean can_scan_ssid; - gboolean supported; - gboolean success; - gboolean can_wowlan; -}; - -#define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00 -#define WLAN_CIPHER_SUITE_WEP40 0x000FAC01 -#define WLAN_CIPHER_SUITE_TKIP 0x000FAC02 -#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04 -#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05 -#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06 -#define WLAN_CIPHER_SUITE_GCMP 0x000FAC08 -#define WLAN_CIPHER_SUITE_SMS4 0x00147201 - -static int -nl80211_wiphy_info_handler(struct nl_msg *msg, void *arg) -{ - static const struct nla_policy freq_policy[] = { - [NL80211_FREQUENCY_ATTR_FREQ] = {.type = NLA_U32}, - [NL80211_FREQUENCY_ATTR_DISABLED] = {.type = NLA_FLAG}, -#ifdef NL80211_FREQUENCY_ATTR_NO_IR - [NL80211_FREQUENCY_ATTR_NO_IR] = {.type = NLA_FLAG}, -#else - [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = {.type = NLA_FLAG}, - [NL80211_FREQUENCY_ATTR_NO_IBSS] = {.type = NLA_FLAG}, -#endif - [NL80211_FREQUENCY_ATTR_RADAR] = {.type = NLA_FLAG}, - [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = {.type = NLA_U32}, - }; - struct nlattr * tb[NL80211_ATTR_MAX + 1]; - struct genlmsghdr * gnlh = nlmsg_data(nlmsg_hdr(msg)); - struct nl80211_device_info *info = arg; - NMWifiUtilsNl80211 * self = info->self; - struct nlattr * tb_band[NL80211_BAND_ATTR_MAX + 1]; - struct nlattr * tb_freq[G_N_ELEMENTS(freq_policy)]; - struct nlattr * nl_band; - struct nlattr * nl_freq; - int rem_freq; - int rem_band; - int freq_idx; - -#ifdef NL80211_FREQUENCY_ATTR_NO_IR - G_STATIC_ASSERT_EXPR(NL80211_FREQUENCY_ATTR_PASSIVE_SCAN == NL80211_FREQUENCY_ATTR_NO_IR - && NL80211_FREQUENCY_ATTR_NO_IBSS == NL80211_FREQUENCY_ATTR_NO_IR); -#else - G_STATIC_ASSERT_EXPR(NL80211_FREQUENCY_ATTR_PASSIVE_SCAN != NL80211_FREQUENCY_ATTR_NO_IBSS); -#endif - - if (nla_parse_arr(tb, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL) < 0) - return NL_SKIP; - - if (tb[NL80211_ATTR_WIPHY] == NULL || tb[NL80211_ATTR_WIPHY_BANDS] == NULL) - return NL_SKIP; - - info->phy = nla_get_u32(tb[NL80211_ATTR_WIPHY]); - - if (tb[NL80211_ATTR_WIPHY_FREQ]) - info->freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); - else - info->freq = 0; - - if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) { - info->can_scan_ssid = nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]) > 0; - } else { - /* old kernel that only had mac80211, so assume it can */ - info->can_scan_ssid = TRUE; - } - - if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) { - struct nlattr *nl_cmd; - int i; - - nla_for_each_nested (nl_cmd, tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) { - switch (nla_get_u32(nl_cmd)) { - case NL80211_CMD_TRIGGER_SCAN: - info->can_scan = TRUE; - break; - case NL80211_CMD_CONNECT: - case NL80211_CMD_AUTHENTICATE: - /* Only devices that support CONNECT or AUTH actually support - * 802.11, unlike say ipw2x00 (up to at least kernel 3.4) which - * has minimal info support, but no actual command support. - * This check mirrors what wpa_supplicant does to determine - * whether or not to use the nl80211 driver. - */ - info->supported = TRUE; - break; - default: - break; - } - } - } - - /* Find number of supported frequencies */ - info->num_freqs = 0; - - nla_for_each_nested (nl_band, tb[NL80211_ATTR_WIPHY_BANDS], rem_band) { - if (nla_parse_nested_arr(tb_band, nl_band, NULL) < 0) - return NL_SKIP; - - nla_for_each_nested (nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { - if (nla_parse_nested_arr(tb_freq, nl_freq, freq_policy) < 0) - continue; - - if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) - continue; - - info->num_freqs++; - } - } - - /* Read supported frequencies */ - info->freqs = g_malloc0(sizeof(guint32) * info->num_freqs); - - freq_idx = 0; - nla_for_each_nested (nl_band, tb[NL80211_ATTR_WIPHY_BANDS], rem_band) { - if (nla_parse_nested_arr(tb_band, nl_band, NULL) < 0) - return NL_SKIP; - - nla_for_each_nested (nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) { - if (nla_parse_nested_arr(tb_freq, nl_freq, freq_policy) < 0) - continue; - - if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) - continue; - - info->freqs[freq_idx] = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); - - info->caps |= NM_WIFI_DEVICE_CAP_FREQ_VALID; - - if (info->freqs[freq_idx] > 2400 && info->freqs[freq_idx] < 2500) - info->caps |= NM_WIFI_DEVICE_CAP_FREQ_2GHZ; - if (info->freqs[freq_idx] > 4900 && info->freqs[freq_idx] < 6000) - info->caps |= NM_WIFI_DEVICE_CAP_FREQ_5GHZ; - - freq_idx++; - } - } - - /* Read security/encryption support */ - if (tb[NL80211_ATTR_CIPHER_SUITES]) { - guint32 *ciphers = nla_data(tb[NL80211_ATTR_CIPHER_SUITES]); - guint i, num; - - num = nla_len(tb[NL80211_ATTR_CIPHER_SUITES]) / sizeof(guint32); - for (i = 0; i < num; i++) { - switch (ciphers[i]) { - case WLAN_CIPHER_SUITE_WEP40: - info->caps |= NM_WIFI_DEVICE_CAP_CIPHER_WEP40; - break; - case WLAN_CIPHER_SUITE_WEP104: - info->caps |= NM_WIFI_DEVICE_CAP_CIPHER_WEP104; - break; - case WLAN_CIPHER_SUITE_TKIP: - info->caps |= (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | NM_WIFI_DEVICE_CAP_WPA); - break; - case WLAN_CIPHER_SUITE_CCMP: - info->caps |= (NM_WIFI_DEVICE_CAP_CIPHER_CCMP | NM_WIFI_DEVICE_CAP_RSN); - break; - case WLAN_CIPHER_SUITE_AES_CMAC: - case WLAN_CIPHER_SUITE_GCMP: - case WLAN_CIPHER_SUITE_SMS4: - break; - default: - _LOGD("don't know the meaning of NL80211_ATTR_CIPHER_SUITE %#8.8x.", ciphers[i]); - break; - } - } - } - - if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) { - struct nlattr *nl_mode; - int i; - - nla_for_each_nested (nl_mode, tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) { - switch (nla_type(nl_mode)) { - case NL80211_IFTYPE_AP: - info->caps |= NM_WIFI_DEVICE_CAP_AP; - break; - case NL80211_IFTYPE_ADHOC: - info->caps |= NM_WIFI_DEVICE_CAP_ADHOC; - break; - case NL80211_IFTYPE_MESH_POINT: - info->caps |= NM_WIFI_DEVICE_CAP_MESH; - break; - } - } - } - - if (tb[NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED]) - info->can_wowlan = TRUE; - - if (tb[NL80211_ATTR_SUPPORT_IBSS_RSN]) - info->caps |= NM_WIFI_DEVICE_CAP_IBSS_RSN; - - info->success = TRUE; - - return NL_SKIP; -} - -static guint32 -wifi_nl80211_get_mesh_channel(NMWifiUtils *data) -{ - NMWifiUtilsNl80211 * self = (NMWifiUtilsNl80211 *) data; - nm_auto_nlmsg struct nl_msg *msg = NULL; - struct nl80211_device_info device_info = {.self = self}; - int i; - - msg = nl80211_alloc_msg(self, NL80211_CMD_GET_WIPHY, 0); - - if (nl80211_send_and_recv(self, msg, nl80211_wiphy_info_handler, &device_info) < 0) { - _LOGW("NL80211_CMD_GET_WIPHY request failed"); - return 0; - } - - for (i = 0; i < self->num_freqs; i++) { - if (device_info.freq == self->freqs[i]) - return i + 1; - } - return 0; -} - -static gboolean -wifi_nl80211_set_mesh_channel(NMWifiUtils *data, guint32 channel) -{ - NMWifiUtilsNl80211 * self = (NMWifiUtilsNl80211 *) data; - nm_auto_nlmsg struct nl_msg *msg = NULL; - int err; - - if (channel > self->num_freqs) - return FALSE; - - msg = nl80211_alloc_msg(self, NL80211_CMD_SET_WIPHY, 0); - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, self->freqs[channel - 1]); - err = nl80211_send_and_recv(self, msg, NULL, NULL); - return err >= 0; - -nla_put_failure: - g_return_val_if_reached(FALSE); -} - -static gboolean -wifi_nl80211_set_mesh_ssid(NMWifiUtils *data, const guint8 *ssid, gsize len) -{ - NMWifiUtilsNl80211 * self = (NMWifiUtilsNl80211 *) data; - nm_auto_nlmsg struct nl_msg *msg = NULL; - int err; - - msg = nl80211_alloc_msg(self, NL80211_CMD_SET_INTERFACE, 0); - NLA_PUT(msg, NL80211_ATTR_MESH_ID, len, ssid); - err = nl80211_send_and_recv(self, msg, NULL, NULL); - return err >= 0; - -nla_put_failure: - g_return_val_if_reached(FALSE); -} - -static void -nm_wifi_utils_nl80211_init(NMWifiUtilsNl80211 *self) -{} - -static void -nm_wifi_utils_nl80211_class_init(NMWifiUtilsNl80211Class *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMWifiUtilsClass *wifi_utils_class = NM_WIFI_UTILS_CLASS(klass); - - object_class->dispose = dispose; - - wifi_utils_class->get_mode = wifi_nl80211_get_mode; - wifi_utils_class->set_mode = wifi_nl80211_set_mode; - wifi_utils_class->set_powersave = wifi_nl80211_set_powersave; - wifi_utils_class->get_wake_on_wlan = wifi_nl80211_get_wake_on_wlan, - wifi_utils_class->set_wake_on_wlan = wifi_nl80211_set_wake_on_wlan, - wifi_utils_class->get_freq = wifi_nl80211_get_freq; - wifi_utils_class->find_freq = wifi_nl80211_find_freq; - wifi_utils_class->get_station = wifi_nl80211_get_station; - wifi_utils_class->indicate_addressing_running = wifi_nl80211_indicate_addressing_running; - wifi_utils_class->get_mesh_channel = wifi_nl80211_get_mesh_channel; - wifi_utils_class->set_mesh_channel = wifi_nl80211_set_mesh_channel; - wifi_utils_class->set_mesh_ssid = wifi_nl80211_set_mesh_ssid; -} - -NMWifiUtils * -nm_wifi_utils_nl80211_new(int ifindex, struct nl_sock *genl) -{ - gs_unref_object NMWifiUtilsNl80211 *self = NULL; - nm_auto_nlmsg struct nl_msg * msg = NULL; - struct nl80211_device_info device_info = {}; - - if (!genl) - return NULL; - - self = g_object_new(NM_TYPE_WIFI_UTILS_NL80211, NULL); - - self->parent.ifindex = ifindex; - self->nl_sock = genl; - - self->id = genl_ctrl_resolve(self->nl_sock, "nl80211"); - if (self->id < 0) { - _LOGD("genl_ctrl_resolve: failed to resolve \"nl80211\""); - return NULL; - } - - self->phy = -1; - - msg = nl80211_alloc_msg(self, NL80211_CMD_GET_WIPHY, 0); - - device_info.self = self; - if (nl80211_send_and_recv(self, msg, nl80211_wiphy_info_handler, &device_info) < 0) { - _LOGD("NL80211_CMD_GET_WIPHY request failed"); - return NULL; - } - - if (!device_info.success) { - _LOGD("NL80211_CMD_GET_WIPHY request indicated failure"); - return NULL; - } - - if (!device_info.supported) { - _LOGD("driver does not fully support nl80211, falling back to WEXT"); - return NULL; - } - - if (!device_info.can_scan_ssid) { - _LOGE("driver does not support SSID scans"); - return NULL; - } - - if (device_info.num_freqs == 0 || device_info.freqs == NULL) { - _LOGE("driver reports no supported frequencies"); - return NULL; - } - - if (device_info.caps == 0) { - _LOGE("driver doesn't report support of any encryption"); - return NULL; - } - - self->phy = device_info.phy; - self->freqs = device_info.freqs; - self->num_freqs = device_info.num_freqs; - self->parent.caps = device_info.caps; - self->can_wowlan = device_info.can_wowlan; - - _LOGD("using nl80211 for Wi-Fi device control"); - return (NMWifiUtils *) g_steal_pointer(&self); -} diff --git a/src/core/platform/wifi/nm-wifi-utils-nl80211.h b/src/core/platform/wifi/nm-wifi-utils-nl80211.h deleted file mode 100644 index 37c32ed7..00000000 --- a/src/core/platform/wifi/nm-wifi-utils-nl80211.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2011 Intel Corporation. All rights reserved. - * Copyright (C) 2018 Red Hat, Inc. - */ - -#ifndef __WIFI_UTILS_NL80211_H__ -#define __WIFI_UTILS_NL80211_H__ - -#include "nm-wifi-utils.h" -#include "nm-platform/nm-netlink.h" - -#define NM_TYPE_WIFI_UTILS_NL80211 (nm_wifi_utils_nl80211_get_type()) -#define NM_WIFI_UTILS_NL80211(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WIFI_UTILS_NL80211, NMWifiUtilsNl80211)) -#define NM_WIFI_UTILS_NL80211_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_WIFI_UTILS_NL80211, NMWifiUtilsNl80211Class)) -#define NM_IS_WIFI_UTILS_NL80211(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_WIFI_UTILS_NL80211)) -#define NM_IS_WIFI_UTILS_NL80211_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_WIFI_UTILS_NL80211)) -#define NM_WIFI_UTILS_NL80211_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_WIFI_UTILS_NL80211, NMWifiUtilsNl80211Class)) - -GType nm_wifi_utils_nl80211_get_type(void); - -NMWifiUtils *nm_wifi_utils_nl80211_new(int ifindex, struct nl_sock *genl); - -#endif /* __WIFI_UTILS_NL80211_H__ */ diff --git a/src/core/platform/wifi/nm-wifi-utils-private.h b/src/core/platform/wifi/nm-wifi-utils-private.h deleted file mode 100644 index 9ed57453..00000000 --- a/src/core/platform/wifi/nm-wifi-utils-private.h +++ /dev/null @@ -1,66 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2011 - 2018 Red Hat, Inc. - */ - -#ifndef __WIFI_UTILS_PRIVATE_H__ -#define __WIFI_UTILS_PRIVATE_H__ - -#include "nm-dbus-interface.h" -#include "nm-wifi-utils.h" - -typedef struct { - GObjectClass parent; - - NM80211Mode (*get_mode)(NMWifiUtils *data); - - gboolean (*set_mode)(NMWifiUtils *data, const NM80211Mode mode); - - /* Set power saving mode on an interface */ - gboolean (*set_powersave)(NMWifiUtils *data, guint32 powersave); - - /* Get WakeOnWLAN configuration on an interface */ - NMSettingWirelessWakeOnWLan (*get_wake_on_wlan)(NMWifiUtils *data); - - /* Set WakeOnWLAN mode on an interface */ - gboolean (*set_wake_on_wlan)(NMWifiUtils *data, NMSettingWirelessWakeOnWLan wowl); - - /* Return current frequency in MHz (really associated BSS frequency) */ - guint32 (*get_freq)(NMWifiUtils *data); - - /* Return first supported frequency in the zero-terminated list */ - guint32 (*find_freq)(NMWifiUtils *data, const guint32 *freqs); - - /* - * @out_bssid: must be NULL or an ETH_ALEN-byte buffer - * @out_quality: receives signal strength percentage 0 - 100% for the current BSSID, if not NULL - * @out_rate: receives current bitrate in Kbps if not NULL - * - * Returns %TRUE on succcess, %FALSE on errors or if not associated. - */ - gboolean (*get_station)(NMWifiUtils *data, - NMEtherAddr *out_bssid, - int * out_quality, - guint32 * out_rate); - - /* OLPC Mesh-only functions */ - - guint32 (*get_mesh_channel)(NMWifiUtils *data); - - /* channel == 0 means "auto channel" */ - gboolean (*set_mesh_channel)(NMWifiUtils *data, guint32 channel); - - /* ssid == NULL means "auto SSID" */ - gboolean (*set_mesh_ssid)(NMWifiUtils *data, const guint8 *ssid, gsize len); - - gboolean (*indicate_addressing_running)(NMWifiUtils *data, gboolean running); -} NMWifiUtilsClass; - -struct NMWifiUtils { - GObject parent; - - int ifindex; - NMDeviceWifiCapabilities caps; -}; - -#endif /* __WIFI_UTILS_PRIVATE_H__ */ diff --git a/src/core/platform/wifi/nm-wifi-utils-wext.c b/src/core/platform/wifi/nm-wifi-utils-wext.c deleted file mode 100644 index a44fcf62..00000000 --- a/src/core/platform/wifi/nm-wifi-utils-wext.c +++ /dev/null @@ -1,836 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2005 - 2018 Red Hat, Inc. - * Copyright (C) 2006 - 2008 Novell, Inc. - */ - -#include "src/core/nm-default-daemon.h" - -#include "nm-wifi-utils-wext.h" - -#include -#include -#include - -/* Hacks necessary to #include wireless.h; yay for WEXT */ -#ifndef __user - #define __user -#endif -#include -#include -#include -#include - -#include "nm-wifi-utils-private.h" -#include "nm-utils.h" -#include "nm-platform/nm-platform-utils.h" -#include "nm-core-internal.h" -#include "nm-core-utils.h" - -typedef struct { - NMWifiUtils parent; - int fd; - struct iw_quality max_qual; - gint8 num_freqs; - guint32 freqs[IW_MAX_FREQUENCIES]; -} NMWifiUtilsWext; - -typedef struct { - NMWifiUtilsClass parent; -} NMWifiUtilsWextClass; - -G_DEFINE_TYPE(NMWifiUtilsWext, nm_wifi_utils_wext, NM_TYPE_WIFI_UTILS) - -/* Until a new wireless-tools comes out that has the defs and the structure, - * need to copy them here. - */ -/* Scan capability flags - in (struct iw_range *)->scan_capa */ -#define NM_IW_SCAN_CAPA_NONE 0x00 -#define NM_IW_SCAN_CAPA_ESSID 0x01 - -struct iw_range_with_scan_capa { - guint32 throughput; - guint32 min_nwid; - guint32 max_nwid; - guint16 old_num_channels; - guint8 old_num_frequency; - - guint8 scan_capa; - /* don't need the rest... */ -}; - -#define _NMLOG_PREFIX_NAME "wifi-wext" -#define _NMLOG(level, domain, ...) \ - G_STMT_START \ - { \ - nm_log((level), \ - (domain), \ - NULL, \ - NULL, \ - "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - _NMLOG_PREFIX_NAME _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - G_STMT_END - -static guint32 -iw_freq_to_uint32(const struct iw_freq *freq) -{ - if (freq->e == 0) { - /* Some drivers report channel not frequency. Convert to a - * frequency; but this assumes that the device is in b/g mode. - */ - if ((freq->m >= 1) && (freq->m <= 13)) - return 2407 + (5 * freq->m); - else if (freq->m == 14) - return 2484; - } - return (guint32)((((double) freq->m) * nm_utils_exp10(freq->e)) / 1000000.0); -} - -static void -dispose(GObject *object) -{ - NMWifiUtilsWext *wext = NM_WIFI_UTILS_WEXT(object); - - wext->fd = nm_close(wext->fd); -} - -static gboolean -get_ifname(int ifindex, char *buffer, const char *op) -{ - int errsv; - - if (!nmp_utils_if_indextoname(ifindex, buffer)) { - errsv = errno; - _LOGW(LOGD_PLATFORM | LOGD_WIFI, - "error getting interface name for ifindex %d, operation '%s': %s (%d)", - ifindex, - op, - nm_strerror_native(errsv), - errsv); - return FALSE; - } - - return TRUE; -} - -static NM80211Mode -wifi_wext_get_mode_ifname(NMWifiUtils *data, const char *ifname) -{ - NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data; - struct iwreq wrq; - int errsv; - - memset(&wrq, 0, sizeof(struct iwreq)); - nm_utils_ifname_cpy(wrq.ifr_name, ifname); - - if (ioctl(wext->fd, SIOCGIWMODE, &wrq) < 0) { - errsv = errno; - if (errsv != ENODEV) { - _LOGW(LOGD_PLATFORM | LOGD_WIFI, "(%s): error %d getting card mode", ifname, errsv); - } - return NM_802_11_MODE_UNKNOWN; - } - - switch (wrq.u.mode) { - case IW_MODE_ADHOC: - return NM_802_11_MODE_ADHOC; - case IW_MODE_MASTER: - return NM_802_11_MODE_AP; - case IW_MODE_INFRA: - case IW_MODE_AUTO: /* hack for WEXT devices reporting IW_MODE_AUTO */ - return NM_802_11_MODE_INFRA; - default: - break; - } - return NM_802_11_MODE_UNKNOWN; -} - -static NM80211Mode -wifi_wext_get_mode(NMWifiUtils *data) -{ - char ifname[IFNAMSIZ]; - - if (!get_ifname(data->ifindex, ifname, "get-mode")) - return FALSE; - - return wifi_wext_get_mode_ifname(data, ifname); -} - -static gboolean -wifi_wext_set_mode(NMWifiUtils *data, const NM80211Mode mode) -{ - NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data; - struct iwreq wrq; - char ifname[IFNAMSIZ]; - - if (!get_ifname(data->ifindex, ifname, "set-mode")) - return FALSE; - - if (wifi_wext_get_mode_ifname(data, ifname) == mode) - return TRUE; - - memset(&wrq, 0, sizeof(struct iwreq)); - switch (mode) { - case NM_802_11_MODE_ADHOC: - wrq.u.mode = IW_MODE_ADHOC; - break; - case NM_802_11_MODE_AP: - wrq.u.mode = IW_MODE_MASTER; - break; - case NM_802_11_MODE_INFRA: - wrq.u.mode = IW_MODE_INFRA; - break; - default: - g_warn_if_reached(); - return FALSE; - } - - nm_utils_ifname_cpy(wrq.ifr_name, ifname); - if (ioctl(wext->fd, SIOCSIWMODE, &wrq) < 0) { - if (errno != ENODEV) { - _LOGE(LOGD_PLATFORM | LOGD_WIFI, "(%s): error setting mode %d", ifname, mode); - } - return FALSE; - } - - return TRUE; -} - -static gboolean -wifi_wext_set_powersave(NMWifiUtils *data, guint32 powersave) -{ - NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data; - struct iwreq wrq; - char ifname[IFNAMSIZ]; - - if (!get_ifname(data->ifindex, ifname, "set-powersave")) - return FALSE; - - memset(&wrq, 0, sizeof(struct iwreq)); - if (powersave == 1) { - wrq.u.power.flags = IW_POWER_ALL_R; - } else - wrq.u.power.disabled = 1; - - nm_utils_ifname_cpy(wrq.ifr_name, ifname); - if (ioctl(wext->fd, SIOCSIWPOWER, &wrq) < 0) { - if (errno != ENODEV) { - _LOGE(LOGD_PLATFORM | LOGD_WIFI, - "(%s): error setting powersave %" G_GUINT32_FORMAT, - ifname, - powersave); - } - return FALSE; - } - - return TRUE; -} - -static guint32 -wifi_wext_get_freq(NMWifiUtils *data) -{ - NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data; - struct iwreq wrq; - char ifname[IFNAMSIZ]; - - if (!get_ifname(data->ifindex, ifname, "get-freq")) - return FALSE; - - memset(&wrq, 0, sizeof(struct iwreq)); - nm_utils_ifname_cpy(wrq.ifr_name, ifname); - if (ioctl(wext->fd, SIOCGIWFREQ, &wrq) < 0) { - _LOGW(LOGD_PLATFORM | LOGD_WIFI, - "(%s): error getting frequency: %s", - ifname, - nm_strerror_native(errno)); - return 0; - } - - return iw_freq_to_uint32(&wrq.u.freq); -} - -static guint32 -wifi_wext_find_freq(NMWifiUtils *data, const guint32 *freqs) -{ - NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data; - int i; - - for (i = 0; i < wext->num_freqs; i++) { - while (*freqs) { - if (wext->freqs[i] == *freqs) - return *freqs; - freqs++; - } - } - return 0; -} - -static gboolean -wifi_wext_get_bssid(NMWifiUtils *data, NMEtherAddr *out_bssid) -{ - NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data; - struct iwreq wrq; - char ifname[IFNAMSIZ]; - - if (!get_ifname(data->ifindex, ifname, "get-bssid")) - return FALSE; - - memset(&wrq, 0, sizeof(wrq)); - nm_utils_ifname_cpy(wrq.ifr_name, ifname); - if (ioctl(wext->fd, SIOCGIWAP, &wrq) < 0) { - _LOGW(LOGD_PLATFORM | LOGD_WIFI, - "(%s): error getting associated BSSID: %s", - ifname, - nm_strerror_native(errno)); - return FALSE; - } - memcpy(out_bssid, &(wrq.u.ap_addr.sa_data), ETH_ALEN); - return TRUE; -} - -static guint32 -wifi_wext_get_rate(NMWifiUtils *data) -{ - NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data; - struct iwreq wrq; - int err; - char ifname[IFNAMSIZ]; - - if (!get_ifname(data->ifindex, ifname, "get-rate")) - return FALSE; - - memset(&wrq, 0, sizeof(wrq)); - nm_utils_ifname_cpy(wrq.ifr_name, ifname); - err = ioctl(wext->fd, SIOCGIWRATE, &wrq); - return ((err == 0) ? wrq.u.bitrate.value / 1000 : 0); -} - -static int -wext_qual_to_percent(const struct iw_quality *qual, const struct iw_quality *max_qual) -{ - int percent = -1; - int level_percent = -1; - - g_return_val_if_fail(qual != NULL, -1); - g_return_val_if_fail(max_qual != NULL, -1); - - /* Magically convert the many different WEXT quality representations to a percentage */ - - _LOGD(LOGD_WIFI, - "QL: qual %d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X, updated: 0x%X ** MAX: qual " - "%d/%u/0x%X, level %d/%u/0x%X, noise %d/%u/0x%X, updated: 0x%X", - (__s8) qual->qual, - qual->qual, - qual->qual, - (__s8) qual->level, - qual->level, - qual->level, - (__s8) qual->noise, - qual->noise, - qual->noise, - qual->updated, - (__s8) max_qual->qual, - max_qual->qual, - max_qual->qual, - (__s8) max_qual->level, - max_qual->level, - max_qual->level, - (__s8) max_qual->noise, - max_qual->noise, - max_qual->noise, - max_qual->updated); - - /* Try using the card's idea of the signal quality first as long as it tells us what the max quality is. - * Drivers that fill in quality values MUST treat them as percentages, ie the "Link Quality" MUST be - * bounded by 0 and max_qual->qual, and MUST change in a linear fashion. Within those bounds, drivers - * are free to use whatever they want to calculate "Link Quality". - */ - if ((max_qual->qual != 0) && !(max_qual->updated & IW_QUAL_QUAL_INVALID) - && !(qual->updated & IW_QUAL_QUAL_INVALID)) - percent = (int) (100 * ((double) qual->qual / (double) max_qual->qual)); - - /* If the driver doesn't specify a complete and valid quality, we have two options: - * - * 1) dBm: driver must specify max_qual->level = 0, and have valid values for - * qual->level and (qual->noise OR max_qual->noise) - * 2) raw RSSI: driver must specify max_qual->level > 0, and have valid values for - * qual->level and max_qual->level - * - * This is the WEXT spec. If this interpretation is wrong, I'll fix it. Otherwise, - * If drivers don't conform to it, they are wrong and need to be fixed. - */ - - if ((max_qual->level == 0) - && !(max_qual->updated & IW_QUAL_LEVEL_INVALID) /* Valid max_qual->level == 0 */ - && !(qual->updated & IW_QUAL_LEVEL_INVALID) /* Must have valid qual->level */ - && (((max_qual->noise > 0) - && !(max_qual->updated & IW_QUAL_NOISE_INVALID)) /* Must have valid max_qual->noise */ - || ((qual->noise > 0) - && !(qual->updated & IW_QUAL_NOISE_INVALID))) /* OR valid qual->noise */ - ) { -/* Absolute power values (dBm) */ - -/* Reasonable fallbacks for dumb drivers that don't specify either level. */ -#define FALLBACK_NOISE_FLOOR_DBM -90 -#define FALLBACK_SIGNAL_MAX_DBM -20 - int max_level = FALLBACK_SIGNAL_MAX_DBM; - int noise = FALLBACK_NOISE_FLOOR_DBM; - int level = qual->level - 0x100; - - level = CLAMP(level, FALLBACK_NOISE_FLOOR_DBM, FALLBACK_SIGNAL_MAX_DBM); - - if ((qual->noise > 0) && !(qual->updated & IW_QUAL_NOISE_INVALID)) - noise = qual->noise - 0x100; - else if ((max_qual->noise > 0) && !(max_qual->updated & IW_QUAL_NOISE_INVALID)) - noise = max_qual->noise - 0x100; - noise = CLAMP(noise, FALLBACK_NOISE_FLOOR_DBM, FALLBACK_SIGNAL_MAX_DBM - 1); - - /* A sort of signal-to-noise ratio calculation */ - level_percent = (int) (100 - - 70 - * (((double) max_level - (double) level) - / ((double) max_level - (double) noise))); - _LOGD(LOGD_WIFI, - "QL1: level_percent is %d. max_level %d, level %d, noise_floor %d.", - level_percent, - max_level, - level, - noise); - } else if ((max_qual->level != 0) - && !(max_qual->updated - & IW_QUAL_LEVEL_INVALID) /* Valid max_qual->level as upper bound */ - && !(qual->updated & IW_QUAL_LEVEL_INVALID)) { - /* Relative power values (RSSI) */ - - int level = qual->level; - - /* Signal level is relavtive (0 -> max_qual->level) */ - level = CLAMP(level, 0, max_qual->level); - level_percent = (int) (100 * ((double) level / (double) max_qual->level)); - _LOGD(LOGD_WIFI, - "QL2: level_percent is %d. max_level %d, level %d.", - level_percent, - max_qual->level, - level); - } else if (percent == -1) { - _LOGD(LOGD_WIFI, - "QL: Could not get quality %% value from driver. Driver is probably buggy."); - } - - /* If the quality percent was 0 or doesn't exist, then try to use signal levels instead */ - if ((percent < 1) && (level_percent >= 0)) - percent = level_percent; - - _LOGD(LOGD_WIFI, "QL: Final quality percent is %d (%d).", percent, CLAMP(percent, 0, 100)); - return (CLAMP(percent, 0, 100)); -} - -static int -wifi_wext_get_qual(NMWifiUtils *data) -{ - NMWifiUtilsWext * wext = (NMWifiUtilsWext *) data; - struct iwreq wrq; - struct iw_statistics stats; - char ifname[IFNAMSIZ]; - - if (!get_ifname(data->ifindex, ifname, "get-qual")) - return FALSE; - - memset(&stats, 0, sizeof(stats)); - wrq.u.data.pointer = &stats; - wrq.u.data.length = sizeof(stats); - wrq.u.data.flags = 1; /* Clear updated flag */ - nm_utils_ifname_cpy(wrq.ifr_name, ifname); - - if (ioctl(wext->fd, SIOCGIWSTATS, &wrq) < 0) { - _LOGW(LOGD_PLATFORM | LOGD_WIFI, - "(%s): error getting signal strength: %s", - ifname, - nm_strerror_native(errno)); - return -1; - } - - return wext_qual_to_percent(&stats.qual, &wext->max_qual); -} - -static gboolean -wifi_wext_get_station(NMWifiUtils *data, - NMEtherAddr *out_bssid, - int * out_quality, - guint32 * out_rate) -{ - NMEtherAddr local_addr; - - if (!out_bssid && !out_quality && !out_rate) { - /* hm, the caller requested no parameter at all? - * Don't simply return TRUE, but at least check that - * we can successfully fetch the bssid. */ - out_bssid = &local_addr; - } - - if (out_bssid) { - if (!wifi_wext_get_bssid(data, out_bssid)) - return FALSE; - } - if (out_quality) { - *out_quality = wifi_wext_get_qual(data); - if (*out_quality < 0) - return FALSE; - } - if (out_rate) { - *out_rate = wifi_wext_get_rate(data); - if (*out_rate == 0) - return FALSE; - } - return TRUE; -} - -/*****************************************************************************/ -/* OLPC Mesh-only functions */ - -static guint32 -wifi_wext_get_mesh_channel(NMWifiUtils *data) -{ - NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data; - guint32 freq; - int i; - - freq = nm_wifi_utils_get_freq(data); - for (i = 0; i < wext->num_freqs; i++) { - if (freq == wext->freqs[i]) - return i + 1; - } - return 0; -} - -static gboolean -wifi_wext_set_mesh_channel(NMWifiUtils *data, guint32 channel) -{ - NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data; - struct iwreq wrq; - char ifname[IFNAMSIZ]; - - if (!get_ifname(data->ifindex, ifname, "set-mesh-channel")) - return FALSE; - - memset(&wrq, 0, sizeof(struct iwreq)); - nm_utils_ifname_cpy(wrq.ifr_name, ifname); - - if (channel > 0) { - wrq.u.freq.flags = IW_FREQ_FIXED; - wrq.u.freq.e = 0; - wrq.u.freq.m = channel; - } - - if (ioctl(wext->fd, SIOCSIWFREQ, &wrq) < 0) { - _LOGE(LOGD_PLATFORM | LOGD_WIFI | LOGD_OLPC, - "(%s): error setting channel to %d: %s", - ifname, - channel, - nm_strerror_native(errno)); - return FALSE; - } - - return TRUE; -} - -static gboolean -wifi_wext_set_mesh_ssid(NMWifiUtils *data, const guint8 *ssid, gsize len) -{ - NMWifiUtilsWext *wext = (NMWifiUtilsWext *) data; - struct iwreq wrq; - char buf[IW_ESSID_MAX_SIZE + 1]; - char ifname[IFNAMSIZ]; - int errsv; - - if (!get_ifname(data->ifindex, ifname, "set-mesh-ssid")) - return FALSE; - - memset(buf, 0, sizeof(buf)); - memcpy(buf, ssid, MIN(sizeof(buf) - 1, len)); - - wrq.u.essid.pointer = (caddr_t) buf; - wrq.u.essid.length = len; - wrq.u.essid.flags = (len > 0) ? 1 : 0; /* 1=enable SSID, 0=disable/any */ - - nm_utils_ifname_cpy(wrq.ifr_name, ifname); - if (ioctl(wext->fd, SIOCSIWESSID, &wrq) == 0) - return TRUE; - - errsv = errno; - if (errsv != ENODEV) { - gs_free char *ssid_str = NULL; - - _LOGE(LOGD_PLATFORM | LOGD_WIFI | LOGD_OLPC, - "(%s): error setting SSID to %s: %s", - ifname, - (ssid_str = _nm_utils_ssid_to_string_arr(ssid, len)), - nm_strerror_native(errsv)); - } - - return FALSE; -} - -/*****************************************************************************/ - -static gboolean -wext_can_scan_ifname(NMWifiUtilsWext *wext, const char *ifname) -{ - struct iwreq wrq; - - memset(&wrq, 0, sizeof(struct iwreq)); - nm_utils_ifname_cpy(wrq.ifr_name, ifname); - if (ioctl(wext->fd, SIOCSIWSCAN, &wrq) < 0) { - if (errno == EOPNOTSUPP) - return FALSE; - } - return TRUE; -} - -static gboolean -wext_get_range_ifname(NMWifiUtilsWext *wext, - const char * ifname, - struct iw_range *range, - guint32 * response_len) -{ - int i = 26; - gboolean success = FALSE; - struct iwreq wrq; - int errsv; - - memset(&wrq, 0, sizeof(struct iwreq)); - nm_utils_ifname_cpy(wrq.ifr_name, ifname); - wrq.u.data.pointer = (caddr_t) range; - wrq.u.data.length = sizeof(struct iw_range); - - /* Need to give some drivers time to recover after suspend/resume - * (ex ipw3945 takes a few seconds to talk to its regulatory daemon; - * see rh bz#362421) - */ - while (i-- > 0) { - if (ioctl(wext->fd, SIOCGIWRANGE, &wrq) == 0) { - if (response_len) - *response_len = wrq.u.data.length; - success = TRUE; - break; - } else { - errsv = errno; - if (errsv != EAGAIN) { - _LOGE(LOGD_PLATFORM | LOGD_WIFI, - "(%s): couldn't get driver range information (%d).", - ifname, - errsv); - break; - } - } - - g_usleep(G_USEC_PER_SEC / 4); - } - - if (i <= 0) { - _LOGW(LOGD_PLATFORM | LOGD_WIFI, - "(%s): driver took too long to respond to IWRANGE query.", - ifname); - } - - return success; -} - -#define WPA_CAPS \ - (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | NM_WIFI_DEVICE_CAP_CIPHER_CCMP | NM_WIFI_DEVICE_CAP_WPA \ - | NM_WIFI_DEVICE_CAP_RSN) - -static guint32 -wext_get_caps(NMWifiUtilsWext *wext, const char *ifname, struct iw_range *range) -{ - guint32 caps = NM_WIFI_DEVICE_CAP_NONE; - - g_return_val_if_fail(wext != NULL, NM_WIFI_DEVICE_CAP_NONE); - g_return_val_if_fail(range != NULL, NM_WIFI_DEVICE_CAP_NONE); - - /* All drivers should support WEP by default */ - caps |= NM_WIFI_DEVICE_CAP_CIPHER_WEP40 | NM_WIFI_DEVICE_CAP_CIPHER_WEP104; - - if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP) - caps |= NM_WIFI_DEVICE_CAP_CIPHER_TKIP; - - if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP) - caps |= NM_WIFI_DEVICE_CAP_CIPHER_CCMP; - - if (range->enc_capa & IW_ENC_CAPA_WPA) - caps |= NM_WIFI_DEVICE_CAP_WPA; - - if (range->enc_capa & IW_ENC_CAPA_WPA2) - caps |= NM_WIFI_DEVICE_CAP_RSN; - - /* Check for cipher support but not WPA support */ - if ((caps & (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | NM_WIFI_DEVICE_CAP_CIPHER_CCMP)) - && !(caps & (NM_WIFI_DEVICE_CAP_WPA | NM_WIFI_DEVICE_CAP_RSN))) { - _LOGW(LOGD_WIFI, - "%s: device supports WPA ciphers but not WPA protocol; WPA unavailable.", - ifname); - caps &= ~WPA_CAPS; - } - - /* Check for WPA support but not cipher support */ - if ((caps & (NM_WIFI_DEVICE_CAP_WPA | NM_WIFI_DEVICE_CAP_RSN)) - && !(caps & (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | NM_WIFI_DEVICE_CAP_CIPHER_CCMP))) { - _LOGW(LOGD_WIFI, - "%s: device supports WPA protocol but not WPA ciphers; WPA unavailable.", - ifname); - caps &= ~WPA_CAPS; - } - - /* There's no way to detect Ad-Hoc/AP mode support with WEXT - * (other than actually trying to do it), so just assume that - * Ad-Hoc is supported and AP isn't. - */ - caps |= NM_WIFI_DEVICE_CAP_ADHOC; - - return caps; -} - -/*****************************************************************************/ - -static void -nm_wifi_utils_wext_init(NMWifiUtilsWext *self) -{} - -static void -nm_wifi_utils_wext_class_init(NMWifiUtilsWextClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMWifiUtilsClass *wifi_utils_class = NM_WIFI_UTILS_CLASS(klass); - - object_class->dispose = dispose; - - wifi_utils_class->get_mode = wifi_wext_get_mode; - wifi_utils_class->set_mode = wifi_wext_set_mode; - wifi_utils_class->set_powersave = wifi_wext_set_powersave; - wifi_utils_class->get_freq = wifi_wext_get_freq; - wifi_utils_class->find_freq = wifi_wext_find_freq; - wifi_utils_class->get_station = wifi_wext_get_station; - wifi_utils_class->get_mesh_channel = wifi_wext_get_mesh_channel; - wifi_utils_class->set_mesh_channel = wifi_wext_set_mesh_channel; - wifi_utils_class->set_mesh_ssid = wifi_wext_set_mesh_ssid; -} - -NMWifiUtils * -nm_wifi_utils_wext_new(int ifindex, gboolean check_scan) -{ - NMWifiUtilsWext * wext; - struct iw_range range; - guint32 response_len = 0; - struct iw_range_with_scan_capa *scan_capa_range; - int i; - gboolean freq_valid = FALSE, has_5ghz = FALSE, has_2ghz = FALSE; - char ifname[IFNAMSIZ]; - - if (!nmp_utils_if_indextoname(ifindex, ifname)) { - _LOGW(LOGD_PLATFORM | LOGD_WIFI, "can't determine interface name for ifindex %d", ifindex); - return NULL; - } - - wext = g_object_new(NM_TYPE_WIFI_UTILS_WEXT, NULL); - - wext->parent.ifindex = ifindex; - wext->fd = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); - if (wext->fd < 0) - goto error; - - memset(&range, 0, sizeof(struct iw_range)); - if (wext_get_range_ifname(wext, ifname, &range, &response_len) == FALSE) { - _LOGI(LOGD_PLATFORM | LOGD_WIFI, "(%s): driver WEXT range request failed", ifname); - goto error; - } - - if ((response_len < 300) || (range.we_version_compiled < 21)) { - _LOGI(LOGD_PLATFORM | LOGD_WIFI, - "(%s): driver WEXT version too old (got %d, expected >= 21)", - ifname, - range.we_version_compiled); - goto error; - } - - wext->max_qual.qual = range.max_qual.qual; - wext->max_qual.level = range.max_qual.level; - wext->max_qual.noise = range.max_qual.noise; - wext->max_qual.updated = range.max_qual.updated; - - wext->num_freqs = MIN(range.num_frequency, IW_MAX_FREQUENCIES); - for (i = 0; i < wext->num_freqs; i++) { - wext->freqs[i] = iw_freq_to_uint32(&range.freq[i]); - freq_valid = TRUE; - if (wext->freqs[i] > 2400 && wext->freqs[i] < 2500) - has_2ghz = TRUE; - else if (wext->freqs[i] > 4900 && wext->freqs[i] < 6000) - has_5ghz = TRUE; - } - - /* Check for scanning capability; cards that can't scan are not supported */ - if (check_scan && (wext_can_scan_ifname(wext, ifname) == FALSE)) { - _LOGI(LOGD_PLATFORM | LOGD_WIFI, "(%s): drivers that cannot scan are unsupported", ifname); - goto error; - } - - /* Check for the ability to scan specific SSIDs. Until the scan_capa - * field gets added to wireless-tools, need to work around that by casting - * to the custom structure. - */ - scan_capa_range = (struct iw_range_with_scan_capa *) ⦥ - if (scan_capa_range->scan_capa & NM_IW_SCAN_CAPA_ESSID) { - _LOGI(LOGD_PLATFORM | LOGD_WIFI, - "(%s): driver supports SSID scans (scan_capa 0x%02X).", - ifname, - scan_capa_range->scan_capa); - } else { - _LOGI(LOGD_PLATFORM | LOGD_WIFI, - "(%s): driver does not support SSID scans (scan_capa 0x%02X).", - ifname, - scan_capa_range->scan_capa); - } - - wext->parent.caps = wext_get_caps(wext, ifname, &range); - if (freq_valid) - wext->parent.caps |= NM_WIFI_DEVICE_CAP_FREQ_VALID; - if (has_2ghz) - wext->parent.caps |= NM_WIFI_DEVICE_CAP_FREQ_2GHZ; - if (has_5ghz) - wext->parent.caps |= NM_WIFI_DEVICE_CAP_FREQ_5GHZ; - - _LOGI(LOGD_PLATFORM | LOGD_WIFI, "(%s): using WEXT for Wi-Fi device control", ifname); - - return (NMWifiUtils *) wext; - -error: - g_object_unref(wext); - return NULL; -} - -gboolean -nm_wifi_utils_wext_is_wifi(const char *iface) -{ - int fd; - struct iwreq iwr; - gboolean is_wifi = FALSE; - - /* performing an ioctl on a non-existing name may cause the automatic - * loading of kernel modules, which should be avoided. - * - * Usually, we should thus make sure that an interface with this name - * exists. - * - * Note that wifi_wext_is_wifi() has only one caller which just verified - * that an interface with this name exists. - */ - - fd = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); - if (fd >= 0) { - nm_utils_ifname_cpy(iwr.ifr_ifrn.ifrn_name, iface); - if (ioctl(fd, SIOCGIWNAME, &iwr) == 0) - is_wifi = TRUE; - nm_close(fd); - } - return is_wifi; -} diff --git a/src/core/platform/wifi/nm-wifi-utils-wext.h b/src/core/platform/wifi/nm-wifi-utils-wext.h deleted file mode 100644 index d6f3453c..00000000 --- a/src/core/platform/wifi/nm-wifi-utils-wext.h +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2011 - 2018 Red Hat, Inc. - */ - -#ifndef __WIFI_UTILS_WEXT_H__ -#define __WIFI_UTILS_WEXT_H__ - -#include "nm-wifi-utils.h" - -#define NM_TYPE_WIFI_UTILS_WEXT (nm_wifi_utils_wext_get_type()) -#define NM_WIFI_UTILS_WEXT(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WIFI_UTILS_WEXT, NMWifiUtilsWext)) -#define NM_WIFI_UTILS_WEXT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_WIFI_UTILS_WEXT, NMWifiUtilsWextClass)) -#define NM_IS_WIFI_UTILS_WEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_WIFI_UTILS_WEXT)) -#define NM_IS_WIFI_UTILS_WEXT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_WIFI_UTILS_WEXT)) -#define NM_WIFI_UTILS_WEXT_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_WIFI_UTILS_WEXT, NMWifiUtilsWextClass)) - -GType nm_wifi_utils_wext_get_type(void); - -NMWifiUtils *nm_wifi_utils_wext_new(int ifindex, gboolean check_scan); - -gboolean nm_wifi_utils_wext_is_wifi(const char *iface); - -#endif /* __WIFI_UTILS_WEXT_H__ */ diff --git a/src/core/platform/wifi/nm-wifi-utils.c b/src/core/platform/wifi/nm-wifi-utils.c deleted file mode 100644 index 49ae1811..00000000 --- a/src/core/platform/wifi/nm-wifi-utils.c +++ /dev/null @@ -1,211 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2005 - 2018 Red Hat, Inc. - * Copyright (C) 2006 - 2008 Novell, Inc. - */ - -#include "src/core/nm-default-daemon.h" - -#include "nm-wifi-utils.h" - -#include -#include -#include - -#include "nm-wifi-utils-private.h" -#include "nm-wifi-utils-nl80211.h" -#if HAVE_WEXT - #include "nm-wifi-utils-wext.h" -#endif -#include "nm-core-utils.h" - -#include "nm-platform/nm-platform-utils.h" - -G_DEFINE_ABSTRACT_TYPE(NMWifiUtils, nm_wifi_utils, G_TYPE_OBJECT) - -/*****************************************************************************/ - -static void -nm_wifi_utils_init(NMWifiUtils *self) -{} - -static void -nm_wifi_utils_class_init(NMWifiUtilsClass *klass) -{} - -NMWifiUtils * -nm_wifi_utils_new(int ifindex, struct nl_sock *genl, gboolean check_scan) -{ - NMWifiUtils *ret; - - g_return_val_if_fail(ifindex > 0, NULL); - - ret = nm_wifi_utils_nl80211_new(ifindex, genl); - -#if HAVE_WEXT - if (ret == NULL) - ret = nm_wifi_utils_wext_new(ifindex, check_scan); -#endif - - return ret; -} - -NMDeviceWifiCapabilities -nm_wifi_utils_get_caps(NMWifiUtils *data) -{ - g_return_val_if_fail(data != NULL, NM_WIFI_DEVICE_CAP_NONE); - - return data->caps; -} - -NM80211Mode -nm_wifi_utils_get_mode(NMWifiUtils *data) -{ - g_return_val_if_fail(data != NULL, NM_802_11_MODE_UNKNOWN); - return NM_WIFI_UTILS_GET_CLASS(data)->get_mode(data); -} - -gboolean -nm_wifi_utils_set_mode(NMWifiUtils *data, const NM80211Mode mode) -{ - NMWifiUtilsClass *klass; - - g_return_val_if_fail(data != NULL, FALSE); - g_return_val_if_fail((mode == NM_802_11_MODE_INFRA) || (mode == NM_802_11_MODE_AP) - || (mode == NM_802_11_MODE_ADHOC) || (mode == NM_802_11_MODE_MESH), - FALSE); - - klass = NM_WIFI_UTILS_GET_CLASS(data); - - /* nl80211 probably doesn't need this */ - return klass->set_mode ? klass->set_mode(data, mode) : TRUE; -} - -gboolean -nm_wifi_utils_set_powersave(NMWifiUtils *data, guint32 powersave) -{ - NMWifiUtilsClass *klass; - - g_return_val_if_fail(data != NULL, FALSE); - - klass = NM_WIFI_UTILS_GET_CLASS(data); - return klass->set_powersave ? klass->set_powersave(data, powersave) : TRUE; -} - -NMSettingWirelessWakeOnWLan -nm_wifi_utils_get_wake_on_wlan(NMWifiUtils *data) -{ - NMWifiUtilsClass *klass; - - g_return_val_if_fail(data != NULL, NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE); - - klass = NM_WIFI_UTILS_GET_CLASS(data); - - return klass->get_wake_on_wlan ? klass->get_wake_on_wlan(data) - : NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE; -} - -gboolean -nm_wifi_utils_set_wake_on_wlan(NMWifiUtils *data, NMSettingWirelessWakeOnWLan wowl) -{ - NMWifiUtilsClass *klass; - - g_return_val_if_fail(data != NULL, FALSE); - - klass = NM_WIFI_UTILS_GET_CLASS(data); - return klass->set_wake_on_wlan ? klass->set_wake_on_wlan(data, wowl) : FALSE; -} - -guint32 -nm_wifi_utils_get_freq(NMWifiUtils *data) -{ - g_return_val_if_fail(data != NULL, 0); - return NM_WIFI_UTILS_GET_CLASS(data)->get_freq(data); -} - -guint32 -nm_wifi_utils_find_freq(NMWifiUtils *data, const guint32 *freqs) -{ - g_return_val_if_fail(data != NULL, 0); - g_return_val_if_fail(freqs != NULL, 0); - return NM_WIFI_UTILS_GET_CLASS(data)->find_freq(data, freqs); -} - -gboolean -nm_wifi_utils_get_station(NMWifiUtils *data, - NMEtherAddr *out_bssid, - int * out_quality, - guint32 * out_rate) -{ - g_return_val_if_fail(data != NULL, FALSE); - - return NM_WIFI_UTILS_GET_CLASS(data)->get_station(data, out_bssid, out_quality, out_rate); -} - -gboolean -nm_wifi_utils_is_wifi(int dirfd, const char *ifname) -{ - g_return_val_if_fail(dirfd >= 0, FALSE); - - if (faccessat(dirfd, "phy80211", F_OK, 0) == 0) - return TRUE; -#if HAVE_WEXT - if (nm_wifi_utils_wext_is_wifi(ifname)) - return TRUE; -#endif - return FALSE; -} - -/* OLPC Mesh-only functions */ - -guint32 -nm_wifi_utils_get_mesh_channel(NMWifiUtils *data) -{ - NMWifiUtilsClass *klass; - - g_return_val_if_fail(data != NULL, FALSE); - - klass = NM_WIFI_UTILS_GET_CLASS(data); - g_return_val_if_fail(klass->get_mesh_channel != NULL, FALSE); - - return klass->get_mesh_channel(data); -} - -gboolean -nm_wifi_utils_set_mesh_channel(NMWifiUtils *data, guint32 channel) -{ - NMWifiUtilsClass *klass; - - g_return_val_if_fail(data != NULL, FALSE); - g_return_val_if_fail(channel <= 13, FALSE); - - klass = NM_WIFI_UTILS_GET_CLASS(data); - g_return_val_if_fail(klass->set_mesh_channel != NULL, FALSE); - - return klass->set_mesh_channel(data, channel); -} - -gboolean -nm_wifi_utils_set_mesh_ssid(NMWifiUtils *data, const guint8 *ssid, gsize len) -{ - NMWifiUtilsClass *klass; - - g_return_val_if_fail(data != NULL, FALSE); - - klass = NM_WIFI_UTILS_GET_CLASS(data); - g_return_val_if_fail(klass->set_mesh_ssid != NULL, FALSE); - - return klass->set_mesh_ssid(data, ssid, len); -} - -gboolean -nm_wifi_utils_indicate_addressing_running(NMWifiUtils *data, gboolean running) -{ - NMWifiUtilsClass *klass; - - g_return_val_if_fail(data != NULL, FALSE); - - klass = NM_WIFI_UTILS_GET_CLASS(data); - return klass->indicate_addressing_running ? klass->indicate_addressing_running(data, running) - : FALSE; -} diff --git a/src/core/platform/wifi/nm-wifi-utils.h b/src/core/platform/wifi/nm-wifi-utils.h deleted file mode 100644 index a252e43e..00000000 --- a/src/core/platform/wifi/nm-wifi-utils.h +++ /dev/null @@ -1,74 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2005 - 2018 Red Hat, Inc. - * Copyright (C) 2006 - 2008 Novell, Inc. - */ - -#ifndef __WIFI_UTILS_H__ -#define __WIFI_UTILS_H__ - -#include - -#include "nm-dbus-interface.h" -#include "nm-setting-wireless.h" -#include "nm-platform/nm-netlink.h" - -typedef struct NMWifiUtils NMWifiUtils; - -#define NM_TYPE_WIFI_UTILS (nm_wifi_utils_get_type()) -#define NM_WIFI_UTILS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WIFI_UTILS, NMWifiUtils)) -#define NM_WIFI_UTILS_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_WIFI_UTILS, NMWifiUtilsClass)) -#define NM_IS_WIFI_UTILS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_WIFI_UTILS)) -#define NM_IS_WIFI_UTILS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_WIFI_UTILS)) -#define NM_WIFI_UTILS_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_WIFI_UTILS, NMWifiUtilsClass)) - -GType nm_wifi_utils_get_type(void); - -gboolean nm_wifi_utils_is_wifi(int dirfd, const char *ifname); - -NMWifiUtils *nm_wifi_utils_new(int ifindex, struct nl_sock *genl, gboolean check_scan); - -NMDeviceWifiCapabilities nm_wifi_utils_get_caps(NMWifiUtils *data); - -NM80211Mode nm_wifi_utils_get_mode(NMWifiUtils *data); - -gboolean nm_wifi_utils_set_mode(NMWifiUtils *data, const NM80211Mode mode); - -/* Returns frequency in MHz */ -guint32 nm_wifi_utils_get_freq(NMWifiUtils *data); - -/* Return the first supported frequency in the zero-terminated list. - * Frequencies are specified in MHz. */ -guint32 nm_wifi_utils_find_freq(NMWifiUtils *data, const guint32 *freqs); - -/* - * @out_bssid: must be NULL or an ETH_ALEN-byte buffer - * @out_quality: receives signal quality in 0 - 100% range if not NULL - * @out_rate: receives current bitrate in Kbps if not NULL - * - * Returns %TRUE on succcess. - */ -gboolean nm_wifi_utils_get_station(NMWifiUtils *data, - NMEtherAddr *out_bssid, - int * out_quality, - guint32 * out_rate); - -/* Tells the driver DHCP or SLAAC is running */ -gboolean nm_wifi_utils_indicate_addressing_running(NMWifiUtils *data, gboolean running); - -gboolean nm_wifi_utils_set_powersave(NMWifiUtils *data, guint32 powersave); - -NMSettingWirelessWakeOnWLan nm_wifi_utils_get_wake_on_wlan(NMWifiUtils *data); - -gboolean nm_wifi_utils_set_wake_on_wlan(NMWifiUtils *data, NMSettingWirelessWakeOnWLan wowl); - -/* OLPC Mesh-only functions */ -guint32 nm_wifi_utils_get_mesh_channel(NMWifiUtils *data); - -gboolean nm_wifi_utils_set_mesh_channel(NMWifiUtils *data, guint32 channel); - -gboolean nm_wifi_utils_set_mesh_ssid(NMWifiUtils *data, const guint8 *ssid, gsize len); - -#endif /* __WIFI_UTILS_H__ */ diff --git a/src/core/platform/wpan/nm-wpan-utils.c b/src/core/platform/wpan/nm-wpan-utils.c deleted file mode 100644 index efb19979..00000000 --- a/src/core/platform/wpan/nm-wpan-utils.c +++ /dev/null @@ -1,286 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2018 Red Hat, Inc. - */ - -#include "src/core/nm-default-daemon.h" - -#include "nm-wpan-utils.h" - -#include - -#include "nm-platform/nm-netlink.h" -#include "platform/linux/nl802154.h" -#include "nm-platform/nm-platform-utils.h" - -#define _NMLOG_PREFIX_NAME "wpan-nl802154" -#define _NMLOG(level, domain, ...) \ - G_STMT_START \ - { \ - char _ifname_buf[IFNAMSIZ]; \ - const char *_ifname = self ? nmp_utils_if_indextoname(self->ifindex, _ifname_buf) : NULL; \ - \ - nm_log((level), \ - (domain), \ - _ifname ?: NULL, \ - NULL, \ - "%s%s%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - _NMLOG_PREFIX_NAME, \ - NM_PRINT_FMT_QUOTED(_ifname, " (", _ifname, ")", "") \ - _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - G_STMT_END - -/*****************************************************************************/ - -struct NMWpanUtils { - GObject parent; - int ifindex; - struct nl_sock *nl_sock; - int id; -}; - -typedef struct { - GObjectClass parent; -} NMWpanUtilsClass; - -G_DEFINE_TYPE(NMWpanUtils, nm_wpan_utils, G_TYPE_OBJECT) - -/*****************************************************************************/ - -static int -ack_handler(struct nl_msg *msg, void *arg) -{ - int *done = arg; - *done = 1; - return NL_STOP; -} - -static int -finish_handler(struct nl_msg *msg, void *arg) -{ - int *done = arg; - *done = 1; - return NL_SKIP; -} - -static int -error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg) -{ - int *done = arg; - *done = err->error; - return NL_SKIP; -} - -static struct nl_msg * -_nl802154_alloc_msg(int id, int ifindex, guint32 cmd, guint32 flags) -{ - nm_auto_nlmsg struct nl_msg *msg = NULL; - - msg = nlmsg_alloc(); - genlmsg_put(msg, 0, 0, id, 0, flags, cmd, 0); - NLA_PUT_U32(msg, NL802154_ATTR_IFINDEX, ifindex); - return g_steal_pointer(&msg); - -nla_put_failure: - g_return_val_if_reached(NULL); -} - -static struct nl_msg * -nl802154_alloc_msg(NMWpanUtils *self, guint32 cmd, guint32 flags) -{ - return _nl802154_alloc_msg(self->id, self->ifindex, cmd, flags); -} - -static int -nl802154_send_and_recv(NMWpanUtils * self, - struct nl_msg *msg, - int (*valid_handler)(struct nl_msg *, void *), - void *valid_data) -{ - int err; - int done = 0; - const struct nl_cb cb = { - .err_cb = error_handler, - .err_arg = &done, - .finish_cb = finish_handler, - .finish_arg = &done, - .ack_cb = ack_handler, - .ack_arg = &done, - .valid_cb = valid_handler, - .valid_arg = valid_data, - }; - - g_return_val_if_fail(msg != NULL, -ENOMEM); - - err = nl_send_auto(self->nl_sock, msg); - if (err < 0) - return err; - - /* Loop until one of our NL callbacks says we're done; on success - * done will be 1, on error it will be < 0. - */ - while (!done) { - err = nl_recvmsgs(self->nl_sock, &cb); - if (err < 0 && err != -EAGAIN) { - _LOGW(LOGD_PLATFORM, "nl_recvmsgs() error: (%d) %s", err, nm_strerror(err)); - break; - } - } - - if (err >= 0 && done < 0) - err = done; - return err; -} - -struct nl802154_interface { - guint16 pan_id; - guint16 short_addr; - - gboolean valid; -}; - -static int -nl802154_get_interface_handler(struct nl_msg *msg, void *arg) -{ - static const struct nla_policy nl802154_policy[] = { - [NL802154_ATTR_PAN_ID] = {.type = NLA_U16}, - [NL802154_ATTR_SHORT_ADDR] = {.type = NLA_U16}, - }; - struct nlattr * tb[G_N_ELEMENTS(nl802154_policy)]; - struct nl802154_interface *info = arg; - struct genlmsghdr * gnlh = nlmsg_data(nlmsg_hdr(msg)); - - if (nla_parse_arr(tb, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), nl802154_policy) < 0) - return NL_SKIP; - - if (tb[NL802154_ATTR_PAN_ID]) - info->pan_id = le16toh(nla_get_u16(tb[NL802154_ATTR_PAN_ID])); - - if (tb[NL802154_ATTR_SHORT_ADDR]) - info->short_addr = le16toh(nla_get_u16(tb[NL802154_ATTR_SHORT_ADDR])); - - info->valid = TRUE; - - return NL_SKIP; -} - -static void -nl802154_get_interface(NMWpanUtils *self, struct nl802154_interface *interface) -{ - nm_auto_nlmsg struct nl_msg *msg = NULL; - - memset(interface, 0, sizeof(*interface)); - - msg = nl802154_alloc_msg(self, NL802154_CMD_GET_INTERFACE, 0); - - nl802154_send_and_recv(self, msg, nl802154_get_interface_handler, interface); -} - -/*****************************************************************************/ - -guint16 -nm_wpan_utils_get_pan_id(NMWpanUtils *self) -{ - struct nl802154_interface interface; - - nl802154_get_interface(self, &interface); - - return interface.pan_id; -} - -gboolean -nm_wpan_utils_set_pan_id(NMWpanUtils *self, guint16 pan_id) -{ - nm_auto_nlmsg struct nl_msg *msg = NULL; - int err; - - g_return_val_if_fail(self != NULL, FALSE); - - msg = nl802154_alloc_msg(self, NL802154_CMD_SET_PAN_ID, 0); - NLA_PUT_U16(msg, NL802154_ATTR_PAN_ID, htole16(pan_id)); - err = nl802154_send_and_recv(self, msg, NULL, NULL); - return err >= 0; - -nla_put_failure: - g_return_val_if_reached(FALSE); -} - -guint16 -nm_wpan_utils_get_short_addr(NMWpanUtils *self) -{ - struct nl802154_interface interface; - - nl802154_get_interface(self, &interface); - - return interface.short_addr; -} - -gboolean -nm_wpan_utils_set_short_addr(NMWpanUtils *self, guint16 short_addr) -{ - nm_auto_nlmsg struct nl_msg *msg = NULL; - int err; - - g_return_val_if_fail(self != NULL, FALSE); - - msg = nl802154_alloc_msg(self, NL802154_CMD_SET_SHORT_ADDR, 0); - NLA_PUT_U16(msg, NL802154_ATTR_SHORT_ADDR, htole16(short_addr)); - err = nl802154_send_and_recv(self, msg, NULL, NULL); - return err >= 0; - -nla_put_failure: - g_return_val_if_reached(FALSE); -} - -gboolean -nm_wpan_utils_set_channel(NMWpanUtils *self, guint8 page, guint8 channel) -{ - nm_auto_nlmsg struct nl_msg *msg = NULL; - int err; - - g_return_val_if_fail(self != NULL, FALSE); - - msg = nl802154_alloc_msg(self, NL802154_CMD_SET_CHANNEL, 0); - NLA_PUT_U8(msg, NL802154_ATTR_PAGE, page); - NLA_PUT_U8(msg, NL802154_ATTR_CHANNEL, channel); - err = nl802154_send_and_recv(self, msg, NULL, NULL); - return err >= 0; - -nla_put_failure: - g_return_val_if_reached(FALSE); -} - -/*****************************************************************************/ - -static void -nm_wpan_utils_init(NMWpanUtils *self) -{} - -static void -nm_wpan_utils_class_init(NMWpanUtilsClass *klass) -{} - -NMWpanUtils * -nm_wpan_utils_new(int ifindex, struct nl_sock *genl, gboolean check_scan) -{ - NMWpanUtils *self; - - g_return_val_if_fail(ifindex > 0, NULL); - - if (!genl) - return NULL; - - self = g_object_new(NM_TYPE_WPAN_UTILS, NULL); - self->ifindex = ifindex; - self->nl_sock = genl; - self->id = genl_ctrl_resolve(genl, "nl802154"); - - if (self->id < 0) { - _LOGD(LOGD_PLATFORM, "genl_ctrl_resolve: failed to resolve \"nl802154\""); - g_object_unref(self); - return NULL; - } - - return self; -} diff --git a/src/core/platform/wpan/nm-wpan-utils.h b/src/core/platform/wpan/nm-wpan-utils.h deleted file mode 100644 index 940c2c9d..00000000 --- a/src/core/platform/wpan/nm-wpan-utils.h +++ /dev/null @@ -1,37 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2018 Red Hat, Inc. - */ - -#ifndef __WPAN_UTILS_H__ -#define __WPAN_UTILS_H__ - -#include - -#include "nm-dbus-interface.h" -#include "nm-platform/nm-netlink.h" - -typedef struct NMWpanUtils NMWpanUtils; - -#define NM_TYPE_WPAN_UTILS (nm_wpan_utils_get_type()) -#define NM_WPAN_UTILS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WPAN_UTILS, NMWpanUtils)) -#define NM_WPAN_UTILS_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_WPAN_UTILS, NMWpanUtilsClass)) -#define NM_IS_WPAN_UTILS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_WPAN_UTILS)) -#define NM_IS_WPAN_UTILS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_WPAN_UTILS)) -#define NM_WPAN_UTILS_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_WPAN_UTILS, NMWpanUtilsClass)) - -GType nm_wpan_utils_get_type(void); - -NMWpanUtils *nm_wpan_utils_new(int ifindex, struct nl_sock *genl, gboolean check_scan); - -guint16 nm_wpan_utils_get_pan_id(NMWpanUtils *self); -gboolean nm_wpan_utils_set_pan_id(NMWpanUtils *self, guint16 pan_id); - -guint16 nm_wpan_utils_get_short_addr(NMWpanUtils *self); -gboolean nm_wpan_utils_set_short_addr(NMWpanUtils *self, guint16 short_addr); - -gboolean nm_wpan_utils_set_channel(NMWpanUtils *self, guint8 page, guint8 channel); - -#endif /* __WPAN_UTILS_H__ */ diff --git a/src/core/ppp/meson.build b/src/core/ppp/meson.build index 607b4718..ffeb0eba 100644 --- a/src/core/ppp/meson.build +++ b/src/core/ppp/meson.build @@ -4,9 +4,19 @@ nm_pppd_plugin = shared_module( 'nm-pppd-plugin', name_prefix: '', sources: 'nm-pppd-plugin.c', - dependencies: libnm_core_nm_default_dep, - c_args: [ - '-DG_LOG_DOMAIN="nm-pppd-plugin"', + include_directories: [ + src_inc, + top_inc, + ], + dependencies: [ + libnm_core_public_dep, + glib_dep, + ], + link_with: [ + libnm_core_impl, + libnm_glib_aux, + libnm_std_aux, + libc_siphash, ], install: true, install_dir: pppd_plugin_dir, @@ -20,7 +30,6 @@ core_plugins += shared_module( 'nm-ppp-manager.c', ], dependencies: core_plugin_dep, - c_args: daemon_c_flags, link_args: '-Wl,--version-script,@0@'.format(linker_script), link_depends: linker_script, install: true, diff --git a/src/core/ppp/nm-ppp-manager-call.c b/src/core/ppp/nm-ppp-manager-call.c index f791e8b0..5e84f596 100644 --- a/src/core/ppp/nm-ppp-manager-call.c +++ b/src/core/ppp/nm-ppp-manager-call.c @@ -18,17 +18,21 @@ /*****************************************************************************/ -static NMPPPOps *ppp_ops = NULL; +static const NMPPPOps *_ppp_ops = NULL; + +#define ppp_ops_get() ((const NMPPPOps *) g_atomic_pointer_get(&_ppp_ops)) NMPPPManager * nm_ppp_manager_create(const char *iface, GError **error) { - NMPPPManager *ret; - GModule * plugin; - GError * error_local = NULL; - NMPPPOps * ops; - struct stat st; - + NMPPPManager * ret; + GModule * plugin; + GError * error_local = NULL; + struct stat st; + const NMPPPOps *ppp_ops; + +again: + ppp_ops = ppp_ops_get(); if (G_UNLIKELY(!ppp_ops)) { if (stat(PPP_PLUGIN_PATH, &st) != 0) { g_set_error_literal(error, @@ -58,7 +62,7 @@ nm_ppp_manager_create(const char *iface, GError **error) return NULL; } - if (!g_module_symbol(plugin, "ppp_ops", (gpointer) &ops)) { + if (!g_module_symbol(plugin, "ppp_ops", (gpointer *) &ppp_ops)) { g_set_error(error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_MISSING_PLUGIN, @@ -67,18 +71,21 @@ nm_ppp_manager_create(const char *iface, GError **error) return NULL; } + nm_assert(ppp_ops); + nm_assert(ppp_ops->create); + nm_assert(ppp_ops->start); + nm_assert(ppp_ops->stop); + nm_assert(ppp_ops->stop_cancel); + + if (!g_atomic_pointer_compare_and_exchange(&_ppp_ops, NULL, ppp_ops)) { + g_module_close(plugin); + goto again; + } + /* after loading glib types from the plugin, we cannot unload the library anymore. * Make it resident. */ g_module_make_resident(plugin); - nm_assert(ops); - nm_assert(ops->create); - nm_assert(ops->start); - nm_assert(ops->stop); - nm_assert(ops->stop_cancel); - - ppp_ops = ops; - nm_log_info(LOGD_CORE | LOGD_PPP, "loaded PPP plugin " PPP_PLUGIN_PATH); } @@ -94,6 +101,8 @@ nm_ppp_manager_set_route_parameters(NMPPPManager *self, guint32 ip6_route_table, guint32 ip6_route_metric) { + const NMPPPOps *ppp_ops = ppp_ops_get(); + g_return_if_fail(ppp_ops); ppp_ops->set_route_parameters(self, @@ -111,6 +120,8 @@ nm_ppp_manager_start(NMPPPManager *self, guint baud_override, GError ** err) { + const NMPPPOps *ppp_ops = ppp_ops_get(); + g_return_val_if_fail(ppp_ops, FALSE); return ppp_ops->start(self, req, ppp_name, timeout_secs, baud_override, err); @@ -122,6 +133,8 @@ nm_ppp_manager_stop(NMPPPManager * self, NMPPPManagerStopCallback callback, gpointer user_data) { + const NMPPPOps *ppp_ops = ppp_ops_get(); + g_return_val_if_fail(ppp_ops, NULL); return ppp_ops->stop(self, cancellable, callback, user_data); @@ -130,6 +143,8 @@ nm_ppp_manager_stop(NMPPPManager * self, void nm_ppp_manager_stop_cancel(NMPPPManagerStopHandle *handle) { + const NMPPPOps *ppp_ops = ppp_ops_get(); + g_return_if_fail(ppp_ops); g_return_if_fail(handle); diff --git a/src/core/ppp/nm-ppp-manager.c b/src/core/ppp/nm-ppp-manager.c index 396a49ae..fefc5d61 100644 --- a/src/core/ppp/nm-ppp-manager.c +++ b/src/core/ppp/nm-ppp-manager.c @@ -28,8 +28,9 @@ #include #include "NetworkManagerUtils.h" -#include "platform/nm-platform.h" -#include "nm-core-internal.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-platform/nm-platform-utils.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-act-request.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" @@ -998,7 +999,7 @@ _ppp_manager_start(NMPPPManager *self, /* Make sure /dev/ppp exists (bgo #533064) */ if (stat("/dev/ppp", &st) || !S_ISCHR(st.st_mode)) - nm_utils_modprobe(NULL, FALSE, "ppp_generic", NULL); + nmp_utils_modprobe(NULL, FALSE, "ppp_generic", NULL); connection = nm_act_request_get_applied_connection(req); g_return_val_if_fail(connection, FALSE); @@ -1445,11 +1446,11 @@ nm_ppp_manager_class_init(NMPPPManagerClass *manager_class) NULL, G_TYPE_NONE, 2, - G_TYPE_UINT /*guint32 in_bytes*/, - G_TYPE_UINT /*guint32 out_bytes*/); + G_TYPE_UINT, /* guint32 in_bytes */ + G_TYPE_UINT); /* guint32 out_bytes */ } -NMPPPOps ppp_ops = { +const NMPPPOps ppp_ops = { .create = _ppp_manager_new, .set_route_parameters = _ppp_manager_set_route_parameters, .start = _ppp_manager_start, diff --git a/src/core/ppp/nm-pppd-plugin.c b/src/core/ppp/nm-pppd-plugin.c index c9016dac..5ffa7d17 100644 --- a/src/core/ppp/nm-pppd-plugin.c +++ b/src/core/ppp/nm-pppd-plugin.c @@ -20,7 +20,7 @@ #include #include -#include "nm-glib-aux/nm-default-glib.h" +#include "libnm-glib-aux/nm-default-glib.h" #include "nm-dbus-interface.h" @@ -226,11 +226,10 @@ nm_ip_up(void *data, int arg) if (opts.dnsaddr[1]) dns[len++] = opts.dnsaddr[1]; - g_variant_builder_add( - &builder, - "{sv}", - NM_PPP_IP4_CONFIG_DNS, - g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, dns, len, sizeof(guint32))); + g_variant_builder_add(&builder, + "{sv}", + NM_PPP_IP4_CONFIG_DNS, + nm_g_variant_new_au(dns, len)); } if (opts.winsaddr[0] || opts.winsaddr[1]) { @@ -242,11 +241,10 @@ nm_ip_up(void *data, int arg) if (opts.winsaddr[1]) wins[len++] = opts.winsaddr[1]; - g_variant_builder_add( - &builder, - "{sv}", - NM_PPP_IP4_CONFIG_WINS, - g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, wins, len, sizeof(guint32))); + g_variant_builder_add(&builder, + "{sv}", + NM_PPP_IP4_CONFIG_WINS, + nm_g_variant_new_au(wins, len)); } g_message("nm-ppp-plugin: sending IPv4 config to NetworkManager..."); diff --git a/src/core/settings/nm-agent-manager.c b/src/core/settings/nm-agent-manager.c index 7e617909..a1c2eb9c 100644 --- a/src/core/settings/nm-agent-manager.c +++ b/src/core/settings/nm-agent-manager.c @@ -9,7 +9,7 @@ #include -#include "nm-libnm-core-intern/nm-common-macros.h" +#include "libnm-core-aux-intern/nm-common-macros.h" #include "nm-dbus-interface.h" #include "nm-secret-agent.h" #include "nm-auth-utils.h" @@ -19,7 +19,7 @@ #include "nm-session-monitor.h" #include "nm-simple-connection.h" #include "NetworkManagerUtils.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "c-list/src/c-list.h" /*****************************************************************************/ diff --git a/src/core/settings/nm-secret-agent.c b/src/core/settings/nm-secret-agent.c index 7e7c5d7d..45152c27 100644 --- a/src/core/settings/nm-secret-agent.c +++ b/src/core/settings/nm-secret-agent.c @@ -10,11 +10,11 @@ #include #include -#include "nm-glib-aux/nm-c-list.h" -#include "nm-glib-aux/nm-dbus-aux.h" +#include "libnm-glib-aux/nm-c-list.h" +#include "libnm-glib-aux/nm-dbus-aux.h" #include "nm-dbus-interface.h" -#include "nm-core-internal.h" -#include "nm-libnm-core-intern/nm-auth-subject.h" +#include "libnm-core-intern/nm-core-internal.h" +#include "libnm-core-aux-intern/nm-auth-subject.h" #include "nm-simple-connection.h" #include "NetworkManagerUtils.h" #include "c-list/src/c-list.h" @@ -583,7 +583,7 @@ nm_secret_agent_delete_secrets(NMSecretAgent * self, priv = NM_SECRET_AGENT_GET_PRIVATE(self); /* No secrets sent; agents must be smart enough to track secrets using the UUID or something */ - dict = nm_connection_to_dbus(connection, NM_CONNECTION_SERIALIZE_NO_SECRETS); + dict = nm_connection_to_dbus(connection, NM_CONNECTION_SERIALIZE_WITH_NON_SECRET); call_id = _call_id_new(self, METHOD_DELETE_SECRETS, path, NULL, callback, callback_data); diff --git a/src/core/settings/nm-settings-connection.c b/src/core/settings/nm-settings-connection.c index 0ff07189..641f3297 100644 --- a/src/core/settings/nm-settings-connection.c +++ b/src/core/settings/nm-settings-connection.c @@ -10,8 +10,8 @@ #include "c-list/src/c-list.h" -#include "nm-glib-aux/nm-keyfile-aux.h" -#include "nm-libnm-core-intern/nm-common-macros.h" +#include "libnm-glib-aux/nm-keyfile-aux.h" +#include "libnm-core-aux-intern/nm-common-macros.h" #include "nm-config.h" #include "nm-config-data.h" #include "nm-dbus-interface.h" @@ -20,7 +20,7 @@ #include "nm-auth-utils.h" #include "nm-agent-manager.h" #include "NetworkManagerUtils.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-audit-manager.h" #include "nm-settings.h" #include "nm-dbus-manager.h" @@ -30,10 +30,11 @@ #define AUTOCONNECT_RETRIES_FOREVER -1 #define AUTOCONNECT_RESET_RETRIES_TIMER 300 -#define _NM_SETTINGS_UPDATE2_FLAG_ALL_PERSIST_MODES \ - ((NMSettingsUpdate2Flags)( \ - NM_SETTINGS_UPDATE2_FLAG_TO_DISK | NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY \ - | NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED | NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY)) +#define _NM_SETTINGS_UPDATE2_FLAG_ALL_PERSIST_MODES \ + ((NMSettingsUpdate2Flags) (NM_SETTINGS_UPDATE2_FLAG_TO_DISK \ + | NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY \ + | NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED \ + | NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY)) /*****************************************************************************/ @@ -79,19 +80,17 @@ typedef struct _NMSettingsConnectionPrivate { NMConnection *connection; + struct { + NMConnectionSerializationOptions options; + GVariant * variant; + } getsettings_cached; + NMSettingsStorage *storage; char *filename; NMDevice *default_wired_device; - /* Caches secrets from on-disk connections; were they not cached any - * call to nm_connection_clear_secrets() wipes them out and we'd have - * to re-read them from disk which defeats the purpose of having the - * connection in-memory at all. - */ - GVariant *system_secrets; - /* Caches secrets from agents during the activation process; if new system * secrets are returned from an agent, they get written out to disk, * triggering a re-read of the connection, which reads only system @@ -168,7 +167,6 @@ static const GDBusSignalInfo signal_info_updated; static const GDBusSignalInfo signal_info_removed; static const NMDBusInterfaceInfoExtended interface_info_settings_connection; -static void update_system_secrets_cache(NMSettingsConnection *self, NMConnection *new); static void update_agent_secrets_cache(NMSettingsConnection *self, NMConnection *new); /*****************************************************************************/ @@ -256,6 +254,57 @@ _seen_bssids_hash_new(void) /*****************************************************************************/ +static void +_getsettings_cached_clear(NMSettingsConnectionPrivate *priv) +{ + if (nm_clear_pointer(&priv->getsettings_cached.variant, g_variant_unref)) { + priv->getsettings_cached.options.timestamp.has = FALSE; + priv->getsettings_cached.options.timestamp.val = 0; + nm_clear_g_free((gpointer *) &priv->getsettings_cached.options.seen_bssids); + } +} + +static GVariant * +_getsettings_cached_get(NMSettingsConnection *self, const NMConnectionSerializationOptions *options) +{ + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE(self); + GVariant * variant; + + if (priv->getsettings_cached.variant) { + if (nm_connection_serialization_options_equal(&priv->getsettings_cached.options, options)) { +#if NM_MORE_ASSERTS > 10 + gs_unref_variant GVariant *variant2 = NULL; + + variant = nm_connection_to_dbus_full(priv->connection, + NM_CONNECTION_SERIALIZE_WITH_NON_SECRET, + options); + nm_assert(variant); + variant2 = g_variant_new("(@a{sa{sv}})", variant); + nm_assert(g_variant_equal(priv->getsettings_cached.variant, variant2)); +#endif + return priv->getsettings_cached.variant; + } + _getsettings_cached_clear(priv); + } + + nm_assert(!priv->getsettings_cached.options.seen_bssids); + + variant = nm_connection_to_dbus_full(priv->connection, + NM_CONNECTION_SERIALIZE_WITH_NON_SECRET, + options); + nm_assert(variant); + + priv->getsettings_cached.variant = g_variant_ref_sink(g_variant_new("(@a{sa{sv}})", variant)); + + priv->getsettings_cached.options = *options; + priv->getsettings_cached.options.seen_bssids = + nm_utils_strv_dup_packed(priv->getsettings_cached.options.seen_bssids, -1); + + return priv->getsettings_cached.variant; +} + +/*****************************************************************************/ + NMConnection * nm_settings_connection_get_connection(NMSettingsConnection *self) { @@ -287,6 +336,9 @@ _nm_settings_connection_set_connection(NMSettingsConnection * self, priv->connection = g_object_ref(new_connection); nmtst_connection_assert_unchanging(priv->connection); + _getsettings_cached_clear(priv); + _nm_settings_notify_sorted_by_autoconnect_priority_maybe_changed(priv->settings); + /* note that we only return @connection_old if the new connection actually differs from * before. * @@ -298,11 +350,6 @@ _nm_settings_connection_set_connection(NMSettingsConnection * self, NM_SET_OUT(out_connection_old, g_steal_pointer(&connection_old)); } - if (NM_FLAGS_HAS(update_reason, NM_SETTINGS_CONNECTION_UPDATE_REASON_CLEAR_SYSTEM_SECRETS)) - update_system_secrets_cache(self, NULL); - else if (NM_FLAGS_HAS(update_reason, NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_SYSTEM_SECRETS)) - update_system_secrets_cache(self, priv->connection); - if (NM_FLAGS_HAS(update_reason, NM_SETTINGS_CONNECTION_UPDATE_REASON_CLEAR_AGENT_SECRETS)) update_agent_secrets_cache(self, NULL); else if (NM_FLAGS_HAS(update_reason, NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_AGENT_SECRETS)) @@ -433,64 +480,21 @@ nm_settings_connection_check_permission(NMSettingsConnection *self, const char * /*****************************************************************************/ -static void -update_system_secrets_cache(NMSettingsConnection *self, NMConnection *new) -{ - NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE(self); - gs_unref_object NMConnection *connection_cloned = NULL; - gs_unref_variant GVariant *old_secrets = NULL; - - old_secrets = g_steal_pointer(&priv->system_secrets); - - if (!new) - goto out; - - /* FIXME: improve NMConnection API so we can avoid the overhead of cloning the connection, - * in particular if there are no secrets to begin with. */ - - connection_cloned = nm_simple_connection_new_clone(new); - - /* Clear out non-system-owned and not-saved secrets */ - _nm_connection_clear_secrets_by_secret_flags(connection_cloned, NM_SETTING_SECRET_FLAG_NONE); - - priv->system_secrets = nm_g_variant_ref_sink( - nm_connection_to_dbus(connection_cloned, NM_CONNECTION_SERIALIZE_ONLY_SECRETS)); - -out: - if (_LOGT_ENABLED()) { - if ((!!old_secrets) != (!!priv->system_secrets)) { - _LOGT("update system secrets: secrets %s", old_secrets ? "cleared" : "set"); - } else if (priv->system_secrets && !g_variant_equal(old_secrets, priv->system_secrets)) - _LOGT("update system secrets: secrets updated"); - } -} - static void update_agent_secrets_cache(NMSettingsConnection *self, NMConnection *new) { - NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE(self); - gs_unref_object NMConnection *connection_cloned = NULL; - gs_unref_variant GVariant *old_secrets = NULL; + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE(self); + gs_unref_variant GVariant *old_secrets = NULL; old_secrets = g_steal_pointer(&priv->agent_secrets); - if (!new) - goto out; - - /* FIXME: improve NMConnection API so we can avoid the overhead of cloning the connection, - * in particular if there are no secrets to begin with. */ - - connection_cloned = nm_simple_connection_new_clone(new); - - /* Clear out non-system-owned secrets */ - _nm_connection_clear_secrets_by_secret_flags(connection_cloned, - NM_SETTING_SECRET_FLAG_NOT_SAVED - | NM_SETTING_SECRET_FLAG_AGENT_OWNED); - - priv->agent_secrets = nm_g_variant_ref_sink( - nm_connection_to_dbus(connection_cloned, NM_CONNECTION_SERIALIZE_ONLY_SECRETS)); + if (new) { + priv->agent_secrets = nm_g_variant_ref_sink( + nm_connection_to_dbus(new, + NM_CONNECTION_SERIALIZE_WITH_SECRETS_AGENT_OWNED + | NM_CONNECTION_SERIALIZE_WITH_SECRETS_NOT_SAVED)); + } -out: if (_LOGT_ENABLED()) { if ((!!old_secrets) != (!!priv->agent_secrets)) { _LOGT("update agent secrets: secrets %s", old_secrets ? "cleared" : "set"); @@ -499,39 +503,6 @@ out: } } -void -nm_settings_connection_clear_secrets(NMSettingsConnection *self, - gboolean clear_cached_system_secrets, - gboolean persist) -{ - gs_unref_object NMConnection *connection_cloned = NULL; - - if (!nm_settings_connection_still_valid(self)) - return; - - /* FIXME: add API to NMConnection so that we can clone a profile without secrets. */ - - connection_cloned = nm_simple_connection_new_clone(nm_settings_connection_get_connection(self)); - - nm_connection_clear_secrets(connection_cloned); - - if (!nm_settings_connection_update( - self, - connection_cloned, - persist ? NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP - : NM_SETTINGS_CONNECTION_PERSIST_MODE_NO_PERSIST, - NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, - NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, - NM_SETTINGS_CONNECTION_UPDATE_REASON_IGNORE_PERSIST_FAILURE - | (clear_cached_system_secrets - ? NM_SETTINGS_CONNECTION_UPDATE_REASON_CLEAR_SYSTEM_SECRETS - : NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE) - | NM_SETTINGS_CONNECTION_UPDATE_REASON_CLEAR_AGENT_SECRETS, - "clear-secrets", - NULL)) - nm_assert_not_reached(); -} - static gboolean _secrets_update(NMConnection * connection, const char * setting_name, @@ -829,6 +800,18 @@ nm_settings_connection_new_secrets(NMSettingsConnection *self, return TRUE; } +static gboolean +match_secret_by_setting_name_and_flags_cb(NMSetting * setting, + const char * secret, + NMSettingSecretFlags flags, + gpointer user_data) +{ + const char *get_secrets_setting_name = user_data; + + return nm_streq(nm_setting_get_name(setting), get_secrets_setting_name) + && NM_FLAGS_HAS(flags, NM_SETTING_SECRET_FLAG_AGENT_OWNED); +} + static void get_secrets_done_cb(NMAgentManager * manager, NMAgentManagerCallId call_id_a, @@ -846,7 +829,6 @@ get_secrets_done_cb(NMAgentManager * manager, NMSettingsConnectionPrivate *priv; NMConnection * applied_connection; gs_free_error GError *local = NULL; - gs_unref_variant GVariant *system_secrets = NULL; gs_unref_object NMConnection *new_connection = NULL; gboolean agent_had_system = FALSE; ForEachSecretFlags cmp_flags = {NM_SETTING_SECRET_FLAG_NONE, NM_SETTING_SECRET_FLAG_NONE}; @@ -917,18 +899,12 @@ get_secrets_done_cb(NMAgentManager * manager, _LOGD("(%s:%p) secrets request completed", setting_name, call_id); - system_secrets = nm_g_variant_ref(priv->system_secrets); - new_connection = nm_simple_connection_new_clone(nm_settings_connection_get_connection(self)); - nm_connection_clear_secrets(new_connection); - - if (!_secrets_update(new_connection, setting_name, system_secrets, NULL, &local)) { - _LOGD("(%s:%p) failed to update with existing secrets: %s", - setting_name, - call_id, - local->message); - } + /* Remove old agent-owned secrets in the requested setting */ + nm_connection_clear_secrets_with_flags(new_connection, + match_secret_by_setting_name_and_flags_cb, + (gpointer) setting_name); /* Update the connection with the agent's secrets; by this point if any * system-owned secrets exist in 'secrets' the agent that provided them @@ -962,7 +938,8 @@ get_secrets_done_cb(NMAgentManager * manager, NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, NM_SETTINGS_CONNECTION_UPDATE_REASON_IGNORE_PERSIST_FAILURE - | NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_SYSTEM_SECRETS + | (agent_had_system ? NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_SYSTEM_SECRETS + : NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE) | NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_AGENT_SECRETS, "get-new-secrets", NULL)) @@ -970,6 +947,8 @@ get_secrets_done_cb(NMAgentManager * manager, applied_connection = call_id->applied_connection; if (applied_connection) { + gs_unref_variant GVariant *filtered_secrets2 = NULL; + get_cmp_flags(self, call_id, applied_connection, @@ -981,18 +960,12 @@ get_secrets_done_cb(NMAgentManager * manager, &agent_had_system, &cmp_flags); - nm_connection_clear_secrets(applied_connection); + nm_connection_clear_secrets_with_flags(applied_connection, + match_secret_by_setting_name_and_flags_cb, + (gpointer) setting_name); - if (!system_secrets - || nm_connection_update_secrets(applied_connection, - setting_name, - system_secrets, - NULL)) { - gs_unref_variant GVariant *filtered_secrets2 = NULL; - - filtered_secrets2 = validate_secret_flags(applied_connection, secrets, &cmp_flags); - nm_connection_update_secrets(applied_connection, setting_name, filtered_secrets2, NULL); - } + filtered_secrets2 = validate_secret_flags(applied_connection, secrets, &cmp_flags); + nm_connection_update_secrets(applied_connection, setting_name, filtered_secrets2, NULL); } _get_secrets_info_callback(call_id, agent_username, setting_name, local); @@ -1060,7 +1033,8 @@ nm_settings_connection_get_secrets(NMSettingsConnection * self, NMAgentManagerCallId call_id_a; gs_free char * joined_hints = NULL; NMSettingsConnectionCallId * call_id; - GError * local = NULL; + GError * local = NULL; + gs_unref_variant GVariant *system_secrets = NULL; g_return_val_if_fail(NM_IS_SETTINGS_CONNECTION(self), NULL); g_return_val_if_fail( @@ -1111,14 +1085,15 @@ nm_settings_connection_get_secrets(NMSettingsConnection * self, * Then we know that the this request probably did not yet include the latest secret-agent. */ priv->last_secret_agent_version_id = nm_agent_manager_get_agent_version_id(priv->agent_mgr); - /* Use priv->system_secrets to work around the fact that nm_connection_clear_secrets() - * will clear secrets on this object's settings. - */ + system_secrets = nm_g_variant_ref_sink( + nm_connection_to_dbus(nm_settings_connection_get_connection(self), + NM_CONNECTION_SERIALIZE_WITH_SECRETS_SYSTEM_OWNED)); + call_id_a = nm_agent_manager_get_secrets(priv->agent_mgr, nm_dbus_object_get_path(NM_DBUS_OBJECT(self)), nm_settings_connection_get_connection(self), subject, - priv->system_secrets, + system_secrets, setting_name, flags, hints, @@ -1327,7 +1302,6 @@ get_settings_auth_cb(NMSettingsConnection * self, { gs_free const char ** seen_bssids = NULL; NMConnectionSerializationOptions options = {}; - GVariant * settings; if (error) { g_dbus_method_invocation_return_gerror(context, error); @@ -1354,10 +1328,8 @@ get_settings_auth_cb(NMSettingsConnection * self, * get returned by the GetSecrets method which can be better * protected against leakage of secrets to unprivileged callers. */ - settings = nm_connection_to_dbus_full(nm_settings_connection_get_connection(self), - NM_CONNECTION_SERIALIZE_NO_SECRETS, - &options); - g_dbus_method_invocation_return_value(context, g_variant_new("(@a{sa{sv}})", settings)); + + g_dbus_method_invocation_return_value(context, _getsettings_cached_get(self, &options)); } static void @@ -1488,14 +1460,21 @@ update_auth_cb(NMSettingsConnection * self, if (!_nm_connection_aggregate(info->new_settings, NM_CONNECTION_AGGREGATE_ANY_SECRETS, NULL)) { + gs_unref_variant GVariant *secrets = NULL; + /* If the new connection has no secrets, we do not want to remove all * secrets, rather we keep all the existing ones. Do that by merging * them in to the new connection. */ + secrets = nm_g_variant_ref_sink( + nm_connection_to_dbus(nm_settings_connection_get_connection(self), + NM_CONNECTION_SERIALIZE_WITH_SECRETS)); + + if (secrets) + nm_connection_update_secrets(info->new_settings, NULL, secrets, NULL); + if (priv->agent_secrets) nm_connection_update_secrets(info->new_settings, NULL, priv->agent_secrets, NULL); - if (priv->system_secrets) - nm_connection_update_secrets(info->new_settings, NULL, priv->system_secrets, NULL); } else { /* Cache the new secrets from the agent, as stuff like inotify-triggered * changes to connection's backing config files will blow them away if @@ -1558,6 +1537,7 @@ update_auth_cb(NMSettingsConnection * self, : NM_SETTINGS_CONNECTION_UPDATE_REASON_REAPPLY_PARTIAL) | NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_SYSTEM_SECRETS | NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_AGENT_SECRETS + | NM_SETTINGS_CONNECTION_UPDATE_REASON_UPDATE_NON_SECRET | (NM_FLAGS_HAS(info->flags, NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT) ? NM_SETTINGS_CONNECTION_UPDATE_REASON_BLOCK_AUTOCONNECT : NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE), @@ -1568,7 +1548,7 @@ update_auth_cb(NMSettingsConnection * self, gs_unref_object NMConnection *for_agent = NULL; /* Dupe the connection so we can clear out non-agent-owned secrets, - * as agent-owned secrets are the only ones we send back be saved. + * as agent-owned secrets are the only ones we send back to be saved. * Only send secrets to agents of the same UID that called update too. */ for_agent = nm_simple_connection_new_clone(nm_settings_connection_get_connection(self)); @@ -1754,10 +1734,10 @@ impl_settings_connection_update2(NMDBusObject * obj, g_variant_get(parameters, "(@a{sa{sv}}u@a{sv})", &settings, &flags_u, &args); if (NM_FLAGS_ANY(flags_u, - ~((guint32)(_NM_SETTINGS_UPDATE2_FLAG_ALL_PERSIST_MODES - | NM_SETTINGS_UPDATE2_FLAG_VOLATILE - | NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT - | NM_SETTINGS_UPDATE2_FLAG_NO_REAPPLY)))) { + ~((guint32) (_NM_SETTINGS_UPDATE2_FLAG_ALL_PERSIST_MODES + | NM_SETTINGS_UPDATE2_FLAG_VOLATILE + | NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT + | NM_SETTINGS_UPDATE2_FLAG_NO_REAPPLY)))) { error = g_error_new_literal(NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_ARGUMENTS, "Unknown flags"); @@ -1888,9 +1868,9 @@ dbus_get_agent_secrets_cb(NMSettingsConnection * self, * by the time we get here. */ dict = nm_connection_to_dbus(nm_settings_connection_get_connection(self), - NM_CONNECTION_SERIALIZE_ONLY_SECRETS); + NM_CONNECTION_SERIALIZE_WITH_SECRETS); if (!dict) - dict = g_variant_new_array(G_VARIANT_TYPE("{sa{sv}}"), NULL, 0); + dict = nm_g_variant_singleton_aLsaLsvII(); g_dbus_method_invocation_return_value(context, g_variant_new("(@a{sa{sv}})", dict)); } } @@ -1959,8 +1939,9 @@ dbus_clear_secrets_auth_cb(NMSettingsConnection * self, GError * error, gpointer user_data) { - NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE(self); - gs_free_error GError *local = NULL; + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE(self); + gs_free_error GError *local = NULL; + gs_unref_object NMConnection *connection_cloned = NULL; if (error) { g_dbus_method_invocation_return_gerror(context, error); @@ -1973,7 +1954,24 @@ dbus_clear_secrets_auth_cb(NMSettingsConnection * self, return; } - nm_settings_connection_clear_secrets(self, TRUE, TRUE); + /* FIXME: add API to NMConnection so that we can clone a profile without secrets. */ + + connection_cloned = nm_simple_connection_new_clone(nm_settings_connection_get_connection(self)); + + nm_connection_clear_secrets(connection_cloned); + + if (!nm_settings_connection_update( + self, + connection_cloned, + NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP, + NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, + NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, + NM_SETTINGS_CONNECTION_UPDATE_REASON_IGNORE_PERSIST_FAILURE + | NM_SETTINGS_CONNECTION_UPDATE_REASON_CLEAR_SYSTEM_SECRETS + | NM_SETTINGS_CONNECTION_UPDATE_REASON_CLEAR_AGENT_SECRETS, + "clear-secrets", + NULL)) + nm_assert_not_reached(); /* Tell agents to remove secrets for this connection */ nm_agent_manager_delete_secrets(priv->agent_mgr, @@ -2142,7 +2140,9 @@ _cmp_last_resort(NMSettingsConnection *a, NMSettingsConnection *b) /* hm, same UUID. Use their pointer value to give them a stable * order. */ - return (a > b) ? -1 : 1; + NM_CMP_DIRECT_PTR(a, b); + + return nm_assert_unreachable_val(0); } /* sorting for "best" connections. @@ -2183,6 +2183,15 @@ nm_settings_connection_cmp_autoconnect_priority(NMSettingsConnection *a, NMSetti return _cmp_last_resort(a, b); } +int +nm_settings_connection_cmp_autoconnect_priority_with_data(gconstpointer pa, + gconstpointer pb, + gpointer user_data) +{ + return nm_settings_connection_cmp_autoconnect_priority((NMSettingsConnection *) pa, + (NMSettingsConnection *) pb); +} + int nm_settings_connection_cmp_autoconnect_priority_p_with_data(gconstpointer pa, gconstpointer pb, @@ -2243,6 +2252,8 @@ nm_settings_connection_update_timestamp(NMSettingsConnection *self, guint64 time _LOGT("timestamp: set timestamp %" G_GUINT64_FORMAT, timestamp); + _nm_settings_notify_sorted_by_autoconnect_priority_maybe_changed(priv->settings); + if (!priv->kf_db_timestamps) return; @@ -2659,7 +2670,6 @@ dispose(GObject *object) _get_secrets_cancel(self, call_id, TRUE); } - nm_clear_pointer(&priv->system_secrets, g_variant_unref); nm_clear_pointer(&priv->agent_secrets, g_variant_unref); nm_clear_pointer(&priv->seen_bssids, g_hash_table_destroy); @@ -2668,6 +2678,8 @@ dispose(GObject *object) g_clear_object(&priv->connection); + _getsettings_cached_clear(priv); + nm_clear_pointer(&priv->kf_db_timestamps, nm_key_file_db_unref); nm_clear_pointer(&priv->kf_db_seen_bssids, nm_key_file_db_unref); @@ -2732,20 +2744,17 @@ static const NMDBusInterfaceInfoExtended interface_info_settings_connection = { .out_args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("result", "a{sv}"), ), ), .handle = impl_settings_connection_update2, ), ), - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, - &signal_info_updated, - &signal_info_removed, ), + .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&signal_info_updated, &signal_info_removed, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Unsaved", - "b", - NM_SETTINGS_CONNECTION_UNSAVED), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Unsaved", + "b", + NM_SETTINGS_CONNECTION_UNSAVED), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Flags", "u", NM_SETTINGS_CONNECTION_FLAGS), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Filename", "s", NM_SETTINGS_CONNECTION_FILENAME), ), ), - .legacy_property_changed = TRUE, }; static void diff --git a/src/core/settings/nm-settings-connection.h b/src/core/settings/nm-settings-connection.h index 7c61dbeb..83a6a7f6 100644 --- a/src/core/settings/nm-settings-connection.h +++ b/src/core/settings/nm-settings-connection.h @@ -63,6 +63,9 @@ typedef enum { NM_SETTINGS_CONNECTION_UPDATE_REASON_BLOCK_AUTOCONNECT = (1u << 8), + /* Is anything other than secrets changing */ + NM_SETTINGS_CONNECTION_UPDATE_REASON_UPDATE_NON_SECRET = (1u << 9), + } NMSettingsConnectionUpdateReason; typedef enum { @@ -274,10 +277,6 @@ nm_settings_connection_get_secrets(NMSettingsConnection * self, void nm_settings_connection_cancel_secrets(NMSettingsConnection * self, NMSettingsConnectionCallId *call_id); -void nm_settings_connection_clear_secrets(NMSettingsConnection *self, - gboolean clear_cached_system_secrets, - gboolean persist); - gboolean nm_settings_connection_check_visibility(NMSettingsConnection *self, NMSessionMonitor * session_monitor); @@ -324,6 +323,9 @@ int nm_settings_connection_cmp_timestamp_p_with_data(gconstpointer pa, gpointer user_data); int nm_settings_connection_cmp_autoconnect_priority(NMSettingsConnection *a, NMSettingsConnection *b); +int nm_settings_connection_cmp_autoconnect_priority_with_data(gconstpointer pa, + gconstpointer pb, + gpointer user_data); int nm_settings_connection_cmp_autoconnect_priority_p_with_data(gconstpointer pa, gconstpointer pb, gpointer user_data); diff --git a/src/core/settings/nm-settings-plugin.c b/src/core/settings/nm-settings-plugin.c index 9e81caab..66cc19b6 100644 --- a/src/core/settings/nm-settings-plugin.c +++ b/src/core/settings/nm-settings-plugin.c @@ -9,7 +9,7 @@ #include "nm-settings-plugin.h" #include "nm-utils.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-settings-connection.h" diff --git a/src/core/settings/nm-settings-storage.c b/src/core/settings/nm-settings-storage.c index c56ba075..e284b822 100644 --- a/src/core/settings/nm-settings-storage.c +++ b/src/core/settings/nm-settings-storage.c @@ -7,6 +7,7 @@ #include "nm-settings-storage.h" +#include "libnm-glib-aux/nm-uuid.h" #include "nm-utils.h" #include "nm-settings-plugin.h" @@ -72,7 +73,7 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps case PROP_UUID: /* construct-only */ self->_uuid = g_value_dup_string(value); - nm_assert(!self->_uuid || nm_utils_is_uuid(self->_uuid)); + nm_assert(!self->_uuid || nm_uuid_is_normalized(self->_uuid)); break; case PROP_FILENAME: /* construct-only */ @@ -97,7 +98,7 @@ NMSettingsStorage * nm_settings_storage_new(NMSettingsPlugin *plugin, const char *uuid, const char *filename) { nm_assert(NM_IS_SETTINGS_PLUGIN(plugin)); - nm_assert(nm_utils_is_uuid(uuid)); + nm_assert(nm_uuid_is_normalized(uuid)); return g_object_new(NM_TYPE_SETTINGS_STORAGE, NM_SETTINGS_STORAGE_PLUGIN, diff --git a/src/core/settings/nm-settings-storage.h b/src/core/settings/nm-settings-storage.h index 970cfd77..2e5e1c55 100644 --- a/src/core/settings/nm-settings-storage.h +++ b/src/core/settings/nm-settings-storage.h @@ -48,36 +48,35 @@ GType nm_settings_storage_get_type(void); NMSettingsStorage * nm_settings_storage_new(struct _NMSettingsPlugin *plugin, const char *uuid, const char *filename); +/* forward declare so we don't have to include "nm-settings-plugin.h" here. */ +GType nm_settings_plugin_get_type(void); + static inline struct _NMSettingsPlugin * nm_settings_storage_get_plugin(const NMSettingsStorage *self) { - GType nm_settings_plugin_get_type(void); - g_return_val_if_fail(NM_IS_SETTINGS_STORAGE(self), NULL); nm_assert(G_TYPE_CHECK_INSTANCE_TYPE(self->_plugin, nm_settings_plugin_get_type())); return self->_plugin; } +gboolean nm_uuid_is_normalized_full(const char *str); + static inline const char * nm_settings_storage_get_uuid(const NMSettingsStorage *self) { - gboolean nm_utils_is_uuid(const char *str); - g_return_val_if_fail(NM_IS_SETTINGS_STORAGE(self), NULL); - nm_assert(nm_utils_is_uuid(self->_uuid)); + nm_assert(nm_uuid_is_normalized_full(self->_uuid)); return self->_uuid; } static inline const char * nm_settings_storage_get_uuid_opt(const NMSettingsStorage *self) { - gboolean nm_utils_is_uuid(const char *str); - g_return_val_if_fail(NM_IS_SETTINGS_STORAGE(self), NULL); - nm_assert(!self->_uuid || nm_utils_is_uuid(self->_uuid)); + nm_assert(!self->_uuid || nm_uuid_is_normalized_full(self->_uuid)); return self->_uuid; } diff --git a/src/core/settings/nm-settings.c b/src/core/settings/nm-settings.c index 3d31fb8b..c876ea14 100644 --- a/src/core/settings/nm-settings.c +++ b/src/core/settings/nm-settings.c @@ -20,9 +20,10 @@ #include #endif -#include "nm-libnm-core-intern/nm-common-macros.h" -#include "nm-glib-aux/nm-keyfile-aux.h" -#include "nm-keyfile-internal.h" +#include "libnm-core-aux-intern/nm-common-macros.h" +#include "libnm-glib-aux/nm-uuid.h" +#include "libnm-glib-aux/nm-keyfile-aux.h" +#include "libnm-core-intern/nm-keyfile-internal.h" #include "nm-dbus-interface.h" #include "nm-connection.h" #include "nm-setting-8021x.h" @@ -44,17 +45,17 @@ #include "nm-setting-proxy.h" #include "nm-setting-bond.h" #include "nm-utils.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" -#include "nm-std-aux/c-list-util.h" -#include "nm-glib-aux/nm-c-list.h" +#include "libnm-std-aux/c-list-util.h" +#include "libnm-glib-aux/nm-c-list.h" #include "nm-dbus-object.h" #include "devices/nm-device-ethernet.h" #include "nm-settings-connection.h" #include "nm-settings-plugin.h" #include "nm-dbus-manager.h" #include "nm-auth-utils.h" -#include "nm-libnm-core-intern/nm-auth-subject.h" +#include "libnm-core-aux-intern/nm-auth-subject.h" #include "nm-session-monitor.h" #include "plugins/keyfile/nms-keyfile-plugin.h" #include "plugins/keyfile/nms-keyfile-storage.h" @@ -139,7 +140,7 @@ nm_assert_storage_data_lst(CList *head) u = nm_settings_storage_get_uuid(sd->storage); if (!uuid) { uuid = u; - nm_assert(nm_utils_is_uuid(uuid)); + nm_assert(nm_uuid_is_normalized(uuid)); } else nm_assert(nm_streq0(uuid, u)); } @@ -182,7 +183,7 @@ _sett_conn_entry_new(const char *uuid) SettConnEntry *sett_conn_entry; gsize l_p_1; - nm_assert(nm_utils_is_uuid(uuid)); + nm_assert(nm_uuid_is_normalized(uuid)); l_p_1 = strlen(uuid) + 1; @@ -370,6 +371,7 @@ typedef struct { CList connections_lst_head; NMSettingsConnection **connections_cached_list; + NMSettingsConnection **connections_cached_list_sorted_by_autoconnect_priority; GSList *unmanaged_specs; GSList *unrecognized_specs; @@ -388,6 +390,12 @@ typedef struct { bool started : 1; + /* Whether NMSettingsConnections changed in a way that affects the comparison + * with nm_settings_connection_cmp_autoconnect_priority_with_data(). In that case, + * we may need to re-sort the connections_cached_list_sorted_by_autoconnect_priority + * list. */ + bool sorted_by_autoconnect_priority_maybe_changed : 1; + } NMSettingsPrivate; struct _NMSettings { @@ -1433,7 +1441,8 @@ _plugin_connections_reload(NMSettings *self) NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, TRUE, NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_SYSTEM_SECRETS - | NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_AGENT_SECRETS); + | NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_AGENT_SECRETS + | NM_SETTINGS_CONNECTION_UPDATE_REASON_UPDATE_NON_SECRET); for (iter = priv->plugins; iter; iter = iter->next) nm_settings_plugin_load_connections_done(iter->data); @@ -1460,7 +1469,7 @@ _add_connection_to_first_plugin(NMSettings * self, uuid = nm_connection_get_uuid(new_connection); - nm_assert(nm_utils_is_uuid(uuid)); + nm_assert(nm_uuid_is_normalized(uuid)); for (iter = priv->plugins; iter; iter = iter->next) { NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN(iter->data); @@ -1541,9 +1550,7 @@ _add_connection_to_first_plugin(NMSettings * self, } agent_owned_secrets = - nm_connection_to_dbus(new_connection, - NM_CONNECTION_SERIALIZE_ONLY_SECRETS - | NM_CONNECTION_SERIALIZE_WITH_SECRETS_AGENT_OWNED); + nm_connection_to_dbus(new_connection, NM_CONNECTION_SERIALIZE_WITH_SECRETS_AGENT_OWNED); connection_to_add_real = _connection_changed_normalize_connection(storage, connection_to_add, @@ -1912,7 +1919,8 @@ again_delete_tombstone: _NM_SETTINGS_CONNECTION_INT_FLAGS_PERSISTENT_MASK, FALSE, NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_SYSTEM_SECRETS - | NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_AGENT_SECRETS + | NM_SETTINGS_CONNECTION_UPDATE_REASON_CLEAR_AGENT_SECRETS + | NM_SETTINGS_CONNECTION_UPDATE_REASON_UPDATE_NON_SECRET | (NM_FLAGS_HAS(add_reason, NM_SETTINGS_CONNECTION_ADD_REASON_BLOCK_AUTOCONNECT) ? NM_SETTINGS_CONNECTION_UPDATE_REASON_BLOCK_AUTOCONNECT : NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE)); @@ -2218,9 +2226,7 @@ nm_settings_update_connection(NMSettings * self, nm_assert(nm_streq(uuid, nm_settings_storage_get_uuid(new_storage))); agent_owned_secrets = - nm_connection_to_dbus(connection, - NM_CONNECTION_SERIALIZE_ONLY_SECRETS - | NM_CONNECTION_SERIALIZE_WITH_SECRETS_AGENT_OWNED); + nm_connection_to_dbus(connection, NM_CONNECTION_SERIALIZE_WITH_SECRETS_AGENT_OWNED); new_connection_real = _connection_changed_normalize_connection(new_storage, new_connection, agent_owned_secrets, @@ -2297,7 +2303,7 @@ nm_settings_delete_connection(NMSettings * self, nm_assert(NM_IS_SETTINGS_STORAGE(cur_storage)); uuid = nm_settings_storage_get_uuid(cur_storage); - nm_assert(nm_utils_is_uuid(uuid)); + nm_assert(nm_uuid_is_normalized(uuid)); sett_conn_entry = _sett_conn_entries_get(self, uuid); @@ -2691,9 +2697,9 @@ impl_settings_add_connection2(NMDBusObject * obj, g_variant_get(parameters, "(@a{sa{sv}}u@a{sv})", &settings, &flags_u, &args); if (NM_FLAGS_ANY(flags_u, - ~((guint32)(NM_SETTINGS_ADD_CONNECTION2_FLAG_TO_DISK - | NM_SETTINGS_ADD_CONNECTION2_FLAG_IN_MEMORY - | NM_SETTINGS_ADD_CONNECTION2_FLAG_BLOCK_AUTOCONNECT)))) { + ~((guint32) (NM_SETTINGS_ADD_CONNECTION2_FLAG_TO_DISK + | NM_SETTINGS_ADD_CONNECTION2_FLAG_IN_MEMORY + | NM_SETTINGS_ADD_CONNECTION2_FLAG_BLOCK_AUTOCONNECT)))) { g_dbus_method_invocation_take_error(invocation, g_error_new_literal(NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_ARGUMENTS, @@ -2814,7 +2820,8 @@ impl_settings_load_connections(NMDBusObject * obj, NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, TRUE, NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_SYSTEM_SECRETS - | NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_AGENT_SECRETS); + | NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_AGENT_SECRETS + | NM_SETTINGS_CONNECTION_UPDATE_REASON_UPDATE_NON_SECRET); for (iter = priv->plugins; iter; iter = iter->next) nm_settings_plugin_load_connections_done(iter->data); @@ -2832,7 +2839,7 @@ impl_settings_load_connections(NMDBusObject * obj, g_dbus_method_invocation_return_value(invocation, g_variant_new("(b^as)", - (gboolean)(!failures), + (gboolean) (!failures), failures ? (const char **) failures->pdata : NM_PTRARRAY_EMPTY(const char *))); @@ -2870,25 +2877,48 @@ impl_settings_reload_connections(NMDBusObject * obj, /*****************************************************************************/ +void +_nm_settings_notify_sorted_by_autoconnect_priority_maybe_changed(NMSettings *self) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE(self); + + priv->sorted_by_autoconnect_priority_maybe_changed = TRUE; +} + static void _clear_connections_cached_list(NMSettingsPrivate *priv) { - if (!priv->connections_cached_list) - return; + if (priv->connections_cached_list) { + nm_assert(priv->connections_len == NM_PTRARRAY_LEN(priv->connections_cached_list)); - nm_assert(priv->connections_len == NM_PTRARRAY_LEN(priv->connections_cached_list)); +#if NM_MORE_ASSERTS + /* set the pointer to a bogus value. This makes it more apparent + * if somebody has a reference to the cached list and still uses + * it. That is a bug, this code just tries to make it blow up + * more eagerly. */ + memset(priv->connections_cached_list, + 0x43, + sizeof(NMSettingsConnection *) * (priv->connections_len + 1)); +#endif + + nm_clear_g_free(&priv->connections_cached_list); + } + if (priv->connections_cached_list_sorted_by_autoconnect_priority) { + nm_assert(priv->connections_len + == NM_PTRARRAY_LEN(priv->connections_cached_list_sorted_by_autoconnect_priority)); #if NM_MORE_ASSERTS - /* set the pointer to a bogus value. This makes it more apparent - * if somebody has a reference to the cached list and still uses - * it. That is a bug, this code just tries to make it blow up - * more eagerly. */ - memset(priv->connections_cached_list, - 0x43, - sizeof(NMSettingsConnection *) * (priv->connections_len + 1)); + /* set the pointer to a bogus value. This makes it more apparent + * if somebody has a reference to the cached list and still uses + * it. That is a bug, this code just tries to make it blow up + * more eagerly. */ + memset(priv->connections_cached_list_sorted_by_autoconnect_priority, + 0x42, + sizeof(NMSettingsConnection *) * (priv->connections_len + 1)); #endif - nm_clear_g_free(&priv->connections_cached_list); + nm_clear_g_free(&priv->connections_cached_list_sorted_by_autoconnect_priority); + } } static void @@ -3027,6 +3057,65 @@ nm_settings_get_connections(NMSettings *self, guint *out_len) return priv->connections_cached_list; } +NMSettingsConnection *const * +nm_settings_get_connections_sorted_by_autoconnect_priority(NMSettings *self, guint *out_len) +{ + NMSettingsPrivate *priv; + gboolean needs_sort = FALSE; + + g_return_val_if_fail(NM_IS_SETTINGS(self), NULL); + + priv = NM_SETTINGS_GET_PRIVATE(self); + + nm_assert(priv->connections_len == c_list_length(&priv->connections_lst_head)); + nm_assert( + !priv->connections_cached_list_sorted_by_autoconnect_priority + || (priv->connections_len + == NM_PTRARRAY_LEN(priv->connections_cached_list_sorted_by_autoconnect_priority))); + + if (!priv->connections_cached_list_sorted_by_autoconnect_priority) { + NMSettingsConnection *const *list_cached; + guint len; + + list_cached = nm_settings_get_connections(self, &len); + priv->connections_cached_list_sorted_by_autoconnect_priority = + nm_memdup(list_cached, sizeof(NMSettingsConnection *) * (len + 1)); + needs_sort = (len > 1); + } else if (priv->sorted_by_autoconnect_priority_maybe_changed) { + if (!nm_utils_ptrarray_is_sorted( + (gconstpointer *) priv->connections_cached_list_sorted_by_autoconnect_priority, + priv->connections_len, + FALSE, + nm_settings_connection_cmp_autoconnect_priority_with_data, + NULL)) { + /* We cache the sorted list, but we don't monitor all entries whether they + * get modified to invalidate the sort order. So every time we have to check + * whether the sort order is still correct. The vast majority of the time it + * is, and this check is faster than sorting anew. */ + needs_sort = TRUE; + } + } else { + nm_assert(nm_utils_ptrarray_is_sorted( + (gconstpointer *) priv->connections_cached_list_sorted_by_autoconnect_priority, + priv->connections_len, + TRUE, + nm_settings_connection_cmp_autoconnect_priority_with_data, + NULL)); + } + + priv->sorted_by_autoconnect_priority_maybe_changed = FALSE; + if (needs_sort) { + g_qsort_with_data(priv->connections_cached_list_sorted_by_autoconnect_priority, + priv->connections_len, + sizeof(NMSettingsConnection *), + nm_settings_connection_cmp_autoconnect_priority_p_with_data, + NULL); + } + + NM_SET_OUT(out_len, priv->connections_len); + return priv->connections_cached_list_sorted_by_autoconnect_priority; +} + /** * nm_settings_get_connections_clone: * @self: the #NMSetting @@ -3058,9 +3147,13 @@ nm_settings_get_connections_clone(NMSettings * self, g_return_val_if_fail(NM_IS_SETTINGS(self), NULL); - list_cached = nm_settings_get_connections(self, &len); + if (sort_compare_func == nm_settings_connection_cmp_autoconnect_priority_p_with_data) { + list_cached = nm_settings_get_connections_sorted_by_autoconnect_priority(self, &len); + sort_compare_func = NULL; + } else + list_cached = nm_settings_get_connections(self, &len); -#if NM_MORE_ASSERTS +#if NM_MORE_ASSERTS > 10 nm_assert(list_cached); for (i = 0; i < len; i++) nm_assert(NM_IS_SETTINGS_CONNECTION(list_cached[i])); @@ -3204,7 +3297,7 @@ add_plugin_load_file(NMSettings *self, const char *pname, GError **error) /* errors after this point are fatal, because we loaded the shared library already. */ - if (!g_module_symbol(module, "nm_settings_plugin_factory", (gpointer)(&factory_func))) { + if (!g_module_symbol(module, "nm_settings_plugin_factory", (gpointer) (&factory_func))) { g_set_error(error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, @@ -4027,18 +4120,16 @@ static const NMDBusInterfaceInfoExtended interface_info_settings = { .in_args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("hostname", "s"), ), ), .handle = impl_settings_save_hostname, ), ), - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, - &signal_info_new_connection, + .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&signal_info_new_connection, &signal_info_connection_removed, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Connections", - "ao", - NM_SETTINGS_CONNECTIONS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Hostname", "s", NM_SETTINGS_HOSTNAME), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("CanModify", - "b", - NM_SETTINGS_CAN_MODIFY), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Connections", + "ao", + NM_SETTINGS_CONNECTIONS), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Hostname", "s", NM_SETTINGS_HOSTNAME), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("CanModify", + "b", + NM_SETTINGS_CAN_MODIFY), ), ), }; static void diff --git a/src/core/settings/nm-settings.h b/src/core/settings/nm-settings.h index 09a0af57..ce18fecc 100644 --- a/src/core/settings/nm-settings.h +++ b/src/core/settings/nm-settings.h @@ -79,6 +79,9 @@ void nm_settings_add_connection_dbus(NMSettings * self, NMSettingsConnection *const *nm_settings_get_connections(NMSettings *settings, guint *out_len); +NMSettingsConnection *const * +nm_settings_get_connections_sorted_by_autoconnect_priority(NMSettings *self, guint *out_len); + NMSettingsConnection **nm_settings_get_connections_clone(NMSettings * self, guint * out_len, NMSettingsConnectionFilterFunc func, @@ -127,4 +130,6 @@ const char *nm_settings_get_startup_complete_blocked_reason(NMSettings *self, void nm_settings_kf_db_write(NMSettings *settings); +void _nm_settings_notify_sorted_by_autoconnect_priority_maybe_changed(NMSettings *self); + #endif /* __NM_SETTINGS_H__ */ diff --git a/src/core/settings/plugins/ifcfg-rh/meson.build b/src/core/settings/plugins/ifcfg-rh/meson.build index a2f11a92..c62fa89d 100644 --- a/src/core/settings/plugins/ifcfg-rh/meson.build +++ b/src/core/settings/plugins/ifcfg-rh/meson.build @@ -28,7 +28,6 @@ libnms_ifcfg_rh_core = static_library( 'shvar.c', ), dependencies: core_default_dep, - c_args: daemon_c_flags, ) libnm_settings_plugin_ifcfg_rh = shared_module( @@ -38,7 +37,6 @@ libnm_settings_plugin_ifcfg_rh = shared_module( 'nms-ifcfg-rh-plugin.c', ), dependencies: core_plugin_dep, - c_args: daemon_c_flags, link_with: libnms_ifcfg_rh_core, link_args: ldflags_linker_script_settings, link_depends: linker_script_settings, diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c index d114db0f..5038ac6a 100644 --- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c +++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c @@ -13,12 +13,12 @@ #include #include -#include "nm-std-aux/c-list-util.h" -#include "nm-glib-aux/nm-c-list.h" -#include "nm-glib-aux/nm-io-utils.h" -#include "nm-std-aux/nm-dbus-compat.h" +#include "libnm-std-aux/c-list-util.h" +#include "libnm-glib-aux/nm-c-list.h" +#include "libnm-glib-aux/nm-io-utils.h" +#include "libnm-std-aux/nm-dbus-compat.h" #include "nm-utils.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-config.h" #include "nm-dbus-manager.h" #include "settings/nm-settings-plugin.h" diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 209957d9..24d67003 100644 --- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -18,7 +18,8 @@ #include #include -#include "nm-glib-aux/nm-secret-utils.h" +#include "libnm-glib-aux/nm-uuid.h" +#include "libnm-glib-aux/nm-secret-utils.h" #include "nm-connection.h" #include "nm-dbus-interface.h" #include "nm-setting-connection.h" @@ -38,11 +39,11 @@ #include "nm-setting-user.h" #include "nm-setting-proxy.h" #include "nm-setting-generic.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-utils.h" -#include "nm-base/nm-ethtool-base.h" +#include "libnm-base/nm-ethtool-base.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "NetworkManagerUtils.h" #include "nms-ifcfg-rh-common.h" @@ -405,11 +406,9 @@ make_connection_setting(const char *file, /* Try for a UUID key before falling back to hashing the file name */ uuid = svGetValueStr(ifcfg, "UUID", &uuid_free); if (!uuid) { - uuid_free = nm_utils_uuid_generate_from_string(svFileGetName(ifcfg), - -1, - NM_UTILS_UUID_TYPE_LEGACY, - NULL); - uuid = uuid_free; + uuid_free = + nm_uuid_generate_from_string_str(svFileGetName(ifcfg), -1, NM_UUID_TYPE_LEGACY, NULL); + uuid = uuid_free; } g_object_set(s_con, @@ -2707,7 +2706,8 @@ make_tc_setting(shvarFile *ifcfg) } if (nm_setting_tc_config_get_num_qdiscs(s_tc) > 0 - || nm_setting_tc_config_get_num_tfilters(s_tc) > 0) + || nm_setting_tc_config_get_num_tfilters(s_tc) > 0 + || svGetValueBoolean(ifcfg, "TC_COMMIT", FALSE)) return NM_SETTING(s_tc); g_object_unref(s_tc); @@ -4302,7 +4302,7 @@ make_wireless_setting(shvarFile *ifcfg, GError **error) bytes = g_bytes_new(value, value_len); ssid_len = g_bytes_get_size(bytes); - if (ssid_len > 32 || ssid_len == 0) { + if (ssid_len == 0 || ssid_len > NM_IW_ESSID_MAX_SIZE) { g_set_error(error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, @@ -4678,7 +4678,9 @@ static NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( {"--coalesce", NM_ETHTOOL_TYPE_COALESCE}, {"--features", NM_ETHTOOL_TYPE_FEATURE}, {"--offload", NM_ETHTOOL_TYPE_FEATURE}, + {"--pause", NM_ETHTOOL_TYPE_PAUSE}, {"--set-ring", NM_ETHTOOL_TYPE_RING}, + {"-A", NM_ETHTOOL_TYPE_PAUSE}, {"-C", NM_ETHTOOL_TYPE_COALESCE}, {"-G", NM_ETHTOOL_TYPE_RING}, {"-K", NM_ETHTOOL_TYPE_FEATURE}, ); @@ -4718,7 +4720,7 @@ parse_ethtool_option(const char * value, w_iter = &words[2]; while (w_iter && *w_iter) { - if (ethtool_type == NM_ETHTOOL_TYPE_FEATURE) { + if (NM_IN_SET(ethtool_type, NM_ETHTOOL_TYPE_FEATURE, NM_ETHTOOL_TYPE_PAUSE)) { w_iter = _next_ethtool_options_nmternary(w_iter, ethtool_type, &ifcfg_option); if (ifcfg_option.has_value) { @@ -5021,6 +5023,7 @@ make_wired_setting(shvarFile *ifcfg, const char *file, NMSetting8021x **s_8021x, const char * cvalue; gs_free char * value = NULL; gboolean found = FALSE; + NMTernary accept_all_mac_addresses; s_wired = NM_SETTING_WIRED(nm_setting_wired_new()); @@ -5118,15 +5121,15 @@ make_wired_setting(shvarFile *ifcfg, const char *file, NMSetting8021x **s_8021x, for (i = 0; options && options[i]; i++) { const char *line = options[i]; const char *equals; - gboolean valid = FALSE; equals = strchr(line, '='); - if (equals) { - ((char *) equals)[0] = '\0'; - valid = nm_setting_wired_add_s390_option(s_wired, line, equals + 1); - } - if (!valid) - PARSE_WARNING("invalid s390 OPTION '%s'", line); + if (!equals) + continue; + + /* Here we don't verify the key/value further. If the file contains invalid keys, + * we will later reject the connection as invalid. */ + ((char *) equals)[0] = '\0'; + nm_setting_wired_add_s390_option(s_wired, line, equals + 1); } found = TRUE; } @@ -5179,6 +5182,15 @@ make_wired_setting(shvarFile *ifcfg, const char *file, NMSetting8021x **s_8021x, } nm_clear_g_free(&value); + accept_all_mac_addresses = svGetValueTernary(ifcfg, "ACCEPT_ALL_MAC_ADDRESSES"); + if (accept_all_mac_addresses != NM_TERNARY_DEFAULT) { + g_object_set(s_wired, + NM_SETTING_WIRED_ACCEPT_ALL_MAC_ADDRESSES, + accept_all_mac_addresses, + NULL); + found = TRUE; + } + if (!found) { g_set_error(error, NM_UTILS_ERROR, @@ -6071,15 +6083,14 @@ make_vlan_setting(shvarFile *ifcfg, const char *file, GError **error) v = iface_name + 4; } - if (v) { - int device_vlan_id; - - /* Grab VLAN ID from interface name; this takes precedence over the - * separate VLAN_ID property for backwards compat. + if (vlan_id == -1 && v) { + /* Grab VLAN ID from interface name; The explicit VLAN_ID option takes precedence + * over detecting the ID based on PHYSDEV. + * + * Note that older versions of NetworkManager had a bug and this would overwrite the + * VLAN_ID in this case. */ - device_vlan_id = _nm_utils_ascii_str_to_int64(v, 10, 0, 4095, -1); - if (device_vlan_id != -1) - vlan_id = device_vlan_id; + vlan_id = _nm_utils_ascii_str_to_int64(v, 10, 0, 4095, -1); } } diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.c index 3f674dea..134bdf68 100644 --- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.c +++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-storage.c @@ -7,8 +7,9 @@ #include "nms-ifcfg-rh-storage.h" +#include "libnm-glib-aux/nm-uuid.h" #include "nm-utils.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-connection.h" #include "nms-ifcfg-rh-plugin.h" @@ -88,7 +89,7 @@ static NMSIfcfgRHStorage * _storage_new(NMSIfcfgRHPlugin *plugin, const char *uuid, const char *filename) { nm_assert(NMS_IS_IFCFG_RH_PLUGIN(plugin)); - nm_assert(!uuid || nm_utils_is_uuid(uuid)); + nm_assert(!uuid || nm_uuid_is_normalized(uuid)); nm_assert(filename && filename[0] == '/'); return g_object_new(NMS_TYPE_IFCFG_RH_STORAGE, diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c index 8da5de47..6f6035e1 100644 --- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c +++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c @@ -9,7 +9,7 @@ #include -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "NetworkManagerUtils.h" #include "nms-ifcfg-rh-common.h" @@ -593,6 +593,9 @@ const char *const _nm_ethtool_ifcfg_names[] = { ETHT_NAME(NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_CSUM_SEGMENTATION, "tx-udp_tnl-csum-segmentation"), ETHT_NAME(NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_SEGMENTATION, "tx-udp_tnl-segmentation"), ETHT_NAME(NM_ETHTOOL_ID_FEATURE_TX_VLAN_STAG_HW_INSERT, "tx-vlan-stag-hw-insert"), + ETHT_NAME(NM_ETHTOOL_ID_PAUSE_AUTONEG, "pause-autoneg"), + ETHT_NAME(NM_ETHTOOL_ID_PAUSE_RX, "pause-rx"), + ETHT_NAME(NM_ETHTOOL_ID_PAUSE_TX, "pause-tx"), ETHT_NAME(NM_ETHTOOL_ID_RING_RX, "rx"), ETHT_NAME(NM_ETHTOOL_ID_RING_RX_JUMBO, "rx-jumbo"), ETHT_NAME(NM_ETHTOOL_ID_RING_RX_MINI, "rx-mini"), @@ -722,6 +725,15 @@ static NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( {"rx-mini", NM_ETHTOOL_ID_RING_RX_MINI}, {"tx", NM_ETHTOOL_ID_RING_TX}, ); +static NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( + _get_ethtoolid_pause_by_name, + NMEthtoolID, + { nm_assert(name); }, + { return NM_ETHTOOL_ID_UNKNOWN; }, + {"pause-autoneg", NM_ETHTOOL_ID_PAUSE_AUTONEG}, + {"pause-rx", NM_ETHTOOL_ID_PAUSE_RX}, + {"pause-tx", NM_ETHTOOL_ID_PAUSE_TX}, ); + const NMEthtoolData * nms_ifcfg_rh_utils_get_ethtool_by_name(const char *name, NMEthtoolType ethtool_type) { @@ -737,6 +749,9 @@ nms_ifcfg_rh_utils_get_ethtool_by_name(const char *name, NMEthtoolType ethtool_t case NM_ETHTOOL_TYPE_RING: id = _get_ethtoolid_ring_by_name(name); break; + case NM_ETHTOOL_TYPE_PAUSE: + id = _get_ethtoolid_pause_by_name(name); + break; default: nm_assert_not_reached(); return NULL; @@ -800,6 +815,7 @@ nms_ifcfg_rh_utils_is_numbered_tag_impl(const char *key, } const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = { + _KEY_TYPE("ACCEPT_ALL_MAC_ADDRESSES", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("ACD_TIMEOUT", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("ADDRESS", NMS_IFCFG_KEY_TYPE_IS_NUMBERED), _KEY_TYPE("AP_ISOLATION", NMS_IFCFG_KEY_TYPE_IS_PLAIN), @@ -1026,6 +1042,7 @@ const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = { _KEY_TYPE("STABLE_ID", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("STP", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("SUBCHANNELS", NMS_IFCFG_KEY_TYPE_IS_PLAIN), + _KEY_TYPE("TC_COMMIT", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("TEAM_CONFIG", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("TEAM_MASTER", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("TEAM_MASTER_UUID", NMS_IFCFG_KEY_TYPE_IS_PLAIN), diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h index 36ec9225..b61ce80a 100644 --- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h +++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h @@ -7,7 +7,7 @@ #define _UTILS_H_ #include "nm-connection.h" -#include "nm-base/nm-ethtool-base.h" +#include "libnm-base/nm-ethtool-base.h" #include "shvar.h" @@ -33,7 +33,7 @@ typedef struct { NMSIfcfgKeyTypeFlags key_flags; } NMSIfcfgKeyTypeInfo; -extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[247]; +extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[249]; const NMSIfcfgKeyTypeInfo *nms_ifcfg_well_known_key_find_info(const char *key, gssize *out_idx); diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index a968fce0..1c5bbbb4 100644 --- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -15,8 +15,9 @@ #include #include -#include "nm-glib-aux/nm-enum-utils.h" -#include "nm-glib-aux/nm-io-utils.h" +#include "libnm-glib-aux/nm-enum-utils.h" +#include "libnm-glib-aux/nm-str-buf.h" +#include "libnm-glib-aux/nm-io-utils.h" #include "nm-manager.h" #include "nm-setting-connection.h" #include "nm-setting-wired.h" @@ -32,9 +33,9 @@ #include "nm-setting-team.h" #include "nm-setting-team-port.h" #include "nm-utils.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "NetworkManagerUtils.h" -#include "nm-base/nm-ethtool-base.h" +#include "libnm-base/nm-ethtool-base.h" #include "nms-ifcfg-rh-common.h" #include "nms-ifcfg-rh-reader.h" @@ -203,18 +204,18 @@ write_object(NMSetting8021x * s_8021x, g_return_val_if_fail(ifcfg != NULL, FALSE); g_return_val_if_fail(objtype != NULL, FALSE); - scheme = (*(objtype->vtable->scheme_func))(s_8021x); + scheme = (*(objtype->vtable->scheme_func)) (s_8021x); switch (scheme) { case NM_SETTING_802_1X_CK_SCHEME_UNKNOWN: break; case NM_SETTING_802_1X_CK_SCHEME_BLOB: - blob = (*(objtype->vtable->blob_func))(s_8021x); + blob = (*(objtype->vtable->blob_func)) (s_8021x); break; case NM_SETTING_802_1X_CK_SCHEME_PATH: - value = (*(objtype->vtable->path_func))(s_8021x); + value = (*(objtype->vtable->path_func)) (s_8021x); break; case NM_SETTING_802_1X_CK_SCHEME_PKCS11: - value = (*(objtype->vtable->uri_func))(s_8021x); + value = (*(objtype->vtable->uri_func)) (s_8021x); break; default: g_set_error(error, @@ -227,8 +228,8 @@ write_object(NMSetting8021x * s_8021x, /* Set the password for certificate/private key. */ nm_sprintf_buf(secret_name, "%s_PASSWORD", objtype->ifcfg_rh_key); nm_sprintf_buf(secret_flags, "%s_PASSWORD_FLAGS", objtype->ifcfg_rh_key); - password = (*(objtype->vtable->passwd_func))(s_8021x); - flags = (*(objtype->vtable->pwflag_func))(s_8021x); + password = (*(objtype->vtable->passwd_func)) (s_8021x); + flags = (*(objtype->vtable->pwflag_func)) (s_8021x); set_secret(ifcfg, secrets, secret_name, password, secret_flags, flags); if (!objtype->vtable->format_func) @@ -299,6 +300,7 @@ write_blobs(GHashTable *blobs, GError **error) g_bytes_get_size(blob), 0600, NULL, + NULL, &write_error)) { g_set_error(error, NM_SETTINGS_ERROR, @@ -862,7 +864,7 @@ write_wireless_setting(NMConnection *connection, return FALSE; } ssid_data = g_bytes_get_data(ssid, &ssid_len); - if (!ssid_len || ssid_len > 32) { + if (ssid_len == 0 || ssid_len > NM_IW_ESSID_MAX_SIZE) { g_set_error(error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, @@ -903,9 +905,9 @@ write_wireless_setting(NMConnection *connection, svSetValueStr(ifcfg, "ESSID", str->str); g_string_free(str, TRUE); } else { - char buf[33]; + char buf[NM_IW_ESSID_MAX_SIZE + 1]; - nm_assert(ssid_len <= 32); + nm_assert(ssid_len <= NM_IW_ESSID_MAX_SIZE); memcpy(buf, ssid_data, ssid_len); buf[ssid_len] = '\0'; svSetValueStr(ifcfg, "ESSID", buf); @@ -1075,25 +1077,18 @@ write_hostname_setting(NMConnection *connection, shvarFile *ifcfg) svSetValueInt64_cond(ifcfg, "HOSTNAME_ONLY_FROM_DEFAULT", t != NM_TERNARY_DEFAULT, t); } -static gboolean -write_wired_setting(NMConnection *connection, shvarFile *ifcfg, GError **error) +static void +write_wired_setting_impl(NMSettingWired *s_wired, shvarFile *ifcfg, gboolean is_virtual) { - NMSettingWired * s_wired; const char *const *s390_subchannels; - guint32 mtu, num_opts, i; + guint32 mtu; + guint32 num_opts; + guint32 i; const char *const *macaddr_blacklist; - s_wired = nm_connection_get_setting_wired(connection); - if (!s_wired) { - g_set_error(error, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_FAILED, - "Missing '%s' setting", - NM_SETTING_WIRED_SETTING_NAME); - return FALSE; - } - - svSetValueStr(ifcfg, "HWADDR", nm_setting_wired_get_mac_address(s_wired)); + svSetValue(ifcfg, + "HWADDR", + nm_setting_wired_get_mac_address(s_wired) ?: (is_virtual ? "" : NULL)); svSetValueStr(ifcfg, "MACADDR", nm_setting_wired_get_cloned_mac_address(s_wired)); @@ -1137,7 +1132,7 @@ write_wired_setting(NMConnection *connection, shvarFile *ifcfg, GError **error) svSetValueStr(ifcfg, "CTCPROT", nm_setting_wired_get_s390_option_by_key(s_wired, "ctcprot")); num_opts = nm_setting_wired_get_num_s390_options(s_wired); - if (s390_subchannels && num_opts) { + if (num_opts > 0) { nm_auto_free_gstring GString *tmp = NULL; for (i = 0; i < num_opts; i++) { @@ -1167,8 +1162,42 @@ write_wired_setting(NMConnection *connection, shvarFile *ifcfg, GError **error) svSetValueStr(ifcfg, "OPTIONS", tmp->str); } + svSetValueTernary(ifcfg, + "ACCEPT_ALL_MAC_ADDRESSES", + nm_setting_wired_get_accept_all_mac_addresses(s_wired)); +} + +static gboolean +write_wired_setting(NMConnection *connection, shvarFile *ifcfg, GError **error) +{ + NMSettingWired *s_wired; + + s_wired = nm_connection_get_setting_wired(connection); + if (!s_wired) { + g_set_error(error, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_FAILED, + "Missing '%s' setting", + NM_SETTING_WIRED_SETTING_NAME); + return FALSE; + } + svSetValueStr(ifcfg, "TYPE", TYPE_ETHERNET); + write_wired_setting_impl(s_wired, ifcfg, FALSE); + return TRUE; +} + +static gboolean +write_wired_for_virtual(NMConnection *connection, shvarFile *ifcfg) +{ + NMSettingWired *s_wired; + + s_wired = nm_connection_get_setting_wired(connection); + if (!s_wired) + return FALSE; + + write_wired_setting_impl(s_wired, ifcfg, TRUE); return TRUE; } @@ -1334,6 +1363,26 @@ write_ethtool_setting(NMConnection *connection, shvarFile *ifcfg, GError **error g_string_append(str, nms_ifcfg_rh_utils_get_ethtool_name(ethtool_id)); g_string_append_printf(str, " %" G_GUINT32_FORMAT, u32); } + for (ethtool_id = _NM_ETHTOOL_ID_PAUSE_FIRST; ethtool_id <= _NM_ETHTOOL_ID_PAUSE_LAST; + ethtool_id++) { + nm_assert(nms_ifcfg_rh_utils_get_ethtool_name(ethtool_id)); + if (!nm_setting_option_get_boolean(NM_SETTING(s_ethtool), + nm_ethtool_data[ethtool_id]->optname, + &b)) + continue; + + _ethtool_gstring_prepare(&str, &is_first, 'A', iface); + g_string_append_c(str, ' '); + g_string_append(str, nms_ifcfg_rh_utils_get_ethtool_name(ethtool_id)); + g_string_append(str, b ? " on" : " off"); + } + + if (!str) { + /* Write an empty dummy "-A" option without arguments. This is to + * ensure that the reader will create an (all default) NMSettingEthtool. + * Also, it seems that `ethtool -A "$IFACE"` is silently accepted. */ + _ethtool_gstring_prepare(&str, &is_first, 'A', iface); + } } if (str) { @@ -1366,35 +1415,6 @@ vlan_priority_maplist_to_stringlist(NMSettingVlan *s_vlan, NMVlanPriorityMap map return value; } -static gboolean -write_wired_for_virtual(NMConnection *connection, shvarFile *ifcfg) -{ - NMSettingWired *s_wired; - gboolean has_wired = FALSE; - - s_wired = nm_connection_get_setting_wired(connection); - if (s_wired) { - const char *device_mac, *cloned_mac; - guint32 mtu; - - has_wired = TRUE; - - device_mac = nm_setting_wired_get_mac_address(s_wired); - svSetValue(ifcfg, "HWADDR", device_mac ?: ""); - - cloned_mac = nm_setting_wired_get_cloned_mac_address(s_wired); - svSetValueStr(ifcfg, "MACADDR", cloned_mac); - - svSetValueStr(ifcfg, - "GENERATE_MAC_ADDRESS_MASK", - nm_setting_wired_get_generate_mac_address_mask(s_wired)); - - mtu = nm_setting_wired_get_mtu(s_wired); - svSetValueInt64_cond(ifcfg, "MTU", mtu != 0, mtu); - } - return has_wired; -} - static gboolean write_vlan_setting(NMConnection *connection, shvarFile *ifcfg, gboolean *wired, GError **error) { @@ -1542,36 +1562,40 @@ write_team_setting(NMConnection *connection, shvarFile *ifcfg, gboolean *wired, static gboolean write_bridge_vlans(NMSetting * setting, - const char *property_name, + gboolean is_port, shvarFile * ifcfg, const char *key, GError ** error) { - gs_unref_ptrarray GPtrArray *vlans = NULL; - NMBridgeVlan * vlan; - GString * string; - guint i; + GPtrArray * vlans; + NMBridgeVlan * vlan; + nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT(0, FALSE); + guint i; - g_object_get(setting, property_name, &vlans, NULL); + if (is_port) + vlans = _nm_setting_bridge_port_get_vlans(NM_SETTING_BRIDGE_PORT(setting)); + else + vlans = _nm_setting_bridge_get_vlans(NM_SETTING_BRIDGE(setting)); if (!vlans || !vlans->len) return TRUE; - string = g_string_new(""); for (i = 0; i < vlans->len; i++) { gs_free char *vlan_str = NULL; vlan = vlans->pdata[i]; vlan_str = nm_bridge_vlan_to_str(vlan, error); - if (!vlan_str) - return FALSE; - if (string->len > 0) - g_string_append(string, ","); - nm_utils_escaped_tokens_escape_gstr_assert(vlan_str, ",", string); + if (!vlan_str) { + /* nm_bridge_vlan_to_str() cannot fail (for now). */ + nm_assert_not_reached(); + continue; + } + if (strbuf.len > 0) + nm_str_buf_append_c(&strbuf, ','); + nm_str_buf_append(&strbuf, nm_utils_escaped_tokens_escape_unnecessary(vlan_str, ",")); } - svSetValueStr(ifcfg, key, string->str); - g_string_free(string, TRUE); + svSetValueStr(ifcfg, key, nm_str_buf_get_str(&strbuf)); return TRUE; } @@ -1807,11 +1831,7 @@ write_bridge_setting(NMConnection *connection, shvarFile *ifcfg, gboolean *wired svSetValueStr(ifcfg, "BRIDGING_OPTS", opts->str); g_string_free(opts, TRUE); - if (!write_bridge_vlans((NMSetting *) s_bridge, - NM_SETTING_BRIDGE_VLANS, - ifcfg, - "BRIDGE_VLANS", - error)) + if (!write_bridge_vlans((NMSetting *) s_bridge, FALSE, ifcfg, "BRIDGE_VLANS", error)) return FALSE; svSetValueStr(ifcfg, "TYPE", TYPE_BRIDGE); @@ -1862,11 +1882,7 @@ write_bridge_port_setting(NMConnection *connection, shvarFile *ifcfg, GError **e svSetValueStr(ifcfg, "BRIDGING_OPTS", string->str); g_string_free(string, TRUE); - if (!write_bridge_vlans((NMSetting *) s_port, - NM_SETTING_BRIDGE_PORT_VLANS, - ifcfg, - "BRIDGE_PORT_VLANS", - error)) + if (!write_bridge_vlans((NMSetting *) s_port, TRUE, ifcfg, "BRIDGE_PORT_VLANS", error)) return FALSE; return TRUE; @@ -2511,46 +2527,46 @@ write_sriov_setting(NMConnection *connection, shvarFile *ifcfg) } } -static gboolean -write_tc_setting(NMConnection *connection, shvarFile *ifcfg, GError **error) +static void +write_tc_setting(NMConnection *connection, shvarFile *ifcfg) { NMSettingTCConfig *s_tc; - guint i, num, n; + guint num_qdiscs; + guint num_filters; + guint i; + guint n; char tag[64]; s_tc = nm_connection_get_setting_tc_config(connection); if (!s_tc) - return TRUE; + return; - num = nm_setting_tc_config_get_num_qdiscs(s_tc); - for (n = 1, i = 0; i < num; i++) { + num_qdiscs = nm_setting_tc_config_get_num_qdiscs(s_tc); + for (n = 1, i = 0; i < num_qdiscs; i++) { NMTCQdisc * qdisc; gs_free char *str = NULL; qdisc = nm_setting_tc_config_get_qdisc(s_tc, i); - str = nm_utils_tc_qdisc_to_str(qdisc, error); - if (!str) - return FALSE; - + str = nm_utils_tc_qdisc_to_str(qdisc, NULL); + nm_assert(str); svSetValueStr(ifcfg, numbered_tag(tag, "QDISC", n), str); n++; } - num = nm_setting_tc_config_get_num_tfilters(s_tc); - for (n = 1, i = 0; i < num; i++) { + num_filters = nm_setting_tc_config_get_num_tfilters(s_tc); + for (n = 1, i = 0; i < num_filters; i++) { NMTCTfilter * tfilter; gs_free char *str = NULL; tfilter = nm_setting_tc_config_get_tfilter(s_tc, i); - str = nm_utils_tc_tfilter_to_str(tfilter, error); - if (!str) - return FALSE; - + str = nm_utils_tc_tfilter_to_str(tfilter, NULL); + nm_assert(str); svSetValueStr(ifcfg, numbered_tag(tag, "FILTER", n), str); n++; } - return TRUE; + if (num_qdiscs == 0 && num_filters == 0) + svSetValueBoolean(ifcfg, "TC_COMMIT", TRUE); } static void @@ -3373,9 +3389,7 @@ do_write_construct(NMConnection * connection, write_match_setting(connection, ifcfg); write_hostname_setting(connection, ifcfg); write_sriov_setting(connection, ifcfg); - - if (!write_tc_setting(connection, ifcfg, error)) - return FALSE; + write_tc_setting(connection, ifcfg); route_path_is_svformat = utils_has_route_file_new_syntax(route_path); diff --git a/src/core/settings/plugins/ifcfg-rh/shvar.c b/src/core/settings/plugins/ifcfg-rh/shvar.c index 386bcac7..80644b64 100644 --- a/src/core/settings/plugins/ifcfg-rh/shvar.c +++ b/src/core/settings/plugins/ifcfg-rh/shvar.c @@ -14,10 +14,11 @@ #include #include -#include "nm-core-internal.h" +#include "libnm-glib-aux/nm-str-buf.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-core-utils.h" -#include "nm-glib-aux/nm-enum-utils.h" -#include "nm-glib-aux/nm-io-utils.h" +#include "libnm-glib-aux/nm-enum-utils.h" +#include "libnm-glib-aux/nm-io-utils.h" #include "c-list/src/c-list.h" #include "nms-ifcfg-rh-utils.h" @@ -152,17 +153,42 @@ _escape_ansic(const char *source) const char *p; char * dest; char * q; + gsize n_alloc; nm_assert(source); - p = (const char *) source; - /* Each source byte needs maximally four destination chars (\777) */ - q = dest = g_malloc(strlen(source) * 4 + 1 + 3); + n_alloc = 4; + for (p = source; p[0]; p++) { + switch (*p) { + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + case '\v': + case '\\': + case '"': + case '\'': + n_alloc += 2; + break; + default: + if ((*p < ' ') || (*p >= 0177)) + n_alloc += 4; + else + n_alloc += 1; + break; + } + } + + dest = g_malloc(n_alloc); + + q = dest; *q++ = '$'; *q++ = '\''; - while (*p) { + for (p = source; p[0]; p++) { + nm_assert(q < &dest[n_alloc]); switch (*p) { case '\b': *q++ = '\\'; @@ -204,12 +230,11 @@ _escape_ansic(const char *source) *q++ = *p; break; } - p++; } *q++ = '\''; *q++ = '\0'; - nm_assert(q - dest <= strlen(source) * 4 + 1 + 3); + nm_assert(q - dest == n_alloc); return dest; } @@ -217,7 +242,7 @@ _escape_ansic(const char *source) /*****************************************************************************/ #define _char_req_escape(ch) NM_IN_SET(ch, '"', '\\', '$', '`') -#define _char_req_escape_old(ch) NM_IN_SET(ch, '"', '\\', '\'', '$', '`', '~') +#define _char_req_escape_old(ch) NM_IN_SET(ch, '"', '\\', '$', '`', '\'', '~') #define _char_req_quotes(ch) NM_IN_SET(ch, ' ', '\'', '~', '\t', '|', '&', ';', '(', ')', '<', '>') const char * @@ -226,8 +251,10 @@ svEscape(const char *s, char **to_free) char *new; gsize mangle = 0; gboolean requires_quotes = FALSE; - int newlen; - size_t i, j, slen; + gsize n_alloc; + gsize slen; + gsize i; + gsize j; for (slen = 0; s[slen]; slen++) { if (_char_req_escape(s[slen])) @@ -247,8 +274,8 @@ svEscape(const char *s, char **to_free) return s; } - newlen = slen + mangle + 3; /* 3 is extra ""\0 */ - new = g_malloc(newlen); + n_alloc = slen + mangle + 3; /* 3 is extra ""\0 */ + new = g_malloc(n_alloc); j = 0; new[j++] = '"'; @@ -260,7 +287,7 @@ svEscape(const char *s, char **to_free) new[j++] = '"'; new[j++] = '\0'; - nm_assert(j == slen + mangle + 3); + nm_assert(j == n_alloc); *to_free = new; return new; @@ -318,14 +345,14 @@ _ch_hex_get(char ch) } static void -_gstr_init(GString **str, const char *value, gsize i) +_strbuf_init(NMStrBuf *str, const char *value, gsize i) { nm_assert(str); nm_assert(value); - if (!(*str)) { - /* if @str is not yet initialized, it allocates - * a new GString and copies @i characters from + if (str->allocated == 0) { + /* if @str is not yet initialized, it initializes + * a new NMStrBuf and copies @i characters from * @value over. * * Unescaping usually does not extend the length of a string, @@ -335,20 +362,20 @@ _gstr_init(GString **str, const char *value, gsize i) * (FACTOR*strlen(value) + CONST), which is non trivial to get * right in all cases. Also, we would have to provision for the * very unlikely extreme case. - * Instead, use a GString buffer which can grow as needed. But for an + * Instead, use a NMStrBuf buffer which can grow as needed. But for an * initial guess, strlen(value) is a good start */ - *str = g_string_new_len(NULL, strlen(value) + 3); - if (i) - g_string_append_len(*str, value, i); + nm_str_buf_maybe_expand(str, strlen(value) + 3u, FALSE); + nm_str_buf_append_len(str, value, i); } } const char * svUnescape(const char *value, char **to_free) { - gsize i, j; - GString *str = NULL; + NMStrBuf str = NM_STR_BUF_INIT(0, FALSE); int looks_like_old_svescaped = -1; + gsize i; + gsize j; /* we handle bash syntax here (note that ifup has #!/bin/bash. * Thus, see https://www.gnu.org/software/bash/manual/html_node/Quoting.html#Quoting */ @@ -395,20 +422,20 @@ svUnescape(const char *value, char **to_free) if (value[i] == '\\') { /* backslash escape */ - _gstr_init(&str, value, i); + _strbuf_init(&str, value, i); i++; if (G_UNLIKELY(value[i] == '\0')) { /* we don't support line continuation */ goto out_error; } - g_string_append_c(str, value[i]); + nm_str_buf_append_c(&str, value[i]); i++; goto loop1_next; } if (value[i] == '\'') { /* single quotes */ - _gstr_init(&str, value, i); + _strbuf_init(&str, value, i); i++; j = i; while (TRUE) { @@ -420,14 +447,14 @@ svUnescape(const char *value, char **to_free) break; j++; } - g_string_append_len(str, &value[i], j - i); + nm_str_buf_append_len(&str, &value[i], j - i); i = j + 1; goto loop1_next; } if (value[i] == '"') { /* double quotes */ - _gstr_init(&str, value, i); + _strbuf_init(&str, value, i); i++; while (TRUE) { if (value[i] == '"') { @@ -466,11 +493,11 @@ svUnescape(const char *value, char **to_free) if (looks_like_old_svescaped < 0) looks_like_old_svescaped = _looks_like_old_svescaped(value); if (!looks_like_old_svescaped) - g_string_append_c(str, '\\'); + nm_str_buf_append_c(&str, '\\'); } else - g_string_append_c(str, '\\'); + nm_str_buf_append_c(&str, '\\'); } - g_string_append_c(str, value[i]); + nm_str_buf_append_c(&str, value[i]); i++; } goto loop1_next; @@ -478,7 +505,7 @@ svUnescape(const char *value, char **to_free) if (value[i] == '$' && value[i + 1] == '\'') { /* ANSI-C Quoting */ - _gstr_init(&str, value, i); + _strbuf_init(&str, value, i); i += 2; while (TRUE) { char ch; @@ -552,7 +579,7 @@ svUnescape(const char *value, char **to_free) } } /* like bash, we cut too large numbers off. E.g. A=$'\772' becomes 0xfa */ - g_string_append_c(str, (guint8) v); + nm_str_buf_append_c(&str, (guint8) v); } else if (NM_IN_SET(value[i], 'x', 'u', 'U')) { const char escape_type = value[i]; int max_digits = escape_type == 'x' ? 2 : escape_type == 'u' ? 4 : 8; @@ -561,8 +588,7 @@ svUnescape(const char *value, char **to_free) i++; if (!_ch_hex_is(value[i])) { /* missing hex value after "\x" escape. This is treated like no escaping. */ - g_string_append_c(str, '\\'); - g_string_append_c(str, escape_type); + nm_str_buf_append_c(&str, '\\', escape_type); } else { v = _ch_hex_get(value[i]); i++; @@ -574,22 +600,21 @@ svUnescape(const char *value, char **to_free) i++; } if (escape_type == 'x') - g_string_append_c(str, v); + nm_str_buf_append_c(&str, v); else { /* we treat the unicode escapes as utf-8 encoded values. */ - g_string_append_unichar(str, v); + nm_str_buf_append_unichar(&str, v); } } } else { - g_string_append_c(str, '\\'); - g_string_append_c(str, value[i]); + nm_str_buf_append_c(&str, '\\', value[i]); i++; } goto loop_ansic_next; } } else ch = value[i]; - g_string_append_c(str, ch); + nm_str_buf_append_c(&str, ch); i++; loop_ansic_next:; } @@ -603,8 +628,8 @@ loop_ansic_next:; } /* an unquoted, regular character. Just consume it directly. */ - if (str) - g_string_append_c(str, value[i]); + if (str.allocated > 0) + nm_str_buf_append_c(&str, value[i]); i++; loop1_next:; @@ -614,18 +639,19 @@ loop1_next:; out_value: if (i == 0) { - nm_assert(!str); + nm_assert(str.allocated == 0); + nm_assert(!str._priv_str); *to_free = NULL; return ""; } - if (str) { - if (str->len == 0 || str->str[0] == '\0') { - g_string_free(str, TRUE); + if (str.allocated > 0) { + if (str.len == 0 || nm_str_buf_get_str_unsafe(&str)[0] == '\0') { + nm_str_buf_destroy(&str); *to_free = NULL; return ""; } else { - *to_free = g_string_free(str, FALSE); + *to_free = nm_str_buf_finalize(&str, NULL); return *to_free; } } @@ -639,8 +665,7 @@ out_value: return value; out_error: - if (str) - g_string_free(str, TRUE); + nm_str_buf_destroy(&str); *to_free = NULL; return NULL; } diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-a.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-a.cexpected index d81d9187..aebcd2b8 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-a.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-a.cexpected @@ -1,5 +1,5 @@ -HWADDR=00:22:15:59:62:97 TYPE=Ethernet +HWADDR=00:22:15:59:62:97 BRIDGING_OPTS="priority=28 hairpin_mode=1" NAME="System test-bridge-component" UUID=${UUID} diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-b.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-b.cexpected index 2e69c5e7..71d2cda8 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-b.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-b.cexpected @@ -1,5 +1,5 @@ -HWADDR=00:22:15:59:62:97 TYPE=Ethernet +HWADDR=00:22:15:59:62:97 NAME="System test-bridge-component" UUID=${UUID} DEVICE=eth0 diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-wired-802-1X-subj-matches.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-wired-802-1X-subj-matches.cexpected index 59a6f79b..240cd5c1 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-wired-802-1X-subj-matches.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-wired-802-1X-subj-matches.cexpected @@ -1,5 +1,5 @@ -HWADDR=00:11:22:33:44:EE TYPE=Ethernet +HWADDR=00:11:22:33:44:EE KEY_MGMT=IEEE8021X IEEE_8021X_EAP_METHODS=PEAP IEEE_8021X_IDENTITY="Jara Cimrman" diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bridge_Component.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bridge_Component.cexpected index a8ff8df3..d31d8ff5 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bridge_Component.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bridge_Component.cexpected @@ -1,6 +1,6 @@ +TYPE=Ethernet HWADDR=31:33:33:37:BE:CD MTU=1492 -TYPE=Ethernet BRIDGING_OPTS="priority=50 path_cost=33" BRIDGE_PORT_VLANS="1 untagged,2 pvid,4-4094 untagged" NAME="Test Write Bridge Component" diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected index cd8fc96f..cc29a2cc 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Wired_Static_Routes.cexpected @@ -1,6 +1,6 @@ +TYPE=Ethernet HWADDR=31:33:33:37:BE:CD MTU=1492 -TYPE=Ethernet PROXY_METHOD=none BROWSER_ONLY=no BOOTPROTO=none diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-static-routes-legacy.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-static-routes-legacy.cexpected index a28c5c1c..8197f320 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-static-routes-legacy.cexpected +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-static-routes-legacy.cexpected @@ -1,5 +1,5 @@ -HWADDR=00:16:41:11:22:33 TYPE=Ethernet +HWADDR=00:16:41:11:22:33 PROXY_METHOD=none BROWSER_ONLY=no BOOTPROTO=dhcp diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write-empty.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write-empty.cexpected new file mode 100644 index 00000000..4df768b4 --- /dev/null +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-tc-write-empty.cexpected @@ -0,0 +1,15 @@ +TYPE=Ethernet +PROXY_METHOD=none +BROWSER_ONLY=no +TC_COMMIT=yes +BOOTPROTO=none +IPADDR=1.1.1.3 +PREFIX=24 +GATEWAY=1.1.1.1 +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=no +NAME="Test Write TC config" +UUID=${UUID} +DEVICE=eth0 +ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-vlanid-use b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-vlanid-use new file mode 100644 index 00000000..fc9c8a45 --- /dev/null +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-vlanid-use @@ -0,0 +1,4 @@ +VLAN=yes +TYPE=Vlan +DEVICE=eth0.9 +VLAN_ID=10 diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-vlanid-use.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-vlanid-use.cexpected new file mode 100644 index 00000000..a7be14ce --- /dev/null +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-vlanid-use.cexpected @@ -0,0 +1,15 @@ +VLAN=yes +TYPE=Vlan +PHYSDEV=eth0 +VLAN_ID=10 +REORDER_HDR=yes +GVRP=no +MVRP=no +HWADDR= +PROXY_METHOD=none +BROWSER_ONLY=no +IPV6INIT=no +NAME="Vlan test-vlan-vlanid-use" +UUID=${UUID} +DEVICE=eth0.9 +ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-1.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-1.cexpected new file mode 100644 index 00000000..5186f90c --- /dev/null +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-1.cexpected @@ -0,0 +1,14 @@ +TYPE=Ethernet +PROXY_METHOD=none +BROWSER_ONLY=no +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=yes +IPV6_AUTOCONF=yes +IPV6_DEFROUTE=yes +IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=stable-privacy +NAME=test_roundtrip_ethtool +UUID=${UUID} +ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-2.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-2.cexpected new file mode 100644 index 00000000..5632ebec --- /dev/null +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-2.cexpected @@ -0,0 +1,15 @@ +TYPE=Ethernet +PROXY_METHOD=none +BROWSER_ONLY=no +ETHTOOL_OPTS="-A net0" +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=yes +IPV6_AUTOCONF=yes +IPV6_DEFROUTE=yes +IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=stable-privacy +NAME=test_roundtrip_ethtool +UUID=${UUID} +ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-3.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-3.cexpected new file mode 100644 index 00000000..96eec43b --- /dev/null +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-3.cexpected @@ -0,0 +1,15 @@ +TYPE=Ethernet +PROXY_METHOD=none +BROWSER_ONLY=no +ETHTOOL_OPTS="autoneg on" +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=yes +IPV6_AUTOCONF=yes +IPV6_DEFROUTE=yes +IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=stable-privacy +NAME=test_roundtrip_ethtool +UUID=${UUID} +ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-4.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-4.cexpected new file mode 100644 index 00000000..90250a30 --- /dev/null +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-4.cexpected @@ -0,0 +1,15 @@ +TYPE=Ethernet +PROXY_METHOD=none +BROWSER_ONLY=no +ETHTOOL_OPTS="-K net0 rx on" +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=yes +IPV6_AUTOCONF=yes +IPV6_DEFROUTE=yes +IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=stable-privacy +NAME=test_roundtrip_ethtool +UUID=${UUID} +ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-5.cexpected b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-5.cexpected new file mode 100644 index 00000000..721eacb2 --- /dev/null +++ b/src/core/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test_roundtrip_ethtool-5.cexpected @@ -0,0 +1,15 @@ +TYPE=Ethernet +PROXY_METHOD=none +BROWSER_ONLY=no +ETHTOOL_OPTS="autoneg on ; -K net0 rx on" +BOOTPROTO=dhcp +DEFROUTE=yes +IPV4_FAILURE_FATAL=no +IPV6INIT=yes +IPV6_AUTOCONF=yes +IPV6_DEFROUTE=yes +IPV6_FAILURE_FATAL=no +IPV6_ADDR_GEN_MODE=stable-privacy +NAME=test_roundtrip_ethtool +UUID=${UUID} +ONBOOT=yes diff --git a/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 59127d01..6193b952 100644 --- a/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/core/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -17,7 +17,8 @@ #include #include -#include "nm-glib-aux/nm-json-aux.h" +#include "libnm-glib-aux/nm-uuid.h" +#include "libnm-glib-aux/nm-json-aux.h" #include "nm-utils.h" #include "nm-setting-connection.h" #include "nm-setting-wired.h" @@ -36,9 +37,9 @@ #include "nm-setting-serial.h" #include "nm-setting-vlan.h" #include "nm-setting-dcb.h" -#include "nm-core-internal.h" -#include "nm-base/nm-ethtool-base.h" -#include "nm-base/nm-ethtool-utils-base.h" +#include "libnm-core-intern/nm-core-internal.h" +#include "libnm-base/nm-ethtool-base.h" +#include "libnm-base/nm-ethtool-utils-base.h" #include "NetworkManagerUtils.h" @@ -180,8 +181,20 @@ _assert_expected_content(NMConnection *connection, const char *filename, const c } if (len_expectd != len_written || memcmp(content_expectd, content_written, len_expectd) != 0) { - if (g_getenv("NMTST_IFCFG_RH_UPDATE_EXPECTED") - || nm_streq0(g_getenv("NM_TEST_REGENERATE"), "1")) { + static int rewrite_static = 0; + int rewrite; + + rewrite = g_atomic_int_get(&rewrite_static); + if (G_UNLIKELY(rewrite == 0)) { + rewrite = (g_getenv("NMTST_IFCFG_RH_UPDATE_EXPECTED") + || nm_streq0(g_getenv("NM_TEST_REGENERATE"), "1")) + ? -1 + : 1; + if (!g_atomic_int_compare_and_exchange(&rewrite_static, 0, rewrite)) + g_assert_not_reached(); + } + + if (rewrite > 0) { if (uuid) { gs_free char *search = g_strdup_printf("UUID=%s\n", uuid); const char * s; @@ -209,15 +222,16 @@ _assert_expected_content(NMConnection *connection, const char *filename, const c success = g_file_set_contents(expected, content_written, len_written, &error); nmtst_assert_success(success, error); } else { - g_error("The content of \"%s\" (%zu) differs from \"%s\" (%zu). Set " - "NMTST_IFCFG_RH_UPDATE_EXPECTED=yes to update the files " - "inplace\n\n>>>%s<<<\n\n>>>%s<<<\n", - filename, - len_written, - expected, - len_expectd, - content_written, - content_expectd); + g_error( + "The content of \"%s\" (%zu) differs from \"%s\" (%zu). Set " + "NMTST_IFCFG_RH_UPDATE_EXPECTED=yes (or NM_TEST_REGENERATE=1) to update the files " + "inplace\n\n>>>%s<<<\n\n>>>%s<<<\n", + filename, + len_written, + expected, + len_expectd, + content_written, + content_expectd); } } } @@ -359,8 +373,10 @@ _writer_new_connection_reread(NMConnection * connection, if (out_filename) *out_filename = filename; - else + else { + nmtst_file_unlink(filename); g_free(filename); + } } static void @@ -2519,7 +2535,7 @@ test_write_dns_options(void) NM_SETTING_CONNECTION_ID, "Test DNS options", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -3932,6 +3948,76 @@ test_read_wired_unknown_ethtool_opt(void) g_assert_cmpstr(nm_setting_wired_get_wake_on_lan_password(s_wired), ==, "00:11:22:33:44:55"); } +static void +test_roundtrip_ethtool(void) +{ + gs_unref_object NMConnection *connection = NULL; + NMSetting * s_ethtool; + NMSetting * s_wired; + + connection = nmtst_create_minimal_connection("test_roundtrip_ethtool", + NULL, + NM_SETTING_WIRED_SETTING_NAME, + NULL); + _writer_new_connec_exp(connection, + TEST_SCRATCH_DIR, + TEST_IFCFG_DIR "/ifcfg-test_roundtrip_ethtool-1.cexpected", + NULL); + g_clear_object(&connection); + + connection = nmtst_create_minimal_connection("test_roundtrip_ethtool", + NULL, + NM_SETTING_WIRED_SETTING_NAME, + NULL); + s_ethtool = nm_setting_ethtool_new(); + nm_connection_add_setting(connection, s_ethtool); + _writer_new_connec_exp(connection, + TEST_SCRATCH_DIR, + TEST_IFCFG_DIR "/ifcfg-test_roundtrip_ethtool-2.cexpected", + NULL); + g_clear_object(&connection); + + connection = nmtst_create_minimal_connection("test_roundtrip_ethtool", + NULL, + NM_SETTING_WIRED_SETTING_NAME, + NULL); + s_wired = nm_connection_get_setting(connection, NM_TYPE_SETTING_WIRED); + g_object_set(s_wired, NM_SETTING_WIRED_AUTO_NEGOTIATE, TRUE, NULL); + _writer_new_connec_exp(connection, + TEST_SCRATCH_DIR, + TEST_IFCFG_DIR "/ifcfg-test_roundtrip_ethtool-3.cexpected", + NULL); + g_clear_object(&connection); + + connection = nmtst_create_minimal_connection("test_roundtrip_ethtool", + NULL, + NM_SETTING_WIRED_SETTING_NAME, + NULL); + s_ethtool = nm_setting_ethtool_new(); + nm_connection_add_setting(connection, s_ethtool); + nm_setting_option_set_boolean(s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_RX, TRUE); + _writer_new_connec_exp(connection, + TEST_SCRATCH_DIR, + TEST_IFCFG_DIR "/ifcfg-test_roundtrip_ethtool-4.cexpected", + NULL); + g_clear_object(&connection); + + connection = nmtst_create_minimal_connection("test_roundtrip_ethtool", + NULL, + NM_SETTING_WIRED_SETTING_NAME, + NULL); + s_wired = nm_connection_get_setting(connection, NM_TYPE_SETTING_WIRED); + g_object_set(s_wired, NM_SETTING_WIRED_AUTO_NEGOTIATE, TRUE, NULL); + s_ethtool = nm_setting_ethtool_new(); + nm_connection_add_setting(connection, s_ethtool); + nm_setting_option_set_boolean(s_ethtool, NM_ETHTOOL_OPTNAME_FEATURE_RX, TRUE); + _writer_new_connec_exp(connection, + TEST_SCRATCH_DIR, + TEST_IFCFG_DIR "/ifcfg-test_roundtrip_ethtool-5.cexpected", + NULL); + g_clear_object(&connection); +} + static void test_read_wifi_hidden(void) { @@ -3977,7 +4063,7 @@ test_write_wifi_hidden(void) NM_SETTING_CONNECTION_ID, "Test Write Wi-Fi Hidden", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME, NULL); @@ -4062,7 +4148,7 @@ test_write_wifi_mac_random(gconstpointer user_data) NM_SETTING_CONNECTION_ID, val, NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME, NULL); @@ -4122,7 +4208,7 @@ test_write_wired_wake_on_lan(void) NM_SETTING_CONNECTION_ID, "Test Write Wired Wake-on-LAN", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, NULL); @@ -4305,7 +4391,7 @@ test_write_wifi_band_a(void) NM_SETTING_CONNECTION_ID, "Test Write Wi-Fi Band A", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME, NULL); @@ -4363,7 +4449,7 @@ test_write_wifi_ap_mode(void) NM_SETTING_CONNECTION_ID, "Test Write Wi-Fi AP Mode", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME, NULL); @@ -4676,7 +4762,7 @@ test_write_wired_static(void) NM_SETTING_CONNECTION_ID, "Test Write Wired Static", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES, @@ -4831,7 +4917,7 @@ test_write_wired_static_with_generic(void) NM_SETTING_CONNECTION_ID, "Test Write Wired Static", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_AUTOCONNECT_RETRIES, @@ -4999,7 +5085,7 @@ test_write_wired_dhcp(void) NM_SETTING_CONNECTION_ID, "Test Write Wired DHCP", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -5111,7 +5197,7 @@ test_write_routing_rules(void) NM_SETTING_CONNECTION_ID, "Test Write Routing Rules", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -5169,7 +5255,7 @@ test_write_wired_match(void) NM_SETTING_CONNECTION_ID, "Test Write Wired with Match setting", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -5315,7 +5401,7 @@ test_write_wired_static_ip6_only(void) NM_SETTING_CONNECTION_ID, "Test Write Wired Static IP6 Only", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -5432,7 +5518,7 @@ test_write_wired_static_ip6_only_gw(gconstpointer user_data) NM_SETTING_CONNECTION_ID, id, NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -5587,7 +5673,7 @@ test_write_wired_static_routes(void) NM_SETTING_CONNECTION_ID, "Test Write Wired Static Routes", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -5711,7 +5797,7 @@ test_write_wired_dhcp_8021x_peap_mschapv2(void) NM_SETTING_CONNECTION_ID, "Test Write Wired DHCP 802.1x PEAP MSCHAPv2", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -5813,7 +5899,7 @@ test_write_wired_8021x_tls(gconstpointer test_data) NM_SETTING_CONNECTION_ID, "Test Write Wired 802.1x TLS Blobs", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -5983,7 +6069,7 @@ test_write_wired_aliases(void) NM_SETTING_CONNECTION_ID, "alias0", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, NULL); @@ -6110,7 +6196,7 @@ test_write_gateway(void) NM_SETTING_CONNECTION_ID, "Test Write Static Addresses Gateway", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, NULL); @@ -6187,7 +6273,7 @@ test_write_wifi_open(void) NM_SETTING_CONNECTION_ID, "Test Write Wifi Open", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -6273,7 +6359,7 @@ test_write_wifi_open_hex_ssid(void) NM_SETTING_CONNECTION_ID, "Test Write Wifi Open Hex SSID", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -6347,7 +6433,7 @@ test_write_wifi_wep(void) NM_SETTING_CONNECTION_ID, "Test Write Wifi WEP", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -6445,7 +6531,7 @@ test_write_wifi_wep_adhoc(void) NM_SETTING_CONNECTION_ID, "Test Write Wifi WEP AdHoc", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -6539,7 +6625,7 @@ test_write_wifi_wep_passphrase(void) NM_SETTING_CONNECTION_ID, "Test Write Wifi WEP Passphrase", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -6634,7 +6720,7 @@ test_write_wifi_wep_40_ascii(void) NM_SETTING_CONNECTION_ID, "Test Write Wifi WEP 40 ASCII", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -6732,7 +6818,7 @@ test_write_wifi_wep_104_ascii(void) NM_SETTING_CONNECTION_ID, "Test Write Wifi WEP 104 ASCII", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -6833,7 +6919,7 @@ test_write_wifi_leap(void) NM_SETTING_CONNECTION_ID, "Test Write Wifi LEAP", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -6931,7 +7017,7 @@ test_write_wifi_leap_secret_flags(gconstpointer data) NM_SETTING_CONNECTION_ID, "Test Write Wifi LEAP Secret Flags", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME, NULL); @@ -7037,7 +7123,7 @@ test_write_wifi_wpa_psk(gconstpointer test_data) NM_SETTING_CONNECTION_ID, args.name, NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -7142,7 +7228,7 @@ test_write_wifi_wpa_psk_adhoc(void) NM_SETTING_CONNECTION_ID, "Test Write Wifi WPA PSK", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -7252,7 +7338,7 @@ test_write_wifi_wpa_eap_tls(void) NM_SETTING_CONNECTION_ID, "Test Write Wifi WPA EAP-TLS", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -7295,8 +7381,8 @@ test_write_wifi_wpa_eap_tls(void) g_object_set(s_8021x, NM_SETTING_802_1X_IDENTITY, "Bill Smith", NULL); g_object_set(s_8021x, NM_SETTING_802_1X_PHASE1_AUTH_FLAGS, - (guint)(NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_0_DISABLE - | NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_1_DISABLE), + (guint) (NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_0_DISABLE + | NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_1_DISABLE), NULL); nm_setting_802_1x_add_eap_method(s_8021x, "tls"); @@ -7379,7 +7465,7 @@ test_write_wifi_wpa_eap_ttls_tls(void) NM_SETTING_CONNECTION_ID, "Test Write Wifi WPA EAP-TTLS (TLS)", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -7515,7 +7601,7 @@ test_write_wifi_wpa_eap_ttls_mschapv2(void) NM_SETTING_CONNECTION_ID, "Test Write Wifi WPA EAP-TTLS (MSCHAPv2)", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -7630,7 +7716,7 @@ test_write_wifi_wpa_then_open(void) NM_SETTING_CONNECTION_ID, "random wifi connection", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -7747,7 +7833,7 @@ test_write_wifi_wpa_then_wep_with_perms(void) NM_SETTING_CONNECTION_ID, "random wifi connection 2", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_PERMISSIONS, @@ -7872,7 +7958,7 @@ test_write_wifi_dynamic_wep_leap(void) NM_SETTING_CONNECTION_ID, "Test Write Wifi Dynamic WEP LEAP", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME, NULL); @@ -7969,7 +8055,7 @@ test_write_wired_qeth_dhcp(void) NM_SETTING_CONNECTION_ID, "Test Write Wired qeth Static", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -8043,7 +8129,7 @@ test_write_wired_ctc_dhcp(void) NM_SETTING_CONNECTION_ID, "Test Write Wired ctc Static", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, NULL); @@ -8118,7 +8204,7 @@ test_write_permissions(void) NM_SETTING_CONNECTION_ID, "Test Write Permissions", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -8187,7 +8273,7 @@ test_write_wifi_wep_agent_keys(void) NM_SETTING_CONNECTION_ID, "Test Write Wifi WEP Agent Owned", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME, NULL); @@ -8273,7 +8359,7 @@ test_write_wired_pppoe(void) NM_SETTING_CONNECTION_ID, "Test Write Wired PPPoE", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -8334,7 +8420,7 @@ test_write_vpn(void) NM_SETTING_CONNECTION_ID, "Test Write VPN", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -8392,7 +8478,7 @@ test_write_mobile_broadband(gconstpointer data) NM_SETTING_CONNECTION_ID, gsm ? "Test Write GSM" : "Test Write CDMA", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -8510,7 +8596,7 @@ test_write_bridge_main(void) NM_SETTING_CONNECTION_ID, "Test Write Bridge Main", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_INTERFACE_NAME, @@ -8639,7 +8725,7 @@ test_write_bridge_component(void) NM_SETTING_CONNECTION_ID, "Test Write Bridge Component", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -8786,6 +8872,38 @@ test_read_vlan_only_vlan_id(void) g_object_unref(connection); } +static void +test_read_vlan_vlanid_use(void) +{ + nmtst_auto_unlinkfile char *testfile = NULL; + gs_unref_object NMConnection *connection = NULL; + gs_unref_object NMConnection *reread = NULL; + NMSettingVlan * s_vlan; + + connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-vlan-vlanid-use", + NULL, + TYPE_ETHERNET, + NULL); + + g_assert_cmpstr(nm_connection_get_interface_name(connection), ==, "eth0.9"); + + s_vlan = nm_connection_get_setting_vlan(connection); + g_assert(s_vlan); + + g_assert_cmpstr(nm_setting_vlan_get_parent(s_vlan), ==, "eth0"); + g_assert_cmpint(nm_setting_vlan_get_id(s_vlan), ==, 10); + g_assert_cmpint(nm_setting_vlan_get_flags(s_vlan), ==, NM_VLAN_FLAG_REORDER_HEADERS); + + _writer_new_connec_exp(connection, + TEST_SCRATCH_DIR, + TEST_IFCFG_DIR "/ifcfg-test-vlan-vlanid-use.cexpected", + &testfile); + + reread = _connection_from_file(testfile, NULL, TYPE_ETHERNET, NULL); + + nmtst_assert_connection_equals(connection, TRUE, reread, FALSE); +} + static void test_read_vlan_only_device(void) { @@ -8991,7 +9109,7 @@ test_write_vlan_reorder_hdr(void) NM_SETTING_CONNECTION_ID, "Test Write VLAN reorder_hdr", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, FALSE, NM_SETTING_CONNECTION_TYPE, @@ -9046,7 +9164,7 @@ test_write_ethernet_missing_ipv6(void) NM_SETTING_CONNECTION_ID, "Test Write Ethernet Without IPv6 Setting", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -9170,7 +9288,7 @@ test_write_bond_main(void) NM_SETTING_CONNECTION_ID, "Test Write Bond Main", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_INTERFACE_NAME, @@ -9270,7 +9388,7 @@ test_write_bond_slave(void) NM_SETTING_CONNECTION_ID, "Test Write Bond Slave", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -9357,7 +9475,7 @@ test_write_infiniband(void) NM_SETTING_CONNECTION_ID, "Test Write InfiniBand", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -9446,7 +9564,7 @@ test_write_bond_slave_ib(void) NM_SETTING_CONNECTION_ID, "Test Write Bond Slave InfiniBand", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_TYPE, @@ -9604,7 +9722,7 @@ test_write_dcb_basic(void) NM_SETTING_CONNECTION_ID, "dcb-test", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_CONNECTION_INTERFACE_NAME, @@ -9850,7 +9968,7 @@ test_write_fcoe_mode(gconstpointer user_data) NM_SETTING_CONNECTION_ID, "fcoe-test", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_CONNECTION_INTERFACE_NAME, @@ -9968,7 +10086,7 @@ test_write_team_master(void) NM_SETTING_CONNECTION_ID, "Test Write Team Master", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_INTERFACE_NAME, "team0", NM_SETTING_CONNECTION_TYPE, @@ -10060,7 +10178,7 @@ test_write_team_port(void) NM_SETTING_CONNECTION_ID, "Test Write Team Port", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_CONNECTION_MASTER, @@ -10119,7 +10237,7 @@ test_write_team_infiniband_port(void) NM_SETTING_CONNECTION_ID, "Test Write Team Infiniband Port", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_TYPE, NM_SETTING_INFINIBAND_SETTING_NAME, NM_SETTING_CONNECTION_MASTER, @@ -10309,7 +10427,7 @@ test_write_proxy_basic(void) NM_SETTING_CONNECTION_ID, "Test Write Proxy Basic", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, NULL); @@ -10999,7 +11117,7 @@ test_sriov_write(void) NM_SETTING_CONNECTION_ID, "Test Write SR-IOV config", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_INTERFACE_NAME, @@ -11108,6 +11226,85 @@ test_tc_read(void) g_object_unref(connection); } +static void +test_tc_write_empty(void) +{ + nmtst_auto_unlinkfile char *testfile = NULL; + gs_unref_object NMConnection *connection = NULL; + gs_unref_object NMConnection *reread = NULL; + NMSettingConnection * s_con; + NMSettingIPConfig * s_ip4; + NMSettingIPConfig * s_ip6; + NMSettingWired * s_wired; + NMSettingTCConfig * s_tc; + NMIPAddress * addr; + GError * error = NULL; + + connection = nm_simple_connection_new(); + + /* Connection setting */ + s_con = (NMSettingConnection *) nm_setting_connection_new(); + nm_connection_add_setting(connection, NM_SETTING(s_con)); + + g_object_set(s_con, + NM_SETTING_CONNECTION_ID, + "Test Write TC config", + NM_SETTING_CONNECTION_UUID, + nm_uuid_generate_random_str_a(), + NM_SETTING_CONNECTION_AUTOCONNECT, + TRUE, + NM_SETTING_CONNECTION_INTERFACE_NAME, + "eth0", + NM_SETTING_CONNECTION_TYPE, + NM_SETTING_WIRED_SETTING_NAME, + NULL); + + /* Wired setting */ + s_wired = (NMSettingWired *) nm_setting_wired_new(); + nm_connection_add_setting(connection, NM_SETTING(s_wired)); + + /* 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_GATEWAY, + "1.1.1.1", + NM_SETTING_IP_CONFIG_MAY_FAIL, + TRUE, + NULL); + + addr = nm_ip_address_new(AF_INET, "1.1.1.3", 24, &error); + g_assert_no_error(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_IGNORE, NULL); + + /* TC setting */ + s_tc = (NMSettingTCConfig *) nm_setting_tc_config_new(); + nm_connection_add_setting(connection, NM_SETTING(s_tc)); + + nm_connection_add_setting(connection, nm_setting_proxy_new()); + + nmtst_assert_connection_verifies_without_normalization(connection); + + _writer_new_connec_exp(connection, + TEST_SCRATCH_DIR, + TEST_IFCFG_DIR "/ifcfg-test-tc-write-empty.cexpected", + &testfile); + + reread = _connection_from_file(testfile, NULL, TYPE_BOND, NULL); + + nmtst_assert_connection_equals(connection, FALSE, reread, FALSE); +} + static void test_tc_write(void) { @@ -11134,7 +11331,7 @@ test_tc_write(void) NM_SETTING_CONNECTION_ID, "Test Write TC config", NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_a(), + nm_uuid_generate_random_str_a(), NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_INTERFACE_NAME, @@ -11326,6 +11523,7 @@ test_ethtool_names(void) } s_idxs[] = { {_NM_ETHTOOL_ID_FEATURE_FIRST, _NM_ETHTOOL_ID_FEATURE_LAST}, {_NM_ETHTOOL_ID_COALESCE_FIRST, _NM_ETHTOOL_ID_COALESCE_LAST}, + {_NM_ETHTOOL_ID_PAUSE_FIRST, _NM_ETHTOOL_ID_PAUSE_LAST}, {_NM_ETHTOOL_ID_RING_FIRST, _NM_ETHTOOL_ID_RING_LAST}, }; const NMEthtoolData *data; @@ -11520,6 +11718,8 @@ main(int argc, char **argv) g_test_add_func(TPATH "802-1x/password_raw", test_read_write_802_1x_password_raw); g_test_add_func(TPATH "802-1x/tls-p12-no-client-cert", test_read_802_1x_tls_p12_no_client_cert); + g_test_add_func(TPATH "wired/roundtrip/ethtool", test_roundtrip_ethtool); + g_test_add_data_func(TPATH "wired/read/aliases/good/0", GINT_TO_POINTER(0), test_read_wired_aliases_good); @@ -11626,6 +11826,7 @@ main(int argc, char **argv) g_test_add_func(TPATH "vlan/read/physdev", test_read_vlan_physdev); g_test_add_func(TPATH "vlan/read/reorder-hdr-1", test_read_vlan_reorder_hdr_1); g_test_add_func(TPATH "vlan/read/reorder-hdr-2", test_read_vlan_reorder_hdr_2); + g_test_add_func(TPATH "vlan/read/vlanid-use", test_read_vlan_vlanid_use); g_test_add_func(TPATH "wired/read/read-wake-on-lan", test_read_wired_wake_on_lan); g_test_add_func(TPATH "wired/read/read-auto-negotiate-off", test_read_wired_auto_negotiate_off); g_test_add_func(TPATH "wired/read/read-auto-negotiate-on", test_read_wired_auto_negotiate_on); @@ -11848,6 +12049,7 @@ main(int argc, char **argv) g_test_add_func(TPATH "tc/read", test_tc_read); g_test_add_func(TPATH "tc/write", test_tc_write); + g_test_add_func(TPATH "tc/write_empty", test_tc_write_empty); g_test_add_func(TPATH "utils/test_well_known_keys", test_well_known_keys); g_test_add_func(TPATH "utils/test_utils_has_route_file_new_syntax", test_utils_has_route_file_new_syntax); diff --git a/src/core/settings/plugins/ifupdown/meson.build b/src/core/settings/plugins/ifupdown/meson.build index dd252783..1bff8155 100644 --- a/src/core/settings/plugins/ifupdown/meson.build +++ b/src/core/settings/plugins/ifupdown/meson.build @@ -7,14 +7,12 @@ libnms_ifupdown_core = static_library( 'nms-ifupdown-parser.c', ), dependencies: core_default_dep, - c_args: daemon_c_flags, ) libnm_settings_plugin_ifupdown = shared_module( 'nm-settings-plugin-ifupdown', sources: 'nms-ifupdown-plugin.c', dependencies: core_plugin_dep, - c_args: daemon_c_flags, link_with: libnms_ifupdown_core, link_args: ldflags_linker_script_settings, link_depends: linker_script_settings, diff --git a/src/core/settings/plugins/ifupdown/nms-ifupdown-parser.c b/src/core/settings/plugins/ifupdown/nms-ifupdown-parser.c index a4974a96..db6b1aef 100644 --- a/src/core/settings/plugins/ifupdown/nms-ifupdown-parser.c +++ b/src/core/settings/plugins/ifupdown/nms-ifupdown-parser.c @@ -12,7 +12,8 @@ #include #include -#include "nm-core-internal.h" +#include "libnm-glib-aux/nm-uuid.h" +#include "libnm-core-intern/nm-core-internal.h" #include "settings/nm-settings-plugin.h" #include "nms-ifupdown-plugin.h" @@ -32,14 +33,6 @@ /*****************************************************************************/ -#define _str_has_prefix(val, prefix, require_suffix) \ - ({ \ - const char *_val = (val); \ - \ - (strncmp(_val, "" prefix "", NM_STRLEN(prefix)) == 0) \ - && (!(require_suffix) || _val[NM_STRLEN(prefix)] != '\0'); \ - }) - static const char * _ifupdownplugin_guess_connection_type(if_block *block) { @@ -51,8 +44,7 @@ _ifupdownplugin_guess_connection_type(if_block *block) if_data *ifb; c_list_for_each_entry (ifb, &block->data_lst_head, data_lst) { - if (_str_has_prefix(ifb->key, "wireless-", FALSE) - || _str_has_prefix(ifb->key, "wpa-", FALSE)) { + if (NM_STR_HAS_PREFIX(ifb->key, "wireless-") || NM_STR_HAS_PREFIX(ifb->key, "wpa-")) { ret_type = NM_SETTING_WIRELESS_SETTING_NAME; break; } @@ -102,7 +94,7 @@ update_wireless_setting_from_if_block(NMConnection *connection, if_block *block) wireless_setting = NM_SETTING_WIRELESS(nm_setting_wireless_new()); c_list_for_each_entry (curr, &block->data_lst_head, data_lst) { - if (_str_has_prefix(curr->key, "wireless-", TRUE)) { + if (NM_STR_HAS_PREFIX_WITH_MORE(curr->key, "wireless-")) { const char *newkey = map_by_mapping(mapping, curr->key + NM_STRLEN("wireless-")); _LOGI("wireless setting key: %s='%s'", newkey, curr->data); @@ -137,7 +129,7 @@ update_wireless_setting_from_if_block(NMConnection *connection, if_block *block) } else { g_object_set(wireless_setting, newkey, curr->data, NULL); } - } else if (_str_has_prefix(curr->key, "wpa-", TRUE)) { + } else if (NM_STR_HAS_PREFIX_WITH_MORE(curr->key, "wpa-")) { const char *newkey = map_by_mapping(mapping, curr->key + NM_STRLEN("wpa-")); if (nm_streq0(newkey, "ssid")) { @@ -304,7 +296,7 @@ update_wireless_security_setting_from_if_block(NMConnection *connection, if_bloc wireless_security_setting = NM_SETTING_WIRELESS_SECURITY(nm_setting_wireless_security_new()); c_list_for_each_entry (curr, &block->data_lst_head, data_lst) { - if (_str_has_prefix(curr->key, "wireless-", TRUE)) { + if (NM_STR_HAS_PREFIX_WITH_MORE(curr->key, "wireless-")) { const char * key = curr->key + NM_STRLEN("wireless-"); char * property_value = NULL; gpointer typed_property_value = NULL; @@ -336,7 +328,7 @@ wireless_next: if (typed_property_value && free_func) (*free_func)(typed_property_value); - } else if (_str_has_prefix(curr->key, "wpa-", TRUE)) { + } else if (NM_STR_HAS_PREFIX_WITH_MORE(curr->key, "wpa-")) { const char * key = curr->key + NM_STRLEN("wpa-"); char * property_value = NULL; gpointer typed_property_value = NULL; @@ -644,7 +636,7 @@ ifupdown_new_connection_from_if_block(if_block *block, gboolean autoconnect, GEr type = _ifupdownplugin_guess_connection_type(block); idstr = g_strconcat("Ifupdown (", block->name, ")", NULL); - uuid = nm_utils_uuid_generate_from_string(idstr, -1, NM_UTILS_UUID_TYPE_LEGACY, NULL); + uuid = nm_uuid_generate_from_string_str(idstr, -1, NM_UUID_TYPE_LEGACY, NULL); g_object_set(s_con, NM_SETTING_CONNECTION_TYPE, type, @@ -655,7 +647,7 @@ ifupdown_new_connection_from_if_block(if_block *block, gboolean autoconnect, GEr NM_SETTING_CONNECTION_UUID, uuid, NM_SETTING_CONNECTION_AUTOCONNECT, - (gboolean)(!!autoconnect), + (gboolean) (!!autoconnect), NULL); _LOGD("update_connection_setting_from_if_block: name:%s, type:%s, id:%s, uuid: %s", diff --git a/src/core/settings/plugins/ifupdown/nms-ifupdown-plugin.c b/src/core/settings/plugins/ifupdown/nms-ifupdown-plugin.c index 34523f8d..80a5638a 100644 --- a/src/core/settings/plugins/ifupdown/nms-ifupdown-plugin.c +++ b/src/core/settings/plugins/ifupdown/nms-ifupdown-plugin.c @@ -9,7 +9,7 @@ #include "nms-ifupdown-plugin.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-core-utils.h" #include "nm-config.h" #include "settings/nm-settings-plugin.h" diff --git a/src/core/settings/plugins/ifupdown/tests/test-ifupdown.c b/src/core/settings/plugins/ifupdown/tests/test-ifupdown.c index 6e3eb0e7..0e8db733 100644 --- a/src/core/settings/plugins/ifupdown/tests/test-ifupdown.c +++ b/src/core/settings/plugins/ifupdown/tests/test-ifupdown.c @@ -5,7 +5,7 @@ #include "src/core/nm-default-daemon.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "settings/plugins/ifupdown/nms-ifupdown-interface-parser.h" #include "settings/plugins/ifupdown/nms-ifupdown-parser.h" diff --git a/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c b/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c index 789bfc1a..e8ae1814 100644 --- a/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c +++ b/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c @@ -13,19 +13,20 @@ #include #include -#include "nm-std-aux/c-list-util.h" -#include "nm-glib-aux/nm-c-list.h" -#include "nm-glib-aux/nm-io-utils.h" +#include "libnm-std-aux/c-list-util.h" +#include "libnm-glib-aux/nm-c-list.h" +#include "libnm-glib-aux/nm-uuid.h" +#include "libnm-glib-aux/nm-io-utils.h" #include "nm-connection.h" #include "nm-setting.h" #include "nm-setting-connection.h" #include "nm-utils.h" #include "nm-config.h" -#include "nm-core-internal.h" -#include "nm-keyfile-internal.h" +#include "libnm-core-intern/nm-core-internal.h" +#include "libnm-core-intern/nm-keyfile-internal.h" -#include "systemd/nm-sd-utils-shared.h" +#include "libnm-systemd-shared/nm-sd-utils-shared.h" #include "settings/nm-settings-plugin.h" #include "settings/nm-settings-storage.h" @@ -233,7 +234,7 @@ _read_from_file(const char * full_filename, nm_assert(!connection || (_nm_connection_verify(connection, NULL) == NM_SETTING_VERIFY_SUCCESS)); - nm_assert(!connection || nm_utils_is_uuid(nm_connection_get_uuid(connection))); + nm_assert(!connection || nm_uuid_is_normalized(nm_connection_get_uuid(connection))); return connection; } @@ -260,7 +261,7 @@ _nm_assert_storage(gpointer plugin /* NMSKeyfilePlugin */, uuid = nms_keyfile_storage_get_uuid(storage); - nm_assert(nm_utils_is_uuid(uuid)); + nm_assert(nm_uuid_is_normalized(uuid)); nm_assert(((NMSKeyfileStorage *) storage)->is_meta_data || !(((NMSKeyfileStorage *) storage)->u.conn_data.connection) @@ -1106,7 +1107,7 @@ nms_keyfile_plugin_set_nmmeta_tombstone(NMSKeyfilePlugin * self, const char * dirname; nm_assert(NMS_IS_KEYFILE_PLUGIN(self)); - nm_assert(nm_utils_is_uuid(uuid)); + nm_assert(nm_uuid_is_normalized(uuid)); nm_assert(!out_storage || !*out_storage); nm_assert(!shadowed_storage || (set && in_memory)); @@ -1246,9 +1247,9 @@ nms_keyfile_plugin_init(NMSKeyfilePlugin *plugin) /* dirname_libs are a set of read-only directories with lower priority than /etc or /run. * There is nothing complicated about having multiple of such directories, so dirname_libs * is a list (which currently only has at most one directory). */ - priv->dirname_libs[0] = nm_sd_utils_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_LIB), FALSE); + priv->dirname_libs[0] = nm_sd_utils_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_LIB)); priv->dirname_libs[1] = NULL; - priv->dirname_run = nm_sd_utils_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_RUN), FALSE); + priv->dirname_run = nm_sd_utils_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_RUN)); priv->dirname_etc = nm_config_data_get_value(NM_CONFIG_GET_DATA_ORIG, NM_CONFIG_KEYFILE_GROUP_KEYFILE, NM_CONFIG_KEYFILE_KEY_KEYFILE_PATH, @@ -1261,10 +1262,9 @@ nms_keyfile_plugin_init(NMSKeyfilePlugin *plugin) } else if (!priv->dirname_etc || priv->dirname_etc[0] != '/') { /* either invalid path or unspecified. Use the default. */ g_free(priv->dirname_etc); - priv->dirname_etc = - nm_sd_utils_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_ETC_DEFAULT), FALSE); + priv->dirname_etc = nm_sd_utils_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_ETC_DEFAULT)); } else - nm_sd_utils_path_simplify(priv->dirname_etc, FALSE); + nm_sd_utils_path_simplify(priv->dirname_etc); /* no duplicates */ if (NM_IN_STRSET(priv->dirname_libs[0], priv->dirname_etc, priv->dirname_run)) diff --git a/src/core/settings/plugins/keyfile/nms-keyfile-reader.c b/src/core/settings/plugins/keyfile/nms-keyfile-reader.c index 70b047f3..8b9d982f 100644 --- a/src/core/settings/plugins/keyfile/nms-keyfile-reader.c +++ b/src/core/settings/plugins/keyfile/nms-keyfile-reader.c @@ -9,7 +9,7 @@ #include -#include "nm-keyfile-internal.h" +#include "libnm-core-intern/nm-keyfile-internal.h" #include "NetworkManagerUtils.h" #include "nms-keyfile-utils.h" diff --git a/src/core/settings/plugins/keyfile/nms-keyfile-storage.c b/src/core/settings/plugins/keyfile/nms-keyfile-storage.c index 89be817a..8c526c81 100644 --- a/src/core/settings/plugins/keyfile/nms-keyfile-storage.c +++ b/src/core/settings/plugins/keyfile/nms-keyfile-storage.c @@ -7,8 +7,9 @@ #include "nms-keyfile-storage.h" +#include "libnm-glib-aux/nm-uuid.h" #include "nm-utils.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nms-keyfile-plugin.h" /*****************************************************************************/ @@ -108,7 +109,7 @@ _storage_new(NMSKeyfilePlugin * plugin, NMSKeyfileStorage *self; nm_assert(NMS_IS_KEYFILE_PLUGIN(plugin)); - nm_assert(nm_utils_is_uuid(uuid)); + nm_assert(nm_uuid_is_normalized(uuid)); nm_assert(filename && filename[0] == '/'); self = g_object_new(NMS_TYPE_KEYFILE_STORAGE, @@ -135,7 +136,7 @@ nms_keyfile_storage_new_tombstone(NMSKeyfilePlugin * plugin, { NMSKeyfileStorage *self; - nm_assert(nm_utils_is_uuid(uuid)); + nm_assert(nm_uuid_is_normalized(uuid)); nm_assert(filename && filename[0] == '/'); nm_assert(nms_keyfile_nmmeta_check_filename(filename, NULL)); nm_assert(NM_IN_SET(storage_type, NMS_KEYFILE_STORAGE_TYPE_ETC, NMS_KEYFILE_STORAGE_TYPE_RUN)); diff --git a/src/core/settings/plugins/keyfile/nms-keyfile-utils.c b/src/core/settings/plugins/keyfile/nms-keyfile-utils.c index f3dffdae..e2c68bbe 100644 --- a/src/core/settings/plugins/keyfile/nms-keyfile-utils.c +++ b/src/core/settings/plugins/keyfile/nms-keyfile-utils.c @@ -10,8 +10,9 @@ #include #include -#include "nm-glib-aux/nm-io-utils.h" -#include "nm-keyfile-internal.h" +#include "libnm-glib-aux/nm-uuid.h" +#include "libnm-glib-aux/nm-io-utils.h" +#include "libnm-core-intern/nm-keyfile-internal.h" #include "nm-utils.h" #include "nm-setting-wired.h" #include "nm-setting-wireless.h" @@ -30,9 +31,9 @@ const char * nms_keyfile_nmmeta_check_filename(const char *filename, guint *out_uuid_len) { - const char *uuid; const char *s; gsize len; + char uuid[37]; s = strrchr(filename, '/'); if (s) @@ -50,17 +51,18 @@ nms_keyfile_nmmeta_check_filename(const char *filename, guint *out_uuid_len) len -= NM_STRLEN(NM_KEYFILE_PATH_SUFFIX_NMMETA); - if (!NM_IN_SET(len, 36, 40)) { + if (len != 36) { /* the remaining part of the filename has not the right length to - * contain a UUID (according to nm_utils_is_uuid()). */ + * contain a UUID (according to nm_uuid_is_normalized()). */ return NULL; } - uuid = nm_strndup_a(100, filename, len, NULL); - if (!nm_utils_is_uuid(uuid)) + memcpy(uuid, filename, 36); + uuid[36] = '\0'; + if (!nm_uuid_is_normalized(uuid)) return NULL; - NM_SET_OUT(out_uuid_len, len); + NM_SET_OUT(out_uuid_len, 36); return filename; } @@ -71,7 +73,7 @@ nms_keyfile_nmmeta_filename(const char *dirname, const char *uuid, gboolean temp char *s; nm_assert(dirname && dirname[0] == '/'); - nm_assert(nm_utils_is_uuid(uuid) && !strchr(uuid, '/')); + nm_assert(nm_uuid_is_normalized(uuid) && !strchr(uuid, '/')); if (g_snprintf(filename, sizeof(filename), @@ -80,7 +82,7 @@ nms_keyfile_nmmeta_filename(const char *dirname, const char *uuid, gboolean temp NM_KEYFILE_PATH_SUFFIX_NMMETA, temporary ? "~" : "") >= sizeof(filename)) { - /* valid uuids are limited in length (nm_utils_is_uuid). The buffer should always + /* valid uuids are limited in length (nm_uuid_is_normalized). The buffer should always * be large enough. */ nm_assert_not_reached(); } @@ -137,7 +139,11 @@ nms_keyfile_nmmeta_read(const char * dirname, NMMETA_KF_GROUP_NAME_NMMETA, NMMETA_KF_KEY_NAME_NMMETA_UUID, NULL); - if (!nm_streq0(v_uuid, uuid)) + if (!v_uuid) + return FALSE; + if (strncmp(v_uuid, uuid, uuid_len) != 0) + return FALSE; + if (v_uuid[uuid_len] != '\0') return FALSE; loaded_path = g_key_file_get_string(kf, @@ -211,7 +217,7 @@ nms_keyfile_nmmeta_write(const char *dirname, int errsv; nm_assert(dirname && dirname[0] == '/'); - nm_assert(nm_utils_is_uuid(uuid) && !strchr(uuid, '/')); + nm_assert(nm_uuid_is_normalized(uuid) && !strchr(uuid, '/')); nm_assert(!loaded_path || loaded_path[0] == '/'); nm_assert(!shadowed_storage || loaded_path); @@ -269,7 +275,13 @@ nms_keyfile_nmmeta_write(const char *dirname, contents = g_key_file_to_data(kf, &length, NULL); - if (!nm_utils_file_set_contents(full_filename, contents, length, 0600, &errsv, NULL)) { + if (!nm_utils_file_set_contents(full_filename, + contents, + length, + 0600, + NULL, + &errsv, + NULL)) { NM_SET_OUT(out_full_filename, g_steal_pointer(&full_filename_tmp)); return -NM_ERRNO_NATIVE(errsv); } diff --git a/src/core/settings/plugins/keyfile/nms-keyfile-writer.c b/src/core/settings/plugins/keyfile/nms-keyfile-writer.c index 0e2c94b5..70afdc23 100644 --- a/src/core/settings/plugins/keyfile/nms-keyfile-writer.c +++ b/src/core/settings/plugins/keyfile/nms-keyfile-writer.c @@ -12,12 +12,12 @@ #include #include -#include "nm-keyfile-internal.h" +#include "libnm-core-intern/nm-keyfile-internal.h" #include "nms-keyfile-utils.h" #include "nms-keyfile-reader.h" -#include "nm-glib-aux/nm-io-utils.h" +#include "libnm-glib-aux/nm-io-utils.h" /*****************************************************************************/ @@ -125,13 +125,14 @@ cert_writer(NMConnection * connection, /* FIXME(keyfile-parse-in-memory): writer must not access/write to the file system before * being sure that the entire profile can be written and all circumstances are good to - * proceed. That means, while writing we must only collect the blogs in-memory, and write + * proceed. That means, while writing we must only collect the blobs in-memory, and write * them all in the end together (or not at all). */ success = nm_utils_file_set_contents(new_path, (const char *) blob_data, blob_len, 0600, NULL, + NULL, &local); if (success) { /* Write the path value to the keyfile. @@ -378,7 +379,7 @@ _internal_write_connection(NMConnection * connection, } } - nm_utils_file_set_contents(path, kf_content_buf, kf_content_len, 0600, NULL, &local_err); + nm_utils_file_set_contents(path, kf_content_buf, kf_content_len, 0600, NULL, NULL, &local_err); if (local_err) { g_set_error(error, NM_SETTINGS_ERROR, diff --git a/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c b/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c index 348b0ed6..a13c2586 100644 --- a/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c +++ b/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c @@ -15,7 +15,8 @@ #include #include -#include "nm-core-internal.h" +#include "libnm-glib-aux/nm-uuid.h" +#include "libnm-core-intern/nm-core-internal.h" #include "settings/plugins/keyfile/nms-keyfile-reader.h" #include "settings/plugins/keyfile/nms-keyfile-writer.h" @@ -2289,7 +2290,7 @@ test_read_missing_id_uuid(void) gs_free char * expected_uuid = NULL; const char * FILENAME = TEST_KEYFILES_DIR "/Test_Missing_ID_UUID"; - expected_uuid = _nm_utils_uuid_generate_from_strings("keyfile", FILENAME, NULL); + expected_uuid = nm_uuid_generate_from_strings("keyfile", FILENAME, NULL); connection = keyfile_read_connection_from_file(FILENAME); diff --git a/src/core/supplicant/nm-supplicant-config.c b/src/core/supplicant/nm-supplicant-config.c index eab494b0..1959a161 100644 --- a/src/core/supplicant/nm-supplicant-config.c +++ b/src/core/supplicant/nm-supplicant-config.c @@ -10,11 +10,11 @@ #include -#include "nm-glib-aux/nm-str-buf.h" -#include "nm-core-internal.h" +#include "libnm-glib-aux/nm-str-buf.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-supplicant-settings-verify.h" #include "nm-setting.h" -#include "nm-libnm-core-intern/nm-auth-subject.h" +#include "libnm-core-aux-intern/nm-auth-subject.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" #include "nm-setting-ip4-config.h" @@ -334,11 +334,10 @@ nm_supplicant_config_to_variant(NMSupplicantConfig *self) break; case NM_SUPPL_OPT_TYPE_BYTES: case NM_SUPPL_OPT_TYPE_UTF8: - g_variant_builder_add( - &builder, - "{sv}", - key, - g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, option->value, option->len, 1)); + g_variant_builder_add(&builder, + "{sv}", + key, + nm_g_variant_new_ay((const guint8 *) option->value, option->len)); break; case NM_SUPPL_OPT_TYPE_KEYWORD: case NM_SUPPL_OPT_TYPE_STRING: @@ -667,8 +666,8 @@ add_string_val(NMSupplicantConfig *self, display_value, \ error) \ ({ \ - typeof(*(setting)) *_setting = (setting); \ - gboolean _success = TRUE; \ + typeof(setting) _setting = (setting); \ + gboolean _success = TRUE; \ \ if (nm_setting_##setting_name##_get_num_##field_plural(_setting)) { \ const char _separator = (separator); \ @@ -815,7 +814,7 @@ nm_supplicant_config_add_setting_wireless_security(NMSupplicantConfig * nm_auto_free_gstring GString *key_mgmt_conf = NULL; const char * key_mgmt, *auth_alg; const char * psk; - gboolean set_pmf; + gboolean set_pmf, wps_disabled; g_return_val_if_fail(NM_IS_SUPPLICANT_CONFIG(self), FALSE); g_return_val_if_fail(setting != NULL, FALSE); @@ -835,53 +834,82 @@ nm_supplicant_config_add_setting_wireless_security(NMSupplicantConfig * } key_mgmt = nm_setting_wireless_security_get_key_mgmt(setting); - key_mgmt_conf = g_string_new(key_mgmt); - if (nm_streq(key_mgmt, "wpa-psk")) { + key_mgmt_conf = g_string_new(""); + + if (nm_streq(key_mgmt, "none")) { + g_string_append(key_mgmt_conf, "NONE"); + + } else if (nm_streq(key_mgmt, "ieee8021x")) { + g_string_append(key_mgmt_conf, "IEEE8021X"); + + } else if (nm_streq(key_mgmt, "owe")) { + pmf = NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED; + + g_string_append(key_mgmt_conf, "OWE"); + + } else if (nm_streq(key_mgmt, "wpa-psk")) { + if (pmf != NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED) + g_string_append(key_mgmt_conf, "WPA-PSK"); if (_get_capability(priv, NM_SUPPL_CAP_TYPE_PMF)) - g_string_append(key_mgmt_conf, " wpa-psk-sha256"); + g_string_append(key_mgmt_conf, " WPA-PSK-SHA256"); if (_get_capability(priv, NM_SUPPL_CAP_TYPE_FT)) - g_string_append(key_mgmt_conf, " ft-psk"); + g_string_append(key_mgmt_conf, " FT-PSK"); + if (_get_capability(priv, NM_SUPPL_CAP_TYPE_SAE)) { + g_string_append(key_mgmt_conf, " SAE"); + if (_get_capability(priv, NM_SUPPL_CAP_TYPE_FT)) + g_string_append(key_mgmt_conf, " FT-SAE"); + } + + } else if (nm_streq(key_mgmt, "sae")) { + pmf = NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED; + + g_string_append(key_mgmt_conf, "SAE"); + if (_get_capability(priv, NM_SUPPL_CAP_TYPE_FT)) + g_string_append(key_mgmt_conf, " FT-SAE"); + } else if (nm_streq(key_mgmt, "wpa-eap")) { + if (pmf != NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED) + g_string_append(key_mgmt_conf, "WPA-EAP"); + if (_get_capability(priv, NM_SUPPL_CAP_TYPE_FT)) { + g_string_append(key_mgmt_conf, " FT-EAP"); + if (_get_capability(priv, NM_SUPPL_CAP_TYPE_SHA384)) + g_string_append(key_mgmt_conf, " FT-EAP-SHA384"); + } if (_get_capability(priv, NM_SUPPL_CAP_TYPE_PMF)) { - g_string_append(key_mgmt_conf, " wpa-eap-sha256"); - + g_string_append(key_mgmt_conf, " WPA-EAP-SHA256"); if (_get_capability(priv, NM_SUPPL_CAP_TYPE_SUITEB192) && pmf == NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED) - g_string_append(key_mgmt_conf, " wpa-eap-suite-b-192"); + g_string_append(key_mgmt_conf, " WPA-EAP-SUITE-B-192"); } - if (_get_capability(priv, NM_SUPPL_CAP_TYPE_FT)) - g_string_append(key_mgmt_conf, " ft-eap"); - if (_get_capability(priv, NM_SUPPL_CAP_TYPE_FT) - && _get_capability(priv, NM_SUPPL_CAP_TYPE_SHA384)) - g_string_append(key_mgmt_conf, " ft-eap-sha384"); + switch (fils) { case NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED: g_string_truncate(key_mgmt_conf, 0); if (!_get_capability(priv, NM_SUPPL_CAP_TYPE_PMF)) - g_string_assign(key_mgmt_conf, "fils-sha256 fils-sha384"); + g_string_assign(key_mgmt_conf, "FILS-SHA256 FILS-SHA384"); /* fall-through */ case NM_SETTING_WIRELESS_SECURITY_FILS_OPTIONAL: - if (_get_capability(priv, NM_SUPPL_CAP_TYPE_PMF)) - g_string_append(key_mgmt_conf, " fils-sha256 fils-sha384"); - if (_get_capability(priv, NM_SUPPL_CAP_TYPE_PMF) - && _get_capability(priv, NM_SUPPL_CAP_TYPE_FT)) - g_string_append(key_mgmt_conf, " ft-fils-sha256"); - if (_get_capability(priv, NM_SUPPL_CAP_TYPE_PMF) - && _get_capability(priv, NM_SUPPL_CAP_TYPE_FT) - && _get_capability(priv, NM_SUPPL_CAP_TYPE_SHA384)) - g_string_append(key_mgmt_conf, " ft-fils-sha384"); + if (_get_capability(priv, NM_SUPPL_CAP_TYPE_PMF)) { + g_string_append(key_mgmt_conf, " FILS-SHA256 FILS-SHA384"); + if (_get_capability(priv, NM_SUPPL_CAP_TYPE_FT)) { + g_string_append(key_mgmt_conf, " FT-FILS-SHA256"); + if (_get_capability(priv, NM_SUPPL_CAP_TYPE_SHA384)) + g_string_append(key_mgmt_conf, " FT-FILS-SHA384"); + } + } break; + default: break; } - } else if (nm_streq(key_mgmt, "sae")) { - if (_get_capability(priv, NM_SUPPL_CAP_TYPE_FT)) - g_string_append(key_mgmt_conf, " ft-sae"); + } else if (nm_streq(key_mgmt, "wpa-eap-suite-b-192")) { pmf = NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED; - if (!nm_supplicant_config_add_option(self, "pairwise", "GCMP-256", -1, NULL, error) - || !nm_supplicant_config_add_option(self, "group", "GCMP-256", -1, NULL, error)) - return FALSE; + + g_string_append(key_mgmt_conf, "WPA-EAP-SUITE-B-192"); + if (_get_capability(priv, NM_SUPPL_CAP_TYPE_FT) + && _get_capability(priv, NM_SUPPL_CAP_TYPE_SHA384)) + g_string_append(key_mgmt_conf, " FT-EAP-SHA384"); } if (!add_string_val(self, key_mgmt_conf->str, "key_mgmt", TRUE, NULL, error)) @@ -950,10 +978,6 @@ nm_supplicant_config_add_setting_wireless_security(NMSupplicantConfig * } } - /* Don't try to enable PMF on non-WPA/SAE/OWE networks */ - if (!NM_IN_STRSET(key_mgmt, "wpa-eap", "wpa-eap-suite-b-192", "wpa-psk", "sae", "owe")) - pmf = NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE; - /* Check if we actually support PMF */ set_pmf = TRUE; if (!_get_capability(priv, NM_SUPPL_CAP_TYPE_PMF)) { @@ -968,7 +992,7 @@ nm_supplicant_config_add_setting_wireless_security(NMSupplicantConfig * } /* Only WPA-specific things when using WPA */ - if (NM_IN_STRSET(key_mgmt, "wpa-psk", "wpa-eap", "sae", "owe")) { + if (NM_IN_STRSET(key_mgmt, "owe", "wpa-psk", "sae", "wpa-eap", "wpa-eap-suite-b-192")) { if (!ADD_STRING_LIST_VAL(self, setting, wireless_security, @@ -980,29 +1004,40 @@ nm_supplicant_config_add_setting_wireless_security(NMSupplicantConfig * NULL, error)) return FALSE; - if (!ADD_STRING_LIST_VAL(self, - setting, - wireless_security, - pairwise, - pairwise, - "pairwise", - ' ', - TRUE, - NULL, - error)) - return FALSE; - if (!ADD_STRING_LIST_VAL(self, - setting, - wireless_security, - group, - groups, - "group", - ' ', - TRUE, - NULL, - error)) - return FALSE; + if (nm_streq(key_mgmt, "wpa-eap-suite-b-192")) { + if (!nm_supplicant_config_add_option(self, "pairwise", "GCMP-256", -1, NULL, error)) + return FALSE; + if (!nm_supplicant_config_add_option(self, "group", "GCMP-256", -1, NULL, error)) + return FALSE; + } else { + if (!ADD_STRING_LIST_VAL(self, + setting, + wireless_security, + pairwise, + pairwise, + "pairwise", + ' ', + TRUE, + NULL, + error)) + return FALSE; + if (!ADD_STRING_LIST_VAL(self, + setting, + wireless_security, + group, + groups, + "group", + ' ', + TRUE, + NULL, + error)) + return FALSE; + } + + /* We set the supplicants global "pmf" config value to "1" (optional), + * so no need to set it network-specific again if PMF_OPTIONAL is set. + */ if (set_pmf && NM_IN_SET(pmf, NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE, @@ -1102,6 +1137,13 @@ nm_supplicant_config_add_setting_wireless_security(NMSupplicantConfig * } } + wps_disabled = (nm_setting_wireless_security_get_wps_method(setting) + == NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_DISABLED); + if (wps_disabled) { + if (!nm_supplicant_config_add_option(self, "wps_disabled", "1", 1, NULL, error)) + return FALSE; + } + return TRUE; } diff --git a/src/core/supplicant/nm-supplicant-interface.c b/src/core/supplicant/nm-supplicant-interface.c index 6d9c604f..1556e290 100644 --- a/src/core/supplicant/nm-supplicant-interface.c +++ b/src/core/supplicant/nm-supplicant-interface.c @@ -12,13 +12,13 @@ #include #include "NetworkManagerUtils.h" -#include "nm-core-internal.h" -#include "nm-glib-aux/nm-c-list.h" -#include "nm-glib-aux/nm-ref-string.h" -#include "nm-std-aux/nm-dbus-compat.h" +#include "libnm-core-intern/nm-core-internal.h" +#include "libnm-glib-aux/nm-c-list.h" +#include "libnm-glib-aux/nm-ref-string.h" +#include "libnm-glib-aux/nm-dbus-aux.h" +#include "libnm-std-aux/nm-dbus-compat.h" #include "nm-supplicant-config.h" #include "nm-supplicant-manager.h" -#include "shared/nm-glib-aux/nm-dbus-aux.h" #define DBUS_TIMEOUT_MSEC 20000 @@ -267,30 +267,41 @@ security_from_vardict(GVariant *security) NM80211ApSecurityFlags flags = NM_802_11_AP_SEC_NONE; const char ** array; const char * tmp; + gsize i; + const char * v; nm_assert(g_variant_is_of_type(security, G_VARIANT_TYPE_VARDICT)); if (g_variant_lookup(security, "KeyMgmt", "^a&s", &array)) { - if (g_strv_contains(array, "wpa-psk") || g_strv_contains(array, "wpa-ft-psk")) - flags |= NM_802_11_AP_SEC_KEY_MGMT_PSK; - if (g_strv_contains(array, "wpa-eap") || g_strv_contains(array, "wpa-ft-eap") - || g_strv_contains(array, "wpa-fils-sha256") - || g_strv_contains(array, "wpa-fils-sha384")) - flags |= NM_802_11_AP_SEC_KEY_MGMT_802_1X; - if (g_strv_contains(array, "sae")) - flags |= NM_802_11_AP_SEC_KEY_MGMT_SAE; - if (g_strv_contains(array, "owe")) - flags |= NM_802_11_AP_SEC_KEY_MGMT_OWE; - if (g_strv_contains(array, "wpa-eap-suite-b-192")) - flags |= NM_802_11_AP_SEC_KEY_MGMT_EAP_SUITE_B_192; + for (i = 0; (v = array[i]); i++) { + if (NM_IN_STRSET(v, "wpa-psk", "wpa-psk-sha256", "wpa-ft-psk")) + flags |= NM_802_11_AP_SEC_KEY_MGMT_PSK; + else if (NM_IN_STRSET(v, + "wpa-eap", + "wpa-eap-sha256", + "wpa-ft-eap", + "wpa-fils-sha256", + "wpa-fils-sha384", + "wpa-fils-ft-sha256", + "wpa-fils-ft-sha384")) + flags |= NM_802_11_AP_SEC_KEY_MGMT_802_1X; + else if (NM_IN_STRSET(v, "sae", "ft-sae")) + flags |= NM_802_11_AP_SEC_KEY_MGMT_SAE; + else if (NM_IN_STRSET(v, "owe")) + flags |= NM_802_11_AP_SEC_KEY_MGMT_OWE; + else if (NM_IN_STRSET(v, "wpa-eap-suite-b-192", "wpa-ft-eap-sha384")) + flags |= NM_802_11_AP_SEC_KEY_MGMT_EAP_SUITE_B_192; + } g_free(array); } if (g_variant_lookup(security, "Pairwise", "^a&s", &array)) { - if (g_strv_contains(array, "tkip")) - flags |= NM_802_11_AP_SEC_PAIR_TKIP; - if (g_strv_contains(array, "ccmp")) - flags |= NM_802_11_AP_SEC_PAIR_CCMP; + for (i = 0; (v = array[i]); i++) { + if (NM_IN_STRSET(v, "tkip")) + flags |= NM_802_11_AP_SEC_PAIR_TKIP; + else if (NM_IN_STRSET(v, "ccmp")) + flags |= NM_802_11_AP_SEC_PAIR_CCMP; + } g_free(array); } @@ -359,8 +370,12 @@ _dbus_connection_call_simple_cb(GObject *source, GAsyncResult *result, gpointer gs_free_error GError *error = NULL; const char * log_reason; gs_free char * remote_error = NULL; + gpointer p_suppress_warning; + gboolean suppress_warning; + + nm_utils_user_data_unpack(user_data, &self, &log_reason, &p_suppress_warning); - nm_utils_user_data_unpack(user_data, &self, &log_reason); + suppress_warning = GPOINTER_TO_INT(p_suppress_warning); res = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error); if (nm_utils_error_is_cancelled(error)) @@ -371,37 +386,70 @@ _dbus_connection_call_simple_cb(GObject *source, GAsyncResult *result, gpointer return; } - remote_error = g_dbus_error_get_remote_error(error); - if (!nm_streq0(remote_error, "fi.w1.wpa_supplicant1.NotConnected")) { - g_dbus_error_strip_remote_error(error); - _LOGW("call-%s: failed with %s", log_reason, error->message); - return; + if (!suppress_warning) { + remote_error = g_dbus_error_get_remote_error(error); + if (!nm_streq0(remote_error, "fi.w1.wpa_supplicant1.NotConnected")) { + g_dbus_error_strip_remote_error(error); + _LOGW("call-%s: failed with %s", log_reason, error->message); + return; + } } _LOGT("call-%s: failed with %s", log_reason, error->message); } static void -_dbus_connection_call_simple(NMSupplicantInterface *self, - const char * interface_name, - const char * method_name, - GVariant * parameters, - const GVariantType * reply_type, - const char * log_reason) +_dbus_connection_call_simple_full_impl(NMSupplicantInterface *self, + const char * interface_name, + const char * method_name, + GVariant * parameters, + const GVariantType * reply_type, + const char * log_reason, + gboolean suppress_warning) { NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self); - _dbus_connection_call(self, - interface_name, - method_name, - parameters, - reply_type, - G_DBUS_CALL_FLAGS_NONE, - DBUS_TIMEOUT_MSEC, - priv->main_cancellable, - _dbus_connection_call_simple_cb, - nm_utils_user_data_pack(self, log_reason)); -} + _dbus_connection_call( + self, + interface_name, + method_name, + parameters, + reply_type, + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT_MSEC, + priv->main_cancellable, + _dbus_connection_call_simple_cb, + nm_utils_user_data_pack(self, log_reason, GINT_TO_POINTER(suppress_warning))); +} + +#define _dbus_connection_call_simple_full(self, \ + interface_name, \ + method_name, \ + parameters, \ + reply_type, \ + log_reason, \ + suppress_warning) \ + _dbus_connection_call_simple_full_impl((self), \ + (interface_name), \ + (method_name), \ + (parameters), \ + (reply_type), \ + "" log_reason "", \ + (suppress_warning)) + +#define _dbus_connection_call_simple(self, \ + interface_name, \ + method_name, \ + parameters, \ + reply_type, \ + log_reason) \ + _dbus_connection_call_simple_full_impl((self), \ + (interface_name), \ + (method_name), \ + (parameters), \ + (reply_type), \ + "" log_reason "", \ + FALSE) /*****************************************************************************/ @@ -557,7 +605,7 @@ _bss_info_properties_changed(NMSupplicantInterface *self, guint16 v_u16; guint32 v_u32; NM80211ApFlags p_ap_flags; - NM80211Mode p_mode; + _NM80211Mode p_mode; guint8 p_signal_percent; const guint8 * arr_data; gsize arr_len; @@ -586,7 +634,7 @@ _bss_info_properties_changed(NMSupplicantInterface *self, if (v_v) { if (g_variant_lookup(v_v, "Type", "&s", &v_s)) { f = NM_802_11_AP_FLAGS_WPS; - if (nm_streq(v_s, "pcb")) + if (nm_streq(v_s, "pbc")) f |= NM_802_11_AP_FLAGS_WPS_PBC; else if (nm_streq(v_s, "pin")) f |= NM_802_11_AP_FLAGS_WPS_PIN; @@ -605,15 +653,15 @@ _bss_info_properties_changed(NMSupplicantInterface *self, if (nm_g_variant_lookup(properties, "Mode", "&s", &v_s)) { if (nm_streq(v_s, "infrastructure")) - p_mode = NM_802_11_MODE_INFRA; + p_mode = _NM_802_11_MODE_INFRA; else if (nm_streq(v_s, "ad-hoc")) - p_mode = NM_802_11_MODE_ADHOC; + p_mode = _NM_802_11_MODE_ADHOC; else if (nm_streq(v_s, "mesh")) - p_mode = NM_802_11_MODE_MESH; + p_mode = _NM_802_11_MODE_MESH; else - p_mode = NM_802_11_MODE_UNKNOWN; + p_mode = _NM_802_11_MODE_UNKNOWN; } else if (initial) - p_mode = NM_802_11_MODE_UNKNOWN; + p_mode = _NM_802_11_MODE_UNKNOWN; else p_mode = bss_info->mode; if (bss_info->mode != p_mode) { @@ -1171,19 +1219,24 @@ parse_capabilities(NMSupplicantInterface *self, GVariant *capabilities) const gboolean old_prop_scan_ssid = priv->prop_scan_ssid; const guint32 old_max_scan_ssids = priv->max_scan_ssids; gboolean have_ft = FALSE; + gboolean have_sae = FALSE; gint32 max_scan_ssids; const char ** array; nm_assert(capabilities && g_variant_is_of_type(capabilities, G_VARIANT_TYPE_VARDICT)); if (g_variant_lookup(capabilities, "KeyMgmt", "^a&s", &array)) { - have_ft = g_strv_contains(array, "wpa-ft-psk"); + have_ft = g_strv_contains(array, "wpa-ft-psk"); + have_sae = g_strv_contains(array, "sae"); g_free(array); } priv->iface_capabilities = NM_SUPPL_CAP_MASK_SET(priv->iface_capabilities, NM_SUPPL_CAP_TYPE_FT, have_ft ? NM_TERNARY_TRUE : NM_TERNARY_FALSE); + priv->iface_capabilities = NM_SUPPL_CAP_MASK_SET(priv->iface_capabilities, + NM_SUPPL_CAP_TYPE_SAE, + have_sae ? NM_TERNARY_TRUE : NM_TERNARY_FALSE); if (g_variant_lookup(capabilities, "Modes", "^a&s", &array)) { /* Setting p2p_capable might toggle _prop_p2p_available_get(). However, @@ -1255,6 +1308,15 @@ _starting_check_ready(NMSupplicantInterface *self) return; } + _LOGD("interface supported features:" + " AP%c" + " FT%c" + " SAE%c" + "", + NM_SUPPL_CAP_TO_CHAR(priv->iface_capabilities, NM_SUPPL_CAP_TYPE_AP), + NM_SUPPL_CAP_TO_CHAR(priv->iface_capabilities, NM_SUPPL_CAP_TYPE_FT), + NM_SUPPL_CAP_TO_CHAR(priv->iface_capabilities, NM_SUPPL_CAP_TYPE_SAE)); + set_state(self, priv->supp_state); } @@ -1278,6 +1340,10 @@ _get_capability(NMSupplicantInterfacePrivate *priv, NMSupplCapType type) value = iface_value; } break; + case NM_SUPPL_CAP_TYPE_SAE: + nm_assert(NM_SUPPL_CAP_MASK_GET(priv->global_capabilities, type) == NM_TERNARY_DEFAULT); + value = NM_SUPPL_CAP_MASK_GET(priv->iface_capabilities, type); + break; default: nm_assert(NM_SUPPL_CAP_MASK_GET(priv->iface_capabilities, type) == NM_TERNARY_DEFAULT); value = NM_SUPPL_CAP_MASK_GET(priv->global_capabilities, type); @@ -1305,9 +1371,13 @@ nm_supplicant_interface_get_capabilities(NMSupplicantInterface *self) caps = NM_SUPPL_CAP_MASK_SET(caps, NM_SUPPL_CAP_TYPE_FT, _get_capability(priv, NM_SUPPL_CAP_TYPE_FT)); + caps = NM_SUPPL_CAP_MASK_SET(caps, + NM_SUPPL_CAP_TYPE_SAE, + _get_capability(priv, NM_SUPPL_CAP_TYPE_SAE)); nm_assert(!NM_FLAGS_ANY(priv->iface_capabilities, - ~(NM_SUPPL_CAP_MASK_T_AP_MASK | NM_SUPPL_CAP_MASK_T_FT_MASK))); + ~(NM_SUPPL_CAP_MASK_T_AP_MASK | NM_SUPPL_CAP_MASK_T_FT_MASK + | NM_SUPPL_CAP_MASK_T_SAE_MASK))); #if NM_MORE_ASSERTS > 10 { @@ -1597,11 +1667,10 @@ _wps_handle_set_pc_cb(GVariant *res, GError *error, gpointer user_data) * enroll with any BSS in range. */ if (!nm_utils_hwaddr_aton(wps_data->bssid, bssid_buf, sizeof(bssid_buf))) nm_assert_not_reached(); - g_variant_builder_add( - &start_args, - "{sv}", - "Bssid", - g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, bssid_buf, ETH_ALEN, sizeof(guint8))); + g_variant_builder_add(&start_args, + "{sv}", + "Bssid", + nm_g_variant_new_ay(bssid_buf, ETH_ALEN)); } wps_data->needs_cancelling = TRUE; @@ -1879,7 +1948,7 @@ _properties_changed_main(NMSupplicantInterface *self, GVariant *properties) if (nm_g_variant_lookup(properties, "CurrentBSS", "&o", &v_s)) { v_s = nm_dbus_path_not_empty(v_s); - if (!nm_ref_string_equals_str(priv->current_bss, v_s)) { + if (!nm_ref_string_equal_str(priv->current_bss, v_s)) { nm_ref_string_unref(priv->current_bss); priv->current_bss = nm_ref_string_new(v_s); do_notify_current_bss = TRUE; @@ -2699,12 +2768,13 @@ nm_supplicant_interface_p2p_cancel_connect(NMSupplicantInterface *self) { g_return_if_fail(NM_IS_SUPPLICANT_INTERFACE(self)); - _dbus_connection_call_simple(self, - NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE, - "Cancel", - NULL, - G_VARIANT_TYPE("()"), - "p2p-cancel"); + _dbus_connection_call_simple_full(self, + NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE, + "Cancel", + NULL, + G_VARIANT_TYPE("()"), + "p2p-cancel", + TRUE); } void diff --git a/src/core/supplicant/nm-supplicant-manager.c b/src/core/supplicant/nm-supplicant-manager.c index 32554187..e432889b 100644 --- a/src/core/supplicant/nm-supplicant-manager.c +++ b/src/core/supplicant/nm-supplicant-manager.c @@ -8,13 +8,13 @@ #include "nm-supplicant-manager.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-dbus-manager.h" -#include "nm-glib-aux/nm-dbus-aux.h" -#include "nm-glib-aux/nm-ref-string.h" +#include "libnm-glib-aux/nm-dbus-aux.h" +#include "libnm-glib-aux/nm-ref-string.h" #include "nm-supplicant-interface.h" #include "nm-supplicant-types.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" /*****************************************************************************/ @@ -168,19 +168,6 @@ _caps_set(NMSupplicantManagerPrivate *priv, NMSupplCapType type, NMTernary value priv->capabilities = NM_SUPPL_CAP_MASK_SET(priv->capabilities, type, value); } -static char -_caps_to_char(NMSupplicantManagerPrivate *priv, NMSupplCapType type) -{ - NMTernary val; - - val = NM_SUPPL_CAP_MASK_GET(priv->capabilities, type); - if (val == NM_TERNARY_TRUE) - return '+'; - if (val == NM_TERNARY_FALSE) - return '-'; - return '?'; -} - /*****************************************************************************/ static void @@ -395,7 +382,7 @@ _create_iface_complete(NMSupplMgrCreateIfaceHandle *handle, nm_clear_g_cancellable(&handle->cancellable); nm_ref_string_unref(handle->name_owner); - nm_g_slice_free_fcn(handle); + nm_g_slice_free(handle); } static void @@ -1008,15 +995,15 @@ _dbus_get_capabilities_cb(GVariant *res, GError *error, gpointer user_data) " FAST%c" " WFD%c" "", - _caps_to_char(priv, NM_SUPPL_CAP_TYPE_AP), - _caps_to_char(priv, NM_SUPPL_CAP_TYPE_PMF), - _caps_to_char(priv, NM_SUPPL_CAP_TYPE_FILS), - _caps_to_char(priv, NM_SUPPL_CAP_TYPE_P2P), - _caps_to_char(priv, NM_SUPPL_CAP_TYPE_FT), - _caps_to_char(priv, NM_SUPPL_CAP_TYPE_SHA384), - _caps_to_char(priv, NM_SUPPL_CAP_TYPE_MESH), - _caps_to_char(priv, NM_SUPPL_CAP_TYPE_FAST), - _caps_to_char(priv, NM_SUPPL_CAP_TYPE_WFD)); + NM_SUPPL_CAP_TO_CHAR(priv->capabilities, NM_SUPPL_CAP_TYPE_AP), + NM_SUPPL_CAP_TO_CHAR(priv->capabilities, NM_SUPPL_CAP_TYPE_PMF), + NM_SUPPL_CAP_TO_CHAR(priv->capabilities, NM_SUPPL_CAP_TYPE_FILS), + NM_SUPPL_CAP_TO_CHAR(priv->capabilities, NM_SUPPL_CAP_TYPE_P2P), + NM_SUPPL_CAP_TO_CHAR(priv->capabilities, NM_SUPPL_CAP_TYPE_FT), + NM_SUPPL_CAP_TO_CHAR(priv->capabilities, NM_SUPPL_CAP_TYPE_SHA384), + NM_SUPPL_CAP_TO_CHAR(priv->capabilities, NM_SUPPL_CAP_TYPE_MESH), + NM_SUPPL_CAP_TO_CHAR(priv->capabilities, NM_SUPPL_CAP_TYPE_FAST), + NM_SUPPL_CAP_TO_CHAR(priv->capabilities, NM_SUPPL_CAP_TYPE_WFD)); nm_assert(g_hash_table_size(priv->supp_ifaces) == 0); nm_assert(c_list_is_empty(&priv->supp_lst_head)); diff --git a/src/core/supplicant/nm-supplicant-settings-verify.c b/src/core/supplicant/nm-supplicant-settings-verify.c index 3f0a33e0..5e77b207 100644 --- a/src/core/supplicant/nm-supplicant-settings-verify.c +++ b/src/core/supplicant/nm-supplicant-settings-verify.c @@ -144,6 +144,7 @@ static const struct Opt opt_table[] = { OPT_BYTES("wep_key2", 0), OPT_BYTES("wep_key3", 0), OPT_INT("wep_tx_keyidx", 0, 3), + OPT_INT("wps_disabled", 0, 1), }; static gboolean diff --git a/src/core/supplicant/nm-supplicant-types.h b/src/core/supplicant/nm-supplicant-types.h index adcf02db..c9b72de1 100644 --- a/src/core/supplicant/nm-supplicant-types.h +++ b/src/core/supplicant/nm-supplicant-types.h @@ -7,6 +7,7 @@ #define __NETWORKMANAGER_SUPPLICANT_TYPES_H__ #include "c-list/src/c-list.h" +#include "libnm-base/nm-base.h" #define NM_WPAS_DBUS_SERVICE "fi.w1.wpa_supplicant1" #define NM_WPAS_DBUS_PATH "/fi/w1/wpa_supplicant1" @@ -41,6 +42,7 @@ typedef enum { NM_SUPPL_CAP_TYPE_FILS, NM_SUPPL_CAP_TYPE_P2P, NM_SUPPL_CAP_TYPE_FT, + NM_SUPPL_CAP_TYPE_SAE, NM_SUPPL_CAP_TYPE_SHA384, NM_SUPPL_CAP_TYPE_MESH, NM_SUPPL_CAP_TYPE_FAST, @@ -49,9 +51,9 @@ typedef enum { _NM_SUPPL_CAP_TYPE_NUM, } NMSupplCapType; -#define NM_SUPPL_CAP_MASK_NO(type) ((NMSupplCapMask)(1llu << ((type) *2u))) -#define NM_SUPPL_CAP_MASK_YES(type) ((NMSupplCapMask)(2llu << ((type) *2u))) -#define NM_SUPPL_CAP_MASK_MASK(type) ((NMSupplCapMask)(3llu << ((type) *2u))) +#define NM_SUPPL_CAP_MASK_NO(type) ((NMSupplCapMask) (1llu << ((type) *2u))) +#define NM_SUPPL_CAP_MASK_YES(type) ((NMSupplCapMask) (2llu << ((type) *2u))) +#define NM_SUPPL_CAP_MASK_MASK(type) ((NMSupplCapMask) (3llu << ((type) *2u))) typedef enum { NM_SUPPL_CAP_MASK_NONE = 0, @@ -71,6 +73,7 @@ typedef enum { _NM_SUPPL_CAP_MASK_DEFINE(MESH), _NM_SUPPL_CAP_MASK_DEFINE(WFD), _NM_SUPPL_CAP_MASK_DEFINE(FT), + _NM_SUPPL_CAP_MASK_DEFINE(SAE), _NM_SUPPL_CAP_MASK_DEFINE(SHA384), #undef _NM_SUPPL_CAP_MASK_DEFINE } NMSupplCapMask; @@ -111,7 +114,20 @@ NM_SUPPL_CAP_MASK_GET(NMSupplCapMask features, NMSupplCapType type) nm_assert(NM_IN_SET(f, 0, 1, 2)); - return (NMTernary)(f - 1); + return (NMTernary) (f - 1); +} + +static inline char +NM_SUPPL_CAP_TO_CHAR(NMSupplCapMask features, NMSupplCapType type) +{ + NMTernary val; + + val = NM_SUPPL_CAP_MASK_GET(features, type); + if (val == NM_TERNARY_TRUE) + return '+'; + if (val == NM_TERNARY_FALSE) + return '-'; + return '?'; } /*****************************************************************************/ @@ -163,7 +179,7 @@ typedef struct _NMSupplicantBssInfo { NM80211ApFlags ap_flags : 5; - NM80211Mode mode : 4; + _NM80211Mode mode : 4; bool bssid_valid : 1; diff --git a/src/core/supplicant/tests/test-supplicant-config.c b/src/core/supplicant/tests/test-supplicant-config.c index 99729c18..0cf35d0e 100644 --- a/src/core/supplicant/tests/test-supplicant-config.c +++ b/src/core/supplicant/tests/test-supplicant-config.c @@ -14,7 +14,7 @@ #include #include -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "supplicant/nm-supplicant-config.h" #include "supplicant/nm-supplicant-settings-verify.h" @@ -394,7 +394,17 @@ test_wifi_wpa_psk(const char * detail, NMTST_EXPECT_NM_INFO("Config: added 'scan_ssid' value '1'*"); NMTST_EXPECT_NM_INFO("Config: added 'bssid' value '11:22:33:44:55:66'*"); NMTST_EXPECT_NM_INFO("Config: added 'freq_list' value *"); - NMTST_EXPECT_NM_INFO("Config: added 'key_mgmt' value 'WPA-PSK WPA-PSK-SHA256'"); + switch (pmf) { + case NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE: + case NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL: + NMTST_EXPECT_NM_INFO("Config: added 'key_mgmt' value 'WPA-PSK WPA-PSK-SHA256'"); + break; + case NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED: + NMTST_EXPECT_NM_INFO("Config: added 'key_mgmt' value ' WPA-PSK-SHA256'"); + break; + default: + break; + } NMTST_EXPECT_NM_INFO("Config: added 'psk' value *"); NMTST_EXPECT_NM_INFO("Config: added 'proto' value 'WPA RSN'"); NMTST_EXPECT_NM_INFO("Config: added 'pairwise' value 'TKIP CCMP'"); @@ -421,11 +431,22 @@ test_wifi_wpa_psk(const char * detail, validate_opt(detail, config_dict, "scan_ssid", NM_SUPPL_OPT_TYPE_INT, GINT_TO_POINTER(1)); validate_opt(detail, config_dict, "ssid", NM_SUPPL_OPT_TYPE_BYTES, ssid); validate_opt(detail, config_dict, "bssid", NM_SUPPL_OPT_TYPE_KEYWORD, bssid_str); - validate_opt(detail, - config_dict, - "key_mgmt", - NM_SUPPL_OPT_TYPE_KEYWORD, - "WPA-PSK WPA-PSK-SHA256"); + switch (pmf) { + case NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE: + case NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL: + validate_opt(detail, + config_dict, + "key_mgmt", + NM_SUPPL_OPT_TYPE_KEYWORD, + "WPA-PSK WPA-PSK-SHA256"); + break; + case NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED: + validate_opt(detail, config_dict, "key_mgmt", NM_SUPPL_OPT_TYPE_KEYWORD, " WPA-PSK-SHA256"); + break; + default: + break; + } + validate_opt(detail, config_dict, "proto", NM_SUPPL_OPT_TYPE_KEYWORD, "WPA RSN"); validate_opt(detail, config_dict, "pairwise", NM_SUPPL_OPT_TYPE_KEYWORD, "TKIP CCMP"); validate_opt(detail, config_dict, "group", NM_SUPPL_OPT_TYPE_KEYWORD, "TKIP CCMP"); @@ -483,6 +504,7 @@ test_wifi_sae_psk(const char *psk) NMTST_EXPECT_NM_INFO("Config: added 'proto' value 'RSN'"); NMTST_EXPECT_NM_INFO("Config: added 'pairwise' value 'TKIP CCMP'"); NMTST_EXPECT_NM_INFO("Config: added 'group' value 'TKIP CCMP'"); + NMTST_EXPECT_NM_INFO("Config: added 'ieee80211w' value '2'"); config_dict = build_supplicant_config(connection, 1500, @@ -815,9 +837,10 @@ test_wifi_eap_suite_b_generation(void) NMTST_EXPECT_NM_INFO("Config: added 'scan_ssid' value '1'*"); NMTST_EXPECT_NM_INFO("Config: added 'bssid' value '11:22:33:44:55:66'*"); NMTST_EXPECT_NM_INFO("Config: added 'freq_list' value *"); + NMTST_EXPECT_NM_INFO("Config: added 'key_mgmt' value 'WPA-EAP-SUITE-B-192'"); NMTST_EXPECT_NM_INFO("Config: added 'pairwise' value 'GCMP-256'"); NMTST_EXPECT_NM_INFO("Config: added 'group' value 'GCMP-256'"); - NMTST_EXPECT_NM_INFO("Config: added 'key_mgmt' value 'WPA-EAP-SUITE-B-192'"); + NMTST_EXPECT_NM_INFO("Config: added 'ieee80211w' value '2'"); NMTST_EXPECT_NM_INFO("Config: added 'eap' value 'TLS'"); NMTST_EXPECT_NM_INFO("Config: added 'fragment_size' value '1086'"); NMTST_EXPECT_NM_INFO("Config: added 'ca_cert' value '*/test-ca-cert.pem'"); diff --git a/src/core/systemd/meson.build b/src/core/systemd/meson.build deleted file mode 100644 index 70f6b542..00000000 --- a/src/core/systemd/meson.build +++ /dev/null @@ -1,62 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later - -incs = include_directories( - 'sd-adapt-core', - 'src/libsystemd-network', - 'src/libsystemd/sd-event', - 'src/systemd', -) - -libnm_systemd_core = static_library( - 'nm-systemd-core', - sources: files( - 'src/libsystemd-network/arp-util.c', - 'src/libsystemd-network/dhcp-identifier.c', - 'src/libsystemd-network/dhcp-network.c', - 'src/libsystemd-network/dhcp-option.c', - 'src/libsystemd-network/dhcp-packet.c', - 'src/libsystemd-network/dhcp6-network.c', - 'src/libsystemd-network/dhcp6-option.c', - 'src/libsystemd-network/lldp-neighbor.c', - 'src/libsystemd-network/lldp-network.c', - 'src/libsystemd-network/network-internal.c', - 'src/libsystemd-network/sd-dhcp-client.c', - 'src/libsystemd-network/sd-dhcp-lease.c', - 'src/libsystemd-network/sd-dhcp6-client.c', - 'src/libsystemd-network/sd-dhcp6-lease.c', - 'src/libsystemd-network/sd-ipv4acd.c', - 'src/libsystemd-network/sd-ipv4ll.c', - 'src/libsystemd-network/sd-lldp.c', - 'src/libsystemd/sd-event/event-util.c', - 'src/libsystemd/sd-event/sd-event.c', - 'src/libsystemd/sd-id128/id128-util.c', - 'src/libsystemd/sd-id128/sd-id128.c', - 'nm-sd.c', - 'nm-sd-utils-core.c', - 'nm-sd-utils-dhcp.c', - 'sd-adapt-core/nm-sd-adapt-core.c', - ), - include_directories: [ - incs, - src_inc, - ], - dependencies: [ - glib_nm_default_dep, - libnm_core_dep, - libnm_systemd_shared_dep, - ], - c_args: [ - '-DG_LOG_DOMAIN="NetworkManager"', - ], - link_with: libc_siphash, -) - -libnm_systemd_core_dep = declare_dependency( - include_directories: incs, - dependencies: [ - glib_dep, - libnm_core_dep, - libnm_systemd_shared_dep, - ], - link_with: libnm_systemd_core, -) diff --git a/src/core/systemd/nm-default-systemd.h b/src/core/systemd/nm-default-systemd.h deleted file mode 100644 index 1979d9c9..00000000 --- a/src/core/systemd/nm-default-systemd.h +++ /dev/null @@ -1,18 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2015 Red Hat, Inc. - */ - -#ifndef __NM_DEFAULT_SYSTEMD_H__ -#define __NM_DEFAULT_SYSTEMD_H__ - -/*****************************************************************************/ - -#include "nm-default-daemon.h" - -#undef NETWORKMANAGER_COMPILATION -#define NETWORKMANAGER_COMPILATION NM_NETWORKMANAGER_COMPILATION_SYSTEMD - -/*****************************************************************************/ - -#endif /* __NM_DEFAULT_SYSTEMD_H__ */ diff --git a/src/core/systemd/nm-sd-utils-core.c b/src/core/systemd/nm-sd-utils-core.c deleted file mode 100644 index af68603e..00000000 --- a/src/core/systemd/nm-sd-utils-core.c +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2018 Red Hat, Inc. - */ - -#include "src/core/systemd/nm-default-systemd.h" - -#include "nm-sd-utils-core.h" - -#include "nm-core-internal.h" - -#include "nm-sd-adapt-core.h" - -#include "sd-id128.h" - -/*****************************************************************************/ - -NMUuid * -nm_sd_utils_id128_get_machine(NMUuid *out_uuid) -{ - g_assert(out_uuid); - - G_STATIC_ASSERT_EXPR(sizeof(*out_uuid) == sizeof(sd_id128_t)); - if (sd_id128_get_machine((sd_id128_t *) out_uuid) < 0) - return NULL; - return out_uuid; -} diff --git a/src/core/systemd/nm-sd-utils-core.h b/src/core/systemd/nm-sd-utils-core.h deleted file mode 100644 index ccad0029..00000000 --- a/src/core/systemd/nm-sd-utils-core.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2018 Red Hat, Inc. - */ - -#ifndef __NM_SD_UTILS_CORE_H__ -#define __NM_SD_UTILS_CORE_H__ - -/*****************************************************************************/ - -struct _NMUuid; - -struct _NMUuid *nm_sd_utils_id128_get_machine(struct _NMUuid *out_uuid); - -/*****************************************************************************/ - -#endif /* __NM_SD_UTILS_CORE_H__ */ diff --git a/src/core/systemd/nm-sd-utils-dhcp.c b/src/core/systemd/nm-sd-utils-dhcp.c deleted file mode 100644 index b5aa315a..00000000 --- a/src/core/systemd/nm-sd-utils-dhcp.c +++ /dev/null @@ -1,41 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2019 Red Hat, Inc. - */ - -#include "src/core/systemd/nm-default-systemd.h" - -#include "nm-sd-utils-dhcp.h" - -#include "sd-adapt-core/nm-sd-adapt-core.h" -#include "src/libsystemd-network/dhcp-lease-internal.h" - -int -nm_sd_dhcp_lease_get_private_options(sd_dhcp_lease *lease, nm_sd_dhcp_option **out_options) -{ - struct sd_dhcp_raw_option *raw_option; - int cnt = 0; - - g_return_val_if_fail(lease, -EINVAL); - g_return_val_if_fail(out_options, -EINVAL); - g_return_val_if_fail(*out_options == NULL, -EINVAL); - - if (lease->private_options == NULL) - return -ENODATA; - - LIST_FOREACH(options, raw_option, lease->private_options) - cnt++; - - *out_options = g_new(nm_sd_dhcp_option, cnt); - cnt = 0; - - LIST_FOREACH(options, raw_option, lease->private_options) - { - (*out_options)[cnt].code = raw_option->tag; - (*out_options)[cnt].data = raw_option->data; - (*out_options)[cnt].data_len = raw_option->length; - cnt++; - } - - return cnt; -} diff --git a/src/core/systemd/nm-sd-utils-dhcp.h b/src/core/systemd/nm-sd-utils-dhcp.h deleted file mode 100644 index 5d126d5b..00000000 --- a/src/core/systemd/nm-sd-utils-dhcp.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2019 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DHCP_SYSTEMD_UTILS_H__ -#define __NETWORKMANAGER_DHCP_SYSTEMD_UTILS_H__ - -#include "nm-sd.h" - -typedef struct { - uint8_t code; - uint8_t data_len; - void * data; -} nm_sd_dhcp_option; - -int nm_sd_dhcp_lease_get_private_options(sd_dhcp_lease *lease, nm_sd_dhcp_option **out_options); - -#endif /* __NETWORKMANAGER_DHCP_SYSTEMD_UTILS_H__ */ diff --git a/src/core/systemd/nm-sd.c b/src/core/systemd/nm-sd.c deleted file mode 100644 index 11f3abbd..00000000 --- a/src/core/systemd/nm-sd.c +++ /dev/null @@ -1,113 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2014 - 2016 Red Hat, Inc. - */ - -#include "src/core/systemd/nm-default-systemd.h" - -#include "nm-sd.h" - -#include "sd-event.h" - -/***************************************************************************** - * Integrating sd_event into glib. Taken and adjusted from - * https://www.freedesktop.org/software/systemd/man/sd_event_get_fd.html - *****************************************************************************/ - -typedef struct SDEventSource { - GSource source; - GPollFD pollfd; - sd_event *event; -} SDEventSource; - -static gboolean -event_prepare(GSource *source, int *timeout_) -{ - return sd_event_prepare(((SDEventSource *) source)->event) > 0; -} - -static gboolean -event_check(GSource *source) -{ - return sd_event_wait(((SDEventSource *) source)->event, 0) > 0; -} - -static gboolean -event_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) -{ - return sd_event_dispatch(((SDEventSource *) source)->event) > 0; -} - -static void -event_finalize(GSource *source) -{ - SDEventSource *s = (SDEventSource *) source; - - sd_event_unref(s->event); -} - -static SDEventSource * -event_create_source(sd_event *event) -{ - static const GSourceFuncs event_funcs = { - .prepare = event_prepare, - .check = event_check, - .dispatch = event_dispatch, - .finalize = event_finalize, - }; - SDEventSource *source; - gboolean is_default_event = FALSE; - int r; - - if (!event) { - is_default_event = TRUE; - r = sd_event_default(&event); - if (r < 0) - g_return_val_if_reached(NULL); - } - - source = (SDEventSource *) g_source_new((GSourceFuncs *) &event_funcs, sizeof(SDEventSource)); - - source->event = is_default_event ? g_steal_pointer(&event) : sd_event_ref(event); - - source->pollfd = (GPollFD){ - .fd = sd_event_get_fd(source->event), - .events = G_IO_IN | G_IO_HUP | G_IO_ERR, - }; - - g_source_add_poll(&source->source, &source->pollfd); - - return source; -} - -static guint -event_attach(sd_event *event, GMainContext *context) -{ - SDEventSource *source; - guint id; - - source = event_create_source(event); - - g_return_val_if_fail(source, 0); - - id = g_source_attach((GSource *) source, context); - g_source_unref((GSource *) source); - - nm_assert(id != 0); - return id; -} - -guint -nm_sd_event_attach_default(void) -{ - return event_attach(NULL, NULL); -} - -/*****************************************************************************/ - -/* ensure that defines in nm-sd.h correspond to the internal defines. */ - -#include "nm-sd-adapt-core.h" -#include "dhcp-lease-internal.h" - -/*****************************************************************************/ diff --git a/src/core/systemd/nm-sd.h b/src/core/systemd/nm-sd.h deleted file mode 100644 index 0ea4be22..00000000 --- a/src/core/systemd/nm-sd.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2014 - 2016 Red Hat, Inc. - */ - -#ifndef __NM_SD_H__ -#define __NM_SD_H__ - -#include "systemd/src/systemd/sd-dhcp-client.h" -#include "systemd/src/systemd/sd-dhcp6-client.h" -#include "systemd/src/systemd/sd-lldp.h" -#include "systemd/src/systemd/sd-ipv4ll.h" - -/*****************************************************************************/ - -guint nm_sd_event_attach_default(void); - -/***************************************************************************** - * expose internal systemd API - * - * FIXME: don't use any internal systemd API. - *****************************************************************************/ - -struct sd_dhcp_lease; - -int dhcp_lease_save(struct sd_dhcp_lease *lease, const char *lease_file); -int dhcp_lease_load(struct sd_dhcp_lease **ret, const char *lease_file); - -#endif /* __NM_SD_H__ */ diff --git a/src/core/systemd/sd-adapt-core/condition.h b/src/core/systemd/sd-adapt-core/condition.h deleted file mode 100644 index d3a6812a..00000000 --- a/src/core/systemd/sd-adapt-core/condition.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -/* dummy header */ - -typedef struct _sd_adapt_Condition Condition; diff --git a/src/core/systemd/sd-adapt-core/conf-parser.h b/src/core/systemd/sd-adapt-core/conf-parser.h deleted file mode 100644 index 637892c2..00000000 --- a/src/core/systemd/sd-adapt-core/conf-parser.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -/* dummy header */ diff --git a/src/core/systemd/sd-adapt-core/device-util.h b/src/core/systemd/sd-adapt-core/device-util.h deleted file mode 100644 index 637892c2..00000000 --- a/src/core/systemd/sd-adapt-core/device-util.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -/* dummy header */ diff --git a/src/core/systemd/sd-adapt-core/khash.h b/src/core/systemd/sd-adapt-core/khash.h deleted file mode 100644 index 637892c2..00000000 --- a/src/core/systemd/sd-adapt-core/khash.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -/* dummy header */ diff --git a/src/core/systemd/sd-adapt-core/network-util.h b/src/core/systemd/sd-adapt-core/network-util.h deleted file mode 100644 index 637892c2..00000000 --- a/src/core/systemd/sd-adapt-core/network-util.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -/* dummy header */ diff --git a/src/core/systemd/sd-adapt-core/nm-sd-adapt-core.c b/src/core/systemd/sd-adapt-core/nm-sd-adapt-core.c deleted file mode 100644 index 9339b33d..00000000 --- a/src/core/systemd/sd-adapt-core/nm-sd-adapt-core.c +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2014 - 2016 Red Hat, Inc. - */ - -#include "src/core/systemd/nm-default-systemd.h" - -#include "nm-sd-adapt-core.h" - -#include "fd-util.h" - -/*****************************************************************************/ - -int -asynchronous_close(int fd) -{ - safe_close(fd); - return -1; -} - -/*****************************************************************************/ diff --git a/src/core/systemd/sd-adapt-core/nm-sd-adapt-core.h b/src/core/systemd/sd-adapt-core/nm-sd-adapt-core.h deleted file mode 100644 index f627d7d4..00000000 --- a/src/core/systemd/sd-adapt-core/nm-sd-adapt-core.h +++ /dev/null @@ -1,88 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2014 - 2018 Red Hat, Inc. - */ - -#ifndef __NM_SD_ADAPT_CORE_H__ -#define __NM_SD_ADAPT_CORE_H__ - -#include "src/core/systemd/nm-default-systemd.h" - -#include -#include -#include - -#undef NETWORKMANAGER_COMPILATION -#include "systemd/sd-adapt-shared/nm-sd-adapt-shared.h" -#undef NETWORKMANAGER_COMPILATION -#define NETWORKMANAGER_COMPILATION NM_NETWORKMANAGER_COMPILATION_SYSTEMD - -#ifndef HAVE_SYS_AUXV_H - #define HAVE_SYS_AUXV_H 0 -#endif - -/***************************************************************************** - * The remainder of the header is only enabled when building the systemd code - * itself. - *****************************************************************************/ - -#if (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_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 - - #ifndef ETHERTYPE_LLDP - #define ETHERTYPE_LLDP 0x88cc - #endif - - #ifndef HAVE_SECURE_GETENV - #ifdef HAVE___SECURE_GETENV - #define secure_getenv __secure_getenv - #else - #error neither secure_getenv nor __secure_getenv is available - #endif - #endif - -/*****************************************************************************/ - -static inline int -sd_notify(int unset_environment, const char *state) -{ - return 0; -} - - /* Can't include both net/if.h and linux/if.h; so have to define this here */ - #ifndef IF_NAMESIZE - #define IF_NAMESIZE 16 - #endif - - #ifndef IFNAMSIZ - #define IFNAMSIZ IF_NAMESIZE - #endif - - #ifndef MAX_HANDLE_SZ - #define MAX_HANDLE_SZ 128 - #endif - - #include "sd-id128.h" - #include "sparse-endian.h" - #include "async.h" - #include "util.h" - -#endif /* (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_SYSTEMD */ - -#endif /* __NM_SD_ADAPT_CORE_H__ */ diff --git a/src/core/systemd/sd-adapt-core/sd-daemon.h b/src/core/systemd/sd-adapt-core/sd-daemon.h deleted file mode 100644 index 637892c2..00000000 --- a/src/core/systemd/sd-adapt-core/sd-daemon.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -/* dummy header */ diff --git a/src/core/systemd/sd-adapt-core/sd-device.h b/src/core/systemd/sd-adapt-core/sd-device.h deleted file mode 100644 index 637892c2..00000000 --- a/src/core/systemd/sd-adapt-core/sd-device.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -/* dummy header */ diff --git a/src/core/systemd/sd-adapt-core/udev-util.h b/src/core/systemd/sd-adapt-core/udev-util.h deleted file mode 100644 index 637892c2..00000000 --- a/src/core/systemd/sd-adapt-core/udev-util.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -/* dummy header */ diff --git a/src/core/systemd/src/libsystemd-network/arp-util.c b/src/core/systemd/src/libsystemd-network/arp-util.c deleted file mode 100644 index 1c777d8a..00000000 --- a/src/core/systemd/src/libsystemd-network/arp-util.c +++ /dev/null @@ -1,140 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/*** - Copyright © 2014 Axis Communications AB. All rights reserved. -***/ - -#include "nm-sd-adapt-core.h" - -#include -#include -#include - -#include "arp-util.h" -#include "fd-util.h" -#include "unaligned.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, unaligned_read_be32(ð_mac->ether_addr_octet[0])),/* 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, unaligned_read_be16(ð_mac->ether_addr_octet[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 = htobe16(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(AF_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; - - return TAKE_FD(s); -} - -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 = htobe16(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 = htobe16(ARPHRD_ETHER), /* HTYPE */ - .ea_hdr.ar_pro = htobe16(ETHERTYPE_IP), /* PTYPE */ - .ea_hdr.ar_hln = ETH_ALEN, /* HLEN */ - .ea_hdr.ar_pln = sizeof(be32_t), /* PLEN */ - .ea_hdr.ar_op = htobe16(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/core/systemd/src/libsystemd-network/arp-util.h b/src/core/systemd/src/libsystemd-network/arp-util.h deleted file mode 100644 index 2dac8cfb..00000000 --- a/src/core/systemd/src/libsystemd-network/arp-util.h +++ /dev/null @@ -1,18 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -/*** - Copyright © 2014 Axis Communications AB. All rights reserved. -***/ - -#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/core/systemd/src/libsystemd-network/dhcp-identifier.c b/src/core/systemd/src/libsystemd-network/dhcp-identifier.c deleted file mode 100644 index 0720e381..00000000 --- a/src/core/systemd/src/libsystemd-network/dhcp-identifier.c +++ /dev/null @@ -1,228 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include "nm-sd-adapt-core.h" - -#include -#include -#include - -#include "sd-device.h" -#include "sd-id128.h" - -#include "dhcp-identifier.h" -#include "dhcp6-protocol.h" -#include "network-util.h" -#include "siphash24.h" -#include "sparse-endian.h" -#include "stdio-util.h" -#include "udev-util.h" -#include "virt.h" - -#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09) -#define APPLICATION_ID SD_ID128_MAKE(a5,0a,d1,12,bf,60,45,77,a2,fb,74,1a,b1,95,5b,03) -#define USEC_2000 ((usec_t) 946684800000000) /* 2000-01-01 00:00:00 UTC */ - -int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len, bool strict) { - struct duid d; - - assert_cc(sizeof(d.raw) >= MAX_DUID_LEN); - if (duid_len > MAX_DUID_LEN) - return -EINVAL; - - if (!strict) - /* Strict validation is not requested. We only ensure that the - * DUID is not too long. */ - return 0; - - switch (duid_type) { - case DUID_TYPE_LLT: - if (duid_len <= sizeof(d.llt)) - return -EINVAL; - break; - case DUID_TYPE_EN: - if (duid_len != sizeof(d.en)) - return -EINVAL; - break; - case DUID_TYPE_LL: - if (duid_len <= sizeof(d.ll)) - return -EINVAL; - break; - case DUID_TYPE_UUID: - if (duid_len != sizeof(d.uuid)) - return -EINVAL; - break; - default: - /* accept unknown type in order to be forward compatible */ - break; - } - return 0; -} - -#if 0 /* NM_IGNORED */ -int dhcp_identifier_set_duid_llt(struct duid *duid, usec_t t, const uint8_t *addr, size_t addr_len, uint16_t arp_type, size_t *len) { - uint16_t time_from_2000y; - - assert(duid); - assert(len); - assert(addr); - - 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 (t < USEC_2000) - time_from_2000y = 0; - else - time_from_2000y = (uint16_t) (((t - USEC_2000) / USEC_PER_SEC) & 0xffffffff); - - unaligned_write_be16(&duid->type, DUID_TYPE_LLT); - unaligned_write_be16(&duid->llt.htype, arp_type); - unaligned_write_be32(&duid->llt.time, time_from_2000y); - memcpy(duid->llt.haddr, addr, addr_len); - - *len = sizeof(duid->type) + sizeof(duid->llt.htype) + sizeof(duid->llt.time) + addr_len; - - return 0; -} - -int dhcp_identifier_set_duid_ll(struct duid *duid, const uint8_t *addr, size_t addr_len, uint16_t arp_type, size_t *len) { - assert(duid); - assert(len); - assert(addr); - - 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; - - unaligned_write_be16(&duid->type, DUID_TYPE_LL); - unaligned_write_be16(&duid->ll.htype, arp_type); - memcpy(duid->ll.haddr, addr, addr_len); - - *len = sizeof(duid->type) + sizeof(duid->ll.htype) + addr_len; - - return 0; -} -#endif /* NM_IGNORED */ - -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) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - machine_id = SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10); -#else - return r; -#endif - } - - unaligned_write_be16(&duid->type, DUID_TYPE_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; -} - -#if 0 /* NM_IGNORED */ -int dhcp_identifier_set_duid_uuid(struct duid *duid, size_t *len) { - sd_id128_t machine_id; - int r; - - assert(duid); - assert(len); - - r = sd_id128_get_machine_app_specific(APPLICATION_ID, &machine_id); - if (r < 0) - return r; - - unaligned_write_be16(&duid->type, DUID_TYPE_UUID); - memcpy(&duid->raw.data, &machine_id, sizeof(machine_id)); - - *len = sizeof(duid->type) + sizeof(machine_id); - - return 0; -} -#endif - -int dhcp_identifier_set_iaid( - int ifindex, - const uint8_t *mac, - size_t mac_len, - bool legacy_unstable_byteorder, - void *_id) { -#if 0 /* NM_IGNORED */ - /* name is a pointer to memory in the sd_device struct, so must - * have the same scope */ - _cleanup_(sd_device_unrefp) sd_device *device = NULL; - const char *name = NULL; - uint64_t id; - uint32_t id32; - - if (detect_container() <= 0) { - /* not in a container, udev will be around */ - char ifindex_str[1 + DECIMAL_STR_MAX(int)]; - int r; - - xsprintf(ifindex_str, "n%d", ifindex); - if (sd_device_new_from_device_id(&device, ifindex_str) >= 0) { - r = sd_device_get_is_initialized(device); - if (r < 0) - return r; - if (r == 0) - /* not yet ready */ - return -EBUSY; - - r = device_is_renaming(device); - if (r < 0) - return r; - if (r > 0) - /* device is under renaming */ - return -EBUSY; - - name = net_get_name_persistent(device); - } - } - - 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); - - id32 = (id & 0xffffffff) ^ (id >> 32); - - if (legacy_unstable_byteorder) - /* for historical reasons (a bug), the bits were swapped and thus - * the result was endianness dependent. Preserve that behavior. */ - id32 = __bswap_32(id32); - else - /* the fixed behavior returns a stable byte order. Since LE is expected - * to be more common, swap the bytes on LE to give the same as legacy - * behavior. */ - id32 = be32toh(id32); - - unaligned_write_ne32(_id, id32); - return 0; -#else /* NM_IGNORED */ - /* for NetworkManager, we don't use this function and we should never call here. - * This got replaced by nm_utils_create_dhcp_iaid(). */ - g_return_val_if_reached (-EINVAL); -#endif /* NM_IGNORED */ -} diff --git a/src/core/systemd/src/libsystemd-network/dhcp-identifier.h b/src/core/systemd/src/libsystemd-network/dhcp-identifier.h deleted file mode 100644 index e9f2ea7e..00000000 --- a/src/core/systemd/src/libsystemd-network/dhcp-identifier.h +++ /dev/null @@ -1,62 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -#include "sd-id128.h" - -#include "macro.h" -#include "sparse-endian.h" -#include "time-util.h" -#include "unaligned.h" - -#define SYSTEMD_PEN 43793 - -typedef enum DUIDType { - DUID_TYPE_LLT = 1, - DUID_TYPE_EN = 2, - DUID_TYPE_LL = 3, - DUID_TYPE_UUID = 4, - _DUID_TYPE_MAX, - _DUID_TYPE_INVALID = -1, -} DUIDType; - -/* 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 - -/* https://tools.ietf.org/html/rfc3315#section-9.1 */ -struct duid { - be16_t type; - union { - struct { - /* DUID_TYPE_LLT */ - be16_t htype; - be32_t time; - uint8_t haddr[0]; - } _packed_ llt; - struct { - /* DUID_TYPE_EN */ - be32_t pen; - uint8_t id[8]; - } _packed_ en; - struct { - /* DUID_TYPE_LL */ - be16_t htype; - uint8_t haddr[0]; - } _packed_ ll; - struct { - /* DUID_TYPE_UUID */ - sd_id128_t uuid; - } _packed_ uuid; - struct { - uint8_t data[MAX_DUID_LEN]; - } _packed_ raw; - }; -} _packed_; - -int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len, bool strict); -int dhcp_identifier_set_duid_llt(struct duid *duid, usec_t t, const uint8_t *addr, size_t addr_len, uint16_t arp_type, size_t *len); -int dhcp_identifier_set_duid_ll(struct duid *duid, const uint8_t *addr, size_t addr_len, uint16_t arp_type, size_t *len); -int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len); -int dhcp_identifier_set_duid_uuid(struct duid *duid, size_t *len); -int dhcp_identifier_set_iaid(int ifindex, const uint8_t *mac, size_t mac_len, bool legacy_unstable_byteorder, void *_id); diff --git a/src/core/systemd/src/libsystemd-network/dhcp-internal.h b/src/core/systemd/src/libsystemd-network/dhcp-internal.h deleted file mode 100644 index 40e6b1f2..00000000 --- a/src/core/systemd/src/libsystemd-network/dhcp-internal.h +++ /dev/null @@ -1,69 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -/*** - Copyright © 2013 Intel Corporation. All rights reserved. -***/ - -#include -#include -#include - -#include "sd-dhcp-client.h" - -#include "dhcp-protocol.h" -#include "socket-util.h" - -typedef struct sd_dhcp_option { - unsigned n_ref; - - uint8_t option; - void *data; - size_t length; -} sd_dhcp_option; - -typedef struct DHCPServerData { - struct in_addr *addr; - size_t size; -} DHCPServerData; - -extern const struct hash_ops dhcp_option_hash_ops; - -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, - const uint8_t *bcast_addr, size_t bcast_addr_len, - uint16_t arp_type, uint16_t port); -int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type); -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_callback_t)(uint8_t code, uint8_t len, - const void *option, void *userdata); - -int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_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 ip_service_type); - -int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, uint16_t port); - -/* 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_errno(client, error, fmt, ...) log_internal(LOG_DEBUG, error, PROJECT_FILE, __LINE__, __func__, "DHCP CLIENT (0x%x): " fmt, client->xid, ##__VA_ARGS__) -#define log_dhcp_client(client, fmt, ...) log_dhcp_client_errno(client, 0, fmt, ##__VA_ARGS__) diff --git a/src/core/systemd/src/libsystemd-network/dhcp-lease-internal.h b/src/core/systemd/src/libsystemd-network/dhcp-lease-internal.h deleted file mode 100644 index 49392d1b..00000000 --- a/src/core/systemd/src/libsystemd-network/dhcp-lease-internal.h +++ /dev/null @@ -1,84 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -/*** - Copyright © 2013 Intel Corporation. All rights reserved. -***/ - -#include "sd-dhcp-client.h" - -#include "dhcp-internal.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; - - uint8_t option; -}; - -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 next_server; - - bool have_subnet_mask; - be32_t subnet_mask; - - bool have_broadcast; - be32_t broadcast; - - struct in_addr *router; - size_t router_size; - - DHCPServerData servers[_SD_DHCP_LEASE_SERVER_TYPE_MAX]; - - struct sd_dhcp_route *static_route; - size_t static_route_size, static_route_allocated; - - uint16_t mtu; /* 0 if unset */ - - char *domainname; - char **search_domains; - 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_parse_search_domains(const uint8_t *option, size_t len, char ***domains); -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); diff --git a/src/core/systemd/src/libsystemd-network/dhcp-network.c b/src/core/systemd/src/libsystemd-network/dhcp-network.c deleted file mode 100644 index 4477f46f..00000000 --- a/src/core/systemd/src/libsystemd-network/dhcp-network.c +++ /dev/null @@ -1,246 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/*** - Copyright © 2013 Intel Corporation. All rights reserved. -***/ - -#include "nm-sd-adapt-core.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dhcp-internal.h" -#include "fd-util.h" -#include "socket-util.h" -#include "unaligned.h" - -static int _bind_raw_socket(int ifindex, union sockaddr_union *link, - uint32_t xid, - const uint8_t *bcast_addr, - size_t bcast_addr_len, - const struct ether_addr *eth_mac, - uint16_t arp_type, uint8_t dhcp_hlen, - uint16_t port) { - 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, port, 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_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_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 */ - - /* We only support MAC address length to be either 0 or 6 (ETH_ALEN). Optionally - * compare chaddr for ETH_ALEN bytes. */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_ALEN, 0, 12), /* A (the MAC address length) == ETH_ALEN ? */ - BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be32(ð_mac->ether_addr_octet[0])), /* 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, unaligned_read_be16(ð_mac->ether_addr_octet[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; - - assert(ifindex > 0); - assert(link); - - s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); - if (s < 0) - return -errno; - - r = setsockopt_int(s, SOL_PACKET, PACKET_AUXDATA, true); - if (r < 0) - return r; - - r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)); - if (r < 0) - return -errno; - - link->ll = (struct sockaddr_ll) { - .sll_family = AF_PACKET, - .sll_protocol = htobe16(ETH_P_IP), - .sll_ifindex = ifindex, - .sll_hatype = htobe16(arp_type), - .sll_halen = bcast_addr_len, - }; - memcpy(link->ll.sll_addr, bcast_addr, bcast_addr_len); /* We may overflow link->ll. link->ll_buffer ensures we have enough space. */ - - r = bind(s, &link->sa, SOCKADDR_LL_LEN(link->ll)); - if (r < 0) - return -errno; - - return TAKE_FD(s); -} - -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, - const uint8_t *bcast_addr, size_t bcast_addr_len, - uint16_t arp_type, uint16_t port) { - 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 *default_bcast_addr; - size_t expected_bcast_addr_len; - uint8_t dhcp_hlen = 0; - - if (arp_type == ARPHRD_ETHER) { - assert_return(mac_addr_len == ETH_ALEN, -EINVAL); - memcpy(ð_mac, mac_addr, ETH_ALEN); - dhcp_hlen = ETH_ALEN; - - default_bcast_addr = eth_bcast; - expected_bcast_addr_len = ETH_ALEN; - } else if (arp_type == ARPHRD_INFINIBAND) { - default_bcast_addr = ib_bcast; - expected_bcast_addr_len = INFINIBAND_ALEN; - } else - return -EINVAL; - - if (bcast_addr && bcast_addr_len > 0) - assert_return(bcast_addr_len == expected_bcast_addr_len, -EINVAL); - else { - bcast_addr = default_bcast_addr; - bcast_addr_len = expected_bcast_addr_len; - } - - return _bind_raw_socket(ifindex, link, xid, bcast_addr, bcast_addr_len, - ð_mac, arp_type, dhcp_hlen, port); -} - -int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) { - 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; - - s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); - if (s < 0) - return -errno; - - if (ip_service_type >= 0) - r = setsockopt_int(s, IPPROTO_IP, IP_TOS, ip_service_type); - else - r = setsockopt_int(s, IPPROTO_IP, IP_TOS, IPTOS_CLASS_CS6); - - if (r < 0) - return r; - - r = setsockopt_int(s, SOL_SOCKET, SO_REUSEADDR, true); - if (r < 0) - return r; - - if (ifindex > 0) { - r = socket_bind_to_ifindex(s, ifindex); - if (r < 0) - return r; - } - - if (address == INADDR_ANY) { - r = setsockopt_int(s, IPPROTO_IP, IP_PKTINFO, true); - if (r < 0) - return r; - - r = setsockopt_int(s, SOL_SOCKET, SO_BROADCAST, true); - if (r < 0) - return r; - - } else { - r = setsockopt_int(s, IPPROTO_IP, IP_FREEBIND, true); - if (r < 0) - return r; - } - - r = bind(s, &src.sa, sizeof(src.in)); - if (r < 0) - return -errno; - - return TAKE_FD(s); -} - -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, SOCKADDR_LL_LEN(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/core/systemd/src/libsystemd-network/dhcp-option.c b/src/core/systemd/src/libsystemd-network/dhcp-option.c deleted file mode 100644 index 2c15d85a..00000000 --- a/src/core/systemd/src/libsystemd-network/dhcp-option.c +++ /dev/null @@ -1,358 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/*** - Copyright © 2013 Intel Corporation. All rights reserved. -***/ - -#include "nm-sd-adapt-core.h" - -#include -#include -#include - -#include "alloc-util.h" -#include "dhcp-internal.h" -#include "dhcp-server-internal.h" -#include "memory-util.h" -#include "strv.h" -#include "utf8.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 != SD_DHCP_OPTION_END) - /* always make sure there is space for an END option */ - size--; - - switch (code) { - - case SD_DHCP_OPTION_PAD: - case SD_DHCP_OPTION_END: - if (*offset + 1 > size) - return -ENOBUFS; - - options[*offset] = code; - *offset += 1; - break; - - case SD_DHCP_OPTION_USER_CLASS: { - size_t total = 0; - char **s; - - STRV_FOREACH(s, (char **) optval) { - size_t len = strlen(*s); - - if (len > 255) - return -ENAMETOOLONG; - - total += 1 + len; - } - - if (*offset + 2 + total > size) - return -ENOBUFS; - - options[*offset] = code; - options[*offset + 1] = total; - *offset += 2; - - STRV_FOREACH(s, (char **) optval) { - size_t len = strlen(*s); - - options[*offset] = len; - - memcpy(&options[*offset + 1], *s, len); - *offset += 1 + len; - } - - break; - } - case SD_DHCP_OPTION_SIP_SERVER: - if (*offset + 3 + optlen > size) - return -ENOBUFS; - - options[*offset] = code; - options[*offset + 1] = optlen + 1; - options[*offset + 2] = 1; - - memcpy_safe(&options[*offset + 3], optval, optlen); - *offset += 3 + optlen; - - break; - case SD_DHCP_OPTION_VENDOR_SPECIFIC: { - OrderedHashmap *s = (OrderedHashmap *) optval; - struct sd_dhcp_option *p; - size_t l = 0; - - ORDERED_HASHMAP_FOREACH(p, s) - l += p->length + 2; - - if (*offset + l + 2 > size) - return -ENOBUFS; - - options[*offset] = code; - options[*offset + 1] = l; - - *offset += 2; - - ORDERED_HASHMAP_FOREACH(p, s) { - options[*offset] = p->option; - options[*offset + 1] = p->length; - memcpy(&options[*offset + 2], p->data, p->length); - *offset += 2 + p->length; - } - - break; - } - default: - if (*offset + 2 + optlen > size) - return -ENOBUFS; - - options[*offset] = code; - options[*offset + 1] = optlen; - - memcpy_safe(&options[*offset + 2], optval, optlen); - *offset += 2 + optlen; - - 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) { - const bool use_file = overload & DHCP_OVERLOAD_FILE; - const bool use_sname = overload & DHCP_OVERLOAD_SNAME; - int r; - - assert(message); - assert(offset); - - /* If *offset is in range [0, size), we are writing to ->options, - * if *offset is in range [size, size + sizeof(message->file)) and use_file, we are writing to ->file, - * if *offset is in range [size + use_file*sizeof(message->file), size + use_file*sizeof(message->file) + sizeof(message->sname)) - * and use_sname, we are writing to ->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 && (use_file || use_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, SD_DHCP_OPTION_END, 0, NULL); - if (r < 0) - return r; - - *offset = size; - } else - return r; - } - - if (use_file) { - size_t 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 && use_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, SD_DHCP_OPTION_END, 0, NULL); - if (r < 0) - return r; - - *offset = size + sizeof(message->file); - } else - return r; - } - } - - if (use_sname) { - size_t sname_offset = *offset - size - use_file*sizeof(message->file); - - 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 + use_file*sizeof(message->file) + 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_callback_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 SD_DHCP_OPTION_PAD: - continue; - - case SD_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 SD_DHCP_OPTION_MESSAGE_TYPE: - if (len != 1) - return -EINVAL; - - if (message_type) - *message_type = *option; - - break; - - case SD_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 = memdup_suffix0((const char *) option, len); - if (!string) - return -ENOMEM; - - if (!ascii_is_valid(string)) - return -EINVAL; - - free_and_replace(*error_message, string); - } - - break; - case SD_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_callback_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 = TAKE_PTR(error_message); - - return message_type; -} - -static sd_dhcp_option* dhcp_option_free(sd_dhcp_option *i) { - if (!i) - return NULL; - - free(i->data); - return mfree(i); -} - -int sd_dhcp_option_new(uint8_t option, const void *data, size_t length, sd_dhcp_option **ret) { - assert_return(ret, -EINVAL); - assert_return(length == 0 || data, -EINVAL); - - _cleanup_free_ void *q = memdup(data, length); - if (!q) - return -ENOMEM; - - sd_dhcp_option *p = new(sd_dhcp_option, 1); - if (!p) - return -ENOMEM; - - *p = (sd_dhcp_option) { - .n_ref = 1, - .option = option, - .length = length, - .data = TAKE_PTR(q), - }; - - *ret = TAKE_PTR(p); - return 0; -} - -DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_option, sd_dhcp_option, dhcp_option_free); -DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR( - dhcp_option_hash_ops, - void, - trivial_hash_func, - trivial_compare_func, - sd_dhcp_option, - sd_dhcp_option_unref); diff --git a/src/core/systemd/src/libsystemd-network/dhcp-packet.c b/src/core/systemd/src/libsystemd-network/dhcp-packet.c deleted file mode 100644 index eeadd562..00000000 --- a/src/core/systemd/src/libsystemd-network/dhcp-packet.c +++ /dev/null @@ -1,173 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/*** - Copyright © 2013 Intel Corporation. All rights reserved. -***/ - -#include "nm-sd-adapt-core.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(IN_SET(op, BOOTREQUEST, BOOTREPLY)); - assert(IN_SET(arp_type, ARPHRD_ETHER, 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, - SD_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, int ip_service_type) { - packet->ip.version = IPVERSION; - packet->ip.ihl = DHCP_IP_SIZE / 4; - packet->ip.tot_len = htobe16(len); - - if (ip_service_type >= 0) - packet->ip.tos = ip_service_type; - else - 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, uint16_t port) { - size_t hdrlen; - - assert(packet); - - /* IP */ - - if (packet->ip.version != IPVERSION) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: not IPv4"); - - if (packet->ip.ihl < 5) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: IPv4 IHL (%u words) invalid", - packet->ip.ihl); - - hdrlen = packet->ip.ihl * 4; - if (hdrlen < 20) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: IPv4 IHL (%zu bytes) " - "smaller than minimum (20 bytes)", - hdrlen); - - if (len < hdrlen) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: packet (%zu bytes) " - "smaller than expected (%zu) by IP header", - len, hdrlen); - - /* UDP */ - - if (packet->ip.protocol != IPPROTO_UDP) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: not UDP"); - - if (len < hdrlen + be16toh(packet->udp.len)) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: packet (%zu bytes) " - "smaller than expected (%zu) by UDP header", - len, hdrlen + be16toh(packet->udp.len)); - - if (be16toh(packet->udp.dest) != port) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: to port %u, which " - "is not the DHCP client port (%u)", - be16toh(packet->udp.dest), port); - - /* 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)) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: invalid IP checksum"); - - 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)) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: invalid UDP checksum"); - } - - return 0; -} diff --git a/src/core/systemd/src/libsystemd-network/dhcp-protocol.h b/src/core/systemd/src/libsystemd-network/dhcp-protocol.h deleted file mode 100644 index 11f4201a..00000000 --- a/src/core/systemd/src/libsystemd-network/dhcp-protocol.h +++ /dev/null @@ -1,99 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -/*** - Copyright © 2013 Intel Corporation. All rights reserved. -***/ - -#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, -}; - -#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/core/systemd/src/libsystemd-network/dhcp6-internal.h b/src/core/systemd/src/libsystemd-network/dhcp6-internal.h deleted file mode 100644 index 24d8a314..00000000 --- a/src/core/systemd/src/libsystemd-network/dhcp6-internal.h +++ /dev/null @@ -1,123 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -/*** - Copyright © 2014-2015 Intel Corporation. All rights reserved. -***/ - -#include -#include - -#include "sd-event.h" - -#include "list.h" -#include "hashmap.h" -#include "macro.h" -#include "sparse-endian.h" - -typedef struct sd_dhcp6_option { - unsigned n_ref; - - uint32_t enterprise_identifier; - uint16_t option; - void *data; - size_t length; -} sd_dhcp6_option; - -extern const struct hash_ops dhcp6_option_hash_ops; - -/* Common option header */ -typedef struct DHCP6Option { - be16_t code; - be16_t len; - uint8_t data[]; -} _packed_ DHCP6Option; - -/* Address option */ -struct iaaddr { - struct in6_addr address; - be32_t lifetime_preferred; - be32_t lifetime_valid; -} _packed_; - -/* Prefix Delegation Prefix option */ -struct iapdprefix { - be32_t lifetime_preferred; - be32_t lifetime_valid; - uint8_t prefixlen; - struct in6_addr address; -} _packed_; - -typedef struct DHCP6Address DHCP6Address; - -struct DHCP6Address { - LIST_FIELDS(DHCP6Address, addresses); - - union { - struct iaaddr iaaddr; - struct iapdprefix iapdprefix; - }; -}; - -/* Non-temporary Address option */ -struct ia_na { - be32_t id; - be32_t lifetime_t1; - be32_t lifetime_t2; -} _packed_; - -/* Prefix Delegation option */ -struct ia_pd { - be32_t id; - be32_t lifetime_t1; - be32_t lifetime_t2; -} _packed_; - -/* Temporary Address option */ -struct ia_ta { - be32_t id; -} _packed_; - -struct DHCP6IA { - uint16_t type; - union { - struct ia_na ia_na; - struct ia_pd ia_pd; - struct ia_ta ia_ta; - }; - - LIST_HEAD(DHCP6Address, addresses); -}; - -typedef struct DHCP6IA DHCP6IA; - -#define log_dhcp6_client_errno(p, error, fmt, ...) log_internal(LOG_DEBUG, error, PROJECT_FILE, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__) -#define log_dhcp6_client(p, fmt, ...) log_dhcp6_client_errno(p, 0, 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, const DHCP6IA *ia); -int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix); -int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn); -int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char **user_class); -int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char **user_class); -int dhcp6_option_append_vendor_option(uint8_t **buf, size_t *buflen, OrderedHashmap *vendor_options); -int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode, - size_t *optlen, uint8_t **optvalue); -int dhcp6_option_parse_status(DHCP6Option *option, size_t len); -int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_status_code); -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_list(const uint8_t *optval, uint16_t optlen, - char ***str_arr); -int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char **str); - -int dhcp6_network_bind_udp_socket(int ifindex, 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/core/systemd/src/libsystemd-network/dhcp6-lease-internal.h b/src/core/systemd/src/libsystemd-network/dhcp6-lease-internal.h deleted file mode 100644 index e9e2362d..00000000 --- a/src/core/systemd/src/libsystemd-network/dhcp6-lease-internal.h +++ /dev/null @@ -1,63 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -/*** - Copyright © 2014-2015 Intel Corporation. All rights reserved. -***/ - -#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; - DHCP6IA pd; - - DHCP6Address *addr_iter; - DHCP6Address *prefix_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; - char *fqdn; -}; - -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_get_pd_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_set_fqdn(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen); - -int dhcp6_lease_new(sd_dhcp6_lease **ret); diff --git a/src/core/systemd/src/libsystemd-network/dhcp6-network.c b/src/core/systemd/src/libsystemd-network/dhcp6-network.c deleted file mode 100644 index b6816de4..00000000 --- a/src/core/systemd/src/libsystemd-network/dhcp6-network.c +++ /dev/null @@ -1,76 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/*** - Copyright © 2014 Intel Corporation. All rights reserved. -***/ - -#include "nm-sd-adapt-core.h" - -#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 ifindex, 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 = ifindex, - }; - _cleanup_close_ int s = -1; - int r; - - assert(ifindex > 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_int(s, IPPROTO_IPV6, IPV6_V6ONLY, true); - if (r < 0) - return r; - - r = setsockopt_int(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, false); - if (r < 0) - return r; - - r = setsockopt_int(s, SOL_SOCKET, SO_REUSEADDR, true); - if (r < 0) - return r; - - r = bind(s, &src.sa, sizeof(src.in6)); - if (r < 0) - return -errno; - - return TAKE_FD(s); -} - -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/core/systemd/src/libsystemd-network/dhcp6-option.c b/src/core/systemd/src/libsystemd-network/dhcp6-option.c deleted file mode 100644 index 21e2d3f0..00000000 --- a/src/core/systemd/src/libsystemd-network/dhcp6-option.c +++ /dev/null @@ -1,795 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/*** - Copyright © 2014-2015 Intel Corporation. All rights reserved. -***/ - -#include "nm-sd-adapt-core.h" - -#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 "dns-domain.h" -#include "memory-util.h" -#include "sparse-endian.h" -#include "strv.h" -#include "unaligned.h" - -typedef struct DHCP6StatusOption { - struct DHCP6Option option; - be16_t status; - char msg[]; -} _packed_ DHCP6StatusOption; - -typedef struct DHCP6AddressOption { - struct DHCP6Option option; - struct iaaddr iaaddr; - uint8_t options[]; -} _packed_ DHCP6AddressOption; - -typedef struct DHCP6PDPrefixOption { - struct DHCP6Option option; - struct iapdprefix iapdprefix; - uint8_t options[]; -} _packed_ DHCP6PDPrefixOption; - -#define DHCP6_OPTION_IA_NA_LEN (sizeof(struct ia_na)) -#define DHCP6_OPTION_IA_PD_LEN (sizeof(struct ia_pd)) -#define DHCP6_OPTION_IA_TA_LEN (sizeof(struct ia_ta)) - -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 + offsetof(DHCP6Option, data)) - return -ENOBUFS; - - option->code = htobe16(optcode); - option->len = htobe16(optlen); - - *buf += offsetof(DHCP6Option, data); - *buflen -= offsetof(DHCP6Option, data); - - 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; - - memcpy_safe(*buf, optval, optlen); - - *buf += optlen; - *buflen -= optlen; - - return 0; -} - -int dhcp6_option_append_vendor_option(uint8_t **buf, size_t *buflen, OrderedHashmap *vendor_options) { - sd_dhcp6_option *options; - int r; - - assert(buf); - assert(*buf); - assert(buflen); - assert(vendor_options); - - ORDERED_HASHMAP_FOREACH(options, vendor_options) { - _cleanup_free_ uint8_t *p = NULL; - size_t total; - - total = 4 + 2 + 2 + options->length; - - p = malloc(total); - if (!p) - return -ENOMEM; - - unaligned_write_be32(p, options->enterprise_identifier); - unaligned_write_be16(p + 4, options->option); - unaligned_write_be16(p + 6, options->length); - memcpy(p + 8, options->data, options->length); - - r = dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_VENDOR_OPTS, total, p); - if (r < 0) - return r; - } - - return 0; -} - -int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia) { - uint16_t len; - uint8_t *ia_hdr; - size_t iaid_offset, ia_buflen, ia_addrlen = 0; - DHCP6Address *addr; - int r; - - assert_return(buf, -EINVAL); - assert_return(*buf, -EINVAL); - assert_return(buflen, -EINVAL); - assert_return(ia, -EINVAL); - - switch (ia->type) { - case SD_DHCP6_OPTION_IA_NA: - len = DHCP6_OPTION_IA_NA_LEN; - iaid_offset = offsetof(DHCP6IA, ia_na); - break; - - case SD_DHCP6_OPTION_IA_TA: - len = DHCP6_OPTION_IA_TA_LEN; - iaid_offset = offsetof(DHCP6IA, ia_ta); - break; - - default: - return -EINVAL; - } - - if (*buflen < offsetof(DHCP6Option, data) + len) - return -ENOBUFS; - - ia_hdr = *buf; - ia_buflen = *buflen; - - *buf += offsetof(DHCP6Option, data); - *buflen -= offsetof(DHCP6Option, data); - - memcpy(*buf, (char*) ia + iaid_offset, len); - - *buf += len; - *buflen -= len; - - LIST_FOREACH(addresses, addr, ia->addresses) { - r = option_append_hdr(buf, buflen, SD_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 += offsetof(DHCP6Option, data) + sizeof(addr->iaaddr); - } - - r = option_append_hdr(&ia_hdr, &ia_buflen, ia->type, len + ia_addrlen); - if (r < 0) - return r; - - return 0; -} - -int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) { - uint8_t buffer[1 + DNS_WIRE_FORMAT_HOSTNAME_MAX]; - int r; - - assert_return(buf && *buf && buflen && fqdn, -EINVAL); - - buffer[0] = DHCP6_FQDN_FLAG_S; /* Request server to perform AAAA RR DNS updates */ - - /* Store domain name after flags field */ - r = dns_name_to_wire_format(fqdn, buffer + 1, sizeof(buffer) - 1, false); - if (r <= 0) - return r; - - /* - * According to RFC 4704, chapter 4.2 only add terminating zero-length - * label in case a FQDN is provided. Since dns_name_to_wire_format - * always adds terminating zero-length label remove if only a hostname - * is provided. - */ - if (dns_name_is_single_label(fqdn)) - r--; - - r = dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_FQDN, 1 + r, buffer); - - return r; -} - -int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char **user_class) { - _cleanup_free_ uint8_t *p = NULL; - size_t total = 0, offset = 0; - char **s; - - assert_return(buf && *buf && buflen && user_class, -EINVAL); - - STRV_FOREACH(s, user_class) { - size_t len = strlen(*s); - uint8_t *q; - - if (len > 0xffff) - return -ENAMETOOLONG; - q = realloc(p, total + len + 2); - if (!q) - return -ENOMEM; - - p = q; - - unaligned_write_be16(&p[offset], len); - memcpy(&p[offset + 2], *s, len); - - offset += 2 + len; - total += 2 + len; - } - - return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_USER_CLASS, total, p); -} - -int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char **vendor_class) { - _cleanup_free_ uint8_t *p = NULL; - uint32_t enterprise_identifier; - size_t total, offset; - char **s; - - assert(buf); - assert(*buf); - assert(buflen); - assert(vendor_class); - - enterprise_identifier = htobe32(SYSTEMD_PEN); - - p = memdup(&enterprise_identifier, sizeof(enterprise_identifier)); - if (!p) - return -ENOMEM; - - total = sizeof(enterprise_identifier); - offset = total; - - STRV_FOREACH(s, vendor_class) { - size_t len = strlen(*s); - uint8_t *q; - - q = realloc(p, total + len + 2); - if (!q) - return -ENOMEM; - - p = q; - - unaligned_write_be16(&p[offset], len); - memcpy(&p[offset + 2], *s, len); - - offset += 2 + len; - total += 2 + len; - } - - return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_VENDOR_CLASS, total, p); -} - -int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix) { - DHCP6Option *option = (DHCP6Option *)buf; - size_t i = sizeof(*option) + sizeof(pd->ia_pd); - DHCP6PDPrefixOption *prefix_opt; - DHCP6Address *prefix; - - assert_return(buf, -EINVAL); - assert_return(pd, -EINVAL); - assert_return(pd->type == SD_DHCP6_OPTION_IA_PD, -EINVAL); - - if (len < i) - return -ENOBUFS; - - option->code = htobe16(SD_DHCP6_OPTION_IA_PD); - - memcpy(&option->data, &pd->ia_pd, sizeof(pd->ia_pd)); - LIST_FOREACH(addresses, prefix, pd->addresses) { - if (len < i + sizeof(*prefix_opt)) - return -ENOBUFS; - - prefix_opt = (DHCP6PDPrefixOption *)&buf[i]; - prefix_opt->option.code = htobe16(SD_DHCP6_OPTION_IA_PD_PREFIX); - prefix_opt->option.len = htobe16(sizeof(prefix_opt->iapdprefix)); - - memcpy(&prefix_opt->iapdprefix, &prefix->iapdprefix, sizeof(struct iapdprefix)); - i += sizeof(*prefix_opt); - } - - if (hint_pd_prefix && hint_pd_prefix->iapdprefix.prefixlen > 0) { - if (len < i + sizeof(*prefix_opt)) - return -ENOBUFS; - - prefix_opt = (DHCP6PDPrefixOption *)&buf[i]; - prefix_opt->option.code = htobe16(SD_DHCP6_OPTION_IA_PD_PREFIX); - prefix_opt->option.len = htobe16(sizeof(prefix_opt->iapdprefix)); - - memcpy(&prefix_opt->iapdprefix, &hint_pd_prefix->iapdprefix, sizeof(struct iapdprefix)); - i += sizeof(*prefix_opt); - } - - option->len = htobe16(i - sizeof(*option)); - - return i; -} - -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 < offsetof(DHCP6Option, data)) - 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_status(DHCP6Option *option, size_t len) { - DHCP6StatusOption *statusopt = (DHCP6StatusOption *)option; - - if (len < sizeof(DHCP6StatusOption) || - be16toh(option->len) + offsetof(DHCP6Option, data) < sizeof(DHCP6StatusOption)) - return -ENOBUFS; - - return be16toh(statusopt->status); -} - -static int dhcp6_option_parse_address(DHCP6Option *option, DHCP6IA *ia, - uint32_t *lifetime_valid) { - DHCP6AddressOption *addr_option = (DHCP6AddressOption *)option; - DHCP6Address *addr; - uint32_t lt_valid, lt_pref; - int r; - - if (be16toh(option->len) + offsetof(DHCP6Option, data) < sizeof(*addr_option)) - return -ENOBUFS; - - lt_valid = be32toh(addr_option->iaaddr.lifetime_valid); - lt_pref = be32toh(addr_option->iaaddr.lifetime_preferred); - - if (lt_valid == 0 || lt_pref > lt_valid) { - log_dhcp6_client(client, "Valid lifetime of an IA address is zero or preferred lifetime %d > valid lifetime %d", - lt_pref, lt_valid); - - return 0; - } - - if (be16toh(option->len) + offsetof(DHCP6Option, data) > sizeof(*addr_option)) { - r = dhcp6_option_parse_status((DHCP6Option *)addr_option->options, be16toh(option->len) + offsetof(DHCP6Option, data) - sizeof(*addr_option)); - if (r != 0) - return r < 0 ? r: 0; - } - - addr = new0(DHCP6Address, 1); - if (!addr) - return -ENOMEM; - - LIST_INIT(addresses, addr); - memcpy(&addr->iaaddr, option->data, sizeof(addr->iaaddr)); - - LIST_PREPEND(addresses, ia->addresses, addr); - - *lifetime_valid = be32toh(addr->iaaddr.lifetime_valid); - - return 0; -} - -static int dhcp6_option_parse_pdprefix(DHCP6Option *option, DHCP6IA *ia, - uint32_t *lifetime_valid) { - DHCP6PDPrefixOption *pdprefix_option = (DHCP6PDPrefixOption *)option; - DHCP6Address *prefix; - uint32_t lt_valid, lt_pref; - int r; - - if (be16toh(option->len) + offsetof(DHCP6Option, data) < sizeof(*pdprefix_option)) - return -ENOBUFS; - - lt_valid = be32toh(pdprefix_option->iapdprefix.lifetime_valid); - lt_pref = be32toh(pdprefix_option->iapdprefix.lifetime_preferred); - - if (lt_valid == 0 || lt_pref > lt_valid) { - log_dhcp6_client(client, "Valid lifetieme of a PD prefix is zero or preferred lifetime %d > valid lifetime %d", - lt_pref, lt_valid); - - return 0; - } - - if (be16toh(option->len) + offsetof(DHCP6Option, data) > sizeof(*pdprefix_option)) { - r = dhcp6_option_parse_status((DHCP6Option *)pdprefix_option->options, be16toh(option->len) + offsetof(DHCP6Option, data) - sizeof(*pdprefix_option)); - if (r != 0) - return r < 0 ? r: 0; - } - - prefix = new0(DHCP6Address, 1); - if (!prefix) - return -ENOMEM; - - LIST_INIT(addresses, prefix); - memcpy(&prefix->iapdprefix, option->data, sizeof(prefix->iapdprefix)); - - LIST_PREPEND(addresses, ia->addresses, prefix); - - *lifetime_valid = be32toh(prefix->iapdprefix.lifetime_valid); - - return 0; -} - -int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_status_code) { - uint32_t lt_t1, lt_t2, lt_valid = 0, lt_min = UINT32_MAX; - uint16_t iatype, optlen; - size_t iaaddr_offset; - int r = 0, status; - size_t i, len; - uint16_t opt; - - assert_return(ia, -EINVAL); - assert_return(!ia->addresses, -EINVAL); - - iatype = be16toh(iaoption->code); - len = be16toh(iaoption->len); - - switch (iatype) { - case SD_DHCP6_OPTION_IA_NA: - - if (len < DHCP6_OPTION_IA_NA_LEN) - return -ENOBUFS; - - iaaddr_offset = DHCP6_OPTION_IA_NA_LEN; - memcpy(&ia->ia_na, iaoption->data, sizeof(ia->ia_na)); - - lt_t1 = be32toh(ia->ia_na.lifetime_t1); - lt_t2 = be32toh(ia->ia_na.lifetime_t2); - - if (lt_t1 && lt_t2 && lt_t1 > lt_t2) { - log_dhcp6_client(client, "IA NA T1 %ds > T2 %ds", - lt_t1, lt_t2); - return -EINVAL; - } - - break; - - case SD_DHCP6_OPTION_IA_PD: - - if (len < sizeof(ia->ia_pd)) - return -ENOBUFS; - - iaaddr_offset = sizeof(ia->ia_pd); - memcpy(&ia->ia_pd, iaoption->data, sizeof(ia->ia_pd)); - - lt_t1 = be32toh(ia->ia_pd.lifetime_t1); - lt_t2 = be32toh(ia->ia_pd.lifetime_t2); - - if (lt_t1 && lt_t2 && lt_t1 > lt_t2) { - log_dhcp6_client(client, "IA PD T1 %ds > T2 %ds", - lt_t1, lt_t2); - return -EINVAL; - } - - break; - - case SD_DHCP6_OPTION_IA_TA: - if (len < DHCP6_OPTION_IA_TA_LEN) - return -ENOBUFS; - - iaaddr_offset = DHCP6_OPTION_IA_TA_LEN; - memcpy(&ia->ia_ta.id, iaoption->data, sizeof(ia->ia_ta)); - - break; - - default: - return -ENOMSG; - } - - ia->type = iatype; - i = iaaddr_offset; - - while (i < len) { - DHCP6Option *option = (DHCP6Option *)&iaoption->data[i]; - - if (len < i + sizeof(*option) || len < i + sizeof(*option) + be16toh(option->len)) - return -ENOBUFS; - - opt = be16toh(option->code); - optlen = be16toh(option->len); - - switch (opt) { - case SD_DHCP6_OPTION_IAADDR: - - if (!IN_SET(ia->type, SD_DHCP6_OPTION_IA_NA, SD_DHCP6_OPTION_IA_TA)) { - log_dhcp6_client(client, "IA Address option not in IA NA or TA option"); - return -EINVAL; - } - - r = dhcp6_option_parse_address(option, ia, <_valid); - if (r < 0) - return r; - - if (lt_valid < lt_min) - lt_min = lt_valid; - - break; - - case SD_DHCP6_OPTION_IA_PD_PREFIX: - - if (!IN_SET(ia->type, SD_DHCP6_OPTION_IA_PD)) { - log_dhcp6_client(client, "IA PD Prefix option not in IA PD option"); - return -EINVAL; - } - - r = dhcp6_option_parse_pdprefix(option, ia, <_valid); - if (r < 0) - return r; - - if (lt_valid < lt_min) - lt_min = lt_valid; - - break; - - case SD_DHCP6_OPTION_STATUS_CODE: - - status = dhcp6_option_parse_status(option, optlen + offsetof(DHCP6Option, data)); - if (status < 0) - return status; - - if (status > 0) { - if (ret_status_code) - *ret_status_code = status; - - log_dhcp6_client(client, "IA status %s", - dhcp6_message_status_to_string(status)); - - return 0; - } - - break; - - default: - log_dhcp6_client(client, "Unknown IA option %d", opt); - break; - } - - i += sizeof(*option) + optlen; - } - - switch(iatype) { - case SD_DHCP6_OPTION_IA_NA: - if (!ia->ia_na.lifetime_t1 && !ia->ia_na.lifetime_t2) { - lt_t1 = lt_min / 2; - lt_t2 = lt_min / 10 * 8; - ia->ia_na.lifetime_t1 = htobe32(lt_t1); - ia->ia_na.lifetime_t2 = htobe32(lt_t2); - - log_dhcp6_client(client, "Computed IA NA T1 %ds and T2 %ds as both were zero", - lt_t1, lt_t2); - } - - break; - - case SD_DHCP6_OPTION_IA_PD: - if (!ia->ia_pd.lifetime_t1 && !ia->ia_pd.lifetime_t2) { - lt_t1 = lt_min / 2; - lt_t2 = lt_min / 10 * 8; - ia->ia_pd.lifetime_t1 = htobe32(lt_t1); - ia->ia_pd.lifetime_t2 = htobe32(lt_t2); - - log_dhcp6_client(client, "Computed IA PD T1 %ds and T2 %ds as both were zero", - lt_t1, lt_t2); - } - - break; - - default: - break; - } - - if (ret_status_code) - *ret_status_code = 0; - - return 1; -} - -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; -} - -static int parse_domain(const uint8_t **data, uint16_t *len, char **out_domain) { - _cleanup_free_ char *ret = NULL; - size_t n = 0, allocated = 0; - const uint8_t *optval = *data; - uint16_t optlen = *len; - bool first = true; - int r; - - if (optlen <= 1) - return -ENODATA; - - for (;;) { - const char *label; - uint8_t c; - - if (optlen == 0) - break; - - c = *optval; - optval++; - optlen--; - - if (c == 0) - /* End label */ - break; - if (c > 63) - return -EBADMSG; - if (c > optlen) - return -EMSGSIZE; - - /* Literal label */ - label = (const char *)optval; - optval += c; - optlen -= c; - - if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) - return -ENOMEM; - - if (first) - first = false; - else - ret[n++] = '.'; - - r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX); - if (r < 0) - return r; - - n += r; - } - - if (n) { - if (!GREEDY_REALLOC(ret, allocated, n + 1)) - return -ENOMEM; - ret[n] = 0; - } - - *out_domain = TAKE_PTR(ret); - *data = optval; - *len = optlen; - - return n; -} - -int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char **str) { - _cleanup_free_ char *domain = NULL; - int r; - - r = parse_domain(&optval, &optlen, &domain); - if (r < 0) - return r; - if (r == 0) - return -ENODATA; - if (optlen != 0) - return -EINVAL; - - *str = TAKE_PTR(domain); - return 0; -} - -int dhcp6_option_parse_domainname_list(const uint8_t *optval, uint16_t optlen, char ***str_arr) { - size_t idx = 0; - _cleanup_strv_free_ char **names = NULL; - int r; - - if (optlen <= 1) - return -ENODATA; - if (optval[optlen - 1] != '\0') - return -EINVAL; - - while (optlen > 0) { - _cleanup_free_ char *ret = NULL; - - r = parse_domain(&optval, &optlen, &ret); - if (r < 0) - return r; - if (r == 0) - continue; - - r = strv_extend(&names, ret); - if (r < 0) - return r; - - idx++; - } - - *str_arr = TAKE_PTR(names); - - return idx; -} - -static sd_dhcp6_option* dhcp6_option_free(sd_dhcp6_option *i) { - if (!i) - return NULL; - - free(i->data); - return mfree(i); -} - -int sd_dhcp6_option_new(uint16_t option, const void *data, size_t length, uint32_t enterprise_identifier, sd_dhcp6_option **ret) { - assert_return(ret, -EINVAL); - assert_return(length == 0 || data, -EINVAL); - - _cleanup_free_ void *q = memdup(data, length); - if (!q) - return -ENOMEM; - - sd_dhcp6_option *p = new(sd_dhcp6_option, 1); - if (!p) - return -ENOMEM; - - *p = (sd_dhcp6_option) { - .n_ref = 1, - .option = option, - .enterprise_identifier = enterprise_identifier, - .length = length, - .data = TAKE_PTR(q), - }; - - *ret = p; - return 0; -} - -DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_option, sd_dhcp6_option, dhcp6_option_free); -DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR( - dhcp6_option_hash_ops, - void, - trivial_hash_func, - trivial_compare_func, - sd_dhcp6_option, - sd_dhcp6_option_unref); diff --git a/src/core/systemd/src/libsystemd-network/dhcp6-protocol.h b/src/core/systemd/src/libsystemd-network/dhcp6-protocol.h deleted file mode 100644 index c7003638..00000000 --- a/src/core/systemd/src/libsystemd-network/dhcp6-protocol.h +++ /dev/null @@ -1,120 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -/*** - Copyright © 2014 Intel Corporation. All rights reserved. -***/ - -#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; - }; - uint8_t options[]; -} _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 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_NTP_SUBOPTION_SRV_ADDR = 1, - DHCP6_NTP_SUBOPTION_MC_ADDR = 2, - DHCP6_NTP_SUBOPTION_SRV_FQDN = 3, -}; - -/* - * RFC 8415, RFC 5007 and RFC 7653 status codes: - * https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#dhcpv6-parameters-5 - */ -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_NO_PREFIX_AVAIL = 6, - DHCP6_STATUS_UNKNOWN_QUERY_TYPE = 7, - DHCP6_STATUS_MALFORMED_QUERY = 8, - DHCP6_STATUS_NOT_CONFIGURED = 9, - DHCP6_STATUS_NOT_ALLOWED = 10, - DHCP6_STATUS_QUERY_TERMINATED = 11, - DHCP6_STATUS_DATA_MISSING = 12, - DHCP6_STATUS_CATCHUP_COMPLETE = 13, - DHCP6_STATUS_NOT_SUPPORTED = 14, - DHCP6_STATUS_TLS_CONNECTION_REFUSED = 15, - DHCP6_STATUS_ADDRESS_IN_USE = 16, - DHCP6_STATUS_CONFIGURATION_CONFLICT = 17, - DHCP6_STATUS_MISSING_BINDING_INFORMATION = 18, - DHCP6_STATUS_OUTDATED_BINDING_INFORMATION = 19, - DHCP6_STATUS_SERVER_SHUTTING_DOWN = 20, - DHCP6_STATUS_DNS_UPDATE_NOT_SUPPORTED = 21, - DHCP6_STATUS_EXCESSIVE_TIME_SKEW = 22, - _DHCP6_STATUS_MAX = 23, -}; - -enum { - DHCP6_FQDN_FLAG_S = (1 << 0), - DHCP6_FQDN_FLAG_O = (1 << 1), - DHCP6_FQDN_FLAG_N = (1 << 2), -}; diff --git a/src/core/systemd/src/libsystemd-network/lldp-internal.h b/src/core/systemd/src/libsystemd-network/lldp-internal.h deleted file mode 100644 index f23695f9..00000000 --- a/src/core/systemd/src/libsystemd-network/lldp-internal.h +++ /dev/null @@ -1,39 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -#include "sd-event.h" -#include "sd-lldp.h" - -#include "hashmap.h" -#include "log.h" -#include "prioq.h" - -struct sd_lldp { - unsigned n_ref; - - int ifindex; - int fd; - - sd_event *event; - int64_t event_priority; - sd_event_source *io_event_source; - sd_event_source *timer_event_source; - - Prioq *neighbor_by_expiry; - Hashmap *neighbor_by_id; - - uint64_t neighbors_max; - - sd_lldp_callback_t callback; - void *userdata; - - uint16_t capability_mask; - - struct ether_addr filter_address; -}; - -#define log_lldp_errno(error, fmt, ...) log_internal(LOG_DEBUG, error, PROJECT_FILE, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__) -#define log_lldp(fmt, ...) log_lldp_errno(0, fmt, ##__VA_ARGS__) - -const char* lldp_event_to_string(sd_lldp_event e) _const_; -sd_lldp_event lldp_event_from_string(const char *s) _pure_; diff --git a/src/core/systemd/src/libsystemd-network/lldp-neighbor.c b/src/core/systemd/src/libsystemd-network/lldp-neighbor.c deleted file mode 100644 index 58ff0e0f..00000000 --- a/src/core/systemd/src/libsystemd-network/lldp-neighbor.c +++ /dev/null @@ -1,794 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include "nm-sd-adapt-core.h" - -#include "alloc-util.h" -#include "escape.h" -#include "ether-addr-util.h" -#include "hexdecoct.h" -#include "in-addr-util.h" -#include "lldp-internal.h" -#include "lldp-neighbor.h" -#include "memory-util.h" -#include "missing_network.h" -#include "unaligned.h" - -static void lldp_neighbor_id_hash_func(const LLDPNeighborID *id, struct siphash *state) { - siphash24_compress(id->chassis_id, id->chassis_id_size, state); - siphash24_compress(&id->chassis_id_size, sizeof(id->chassis_id_size), state); - siphash24_compress(id->port_id, id->port_id_size, state); - siphash24_compress(&id->port_id_size, sizeof(id->port_id_size), state); -} - -int lldp_neighbor_id_compare_func(const LLDPNeighborID *x, const LLDPNeighborID *y) { - return memcmp_nn(x->chassis_id, x->chassis_id_size, y->chassis_id, y->chassis_id_size) - ?: memcmp_nn(x->port_id, x->port_id_size, y->port_id, y->port_id_size); -} - -DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(lldp_neighbor_hash_ops, LLDPNeighborID, lldp_neighbor_id_hash_func, lldp_neighbor_id_compare_func, - sd_lldp_neighbor, lldp_neighbor_unlink); - -int lldp_neighbor_prioq_compare_func(const void *a, const void *b) { - const sd_lldp_neighbor *x = a, *y = b; - - return CMP(x->until, y->until); -} - -_public_ sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n) { - if (!n) - return NULL; - - assert(n->n_ref > 0 || n->lldp); - n->n_ref++; - - return n; -} - -static void lldp_neighbor_free(sd_lldp_neighbor *n) { - assert(n); - - free(n->id.port_id); - free(n->id.chassis_id); - free(n->port_description); - free(n->system_name); - free(n->system_description); - free(n->mud_url); - free(n->chassis_id_as_string); - free(n->port_id_as_string); - free(n); -} - -_public_ sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n) { - - /* Drops one reference from the neighbor. Note that the object is not freed unless it is already unlinked from - * the sd_lldp object. */ - - if (!n) - return NULL; - - assert(n->n_ref > 0); - n->n_ref--; - - if (n->n_ref <= 0 && !n->lldp) - lldp_neighbor_free(n); - - return NULL; -} - -sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n) { - - /* Removes the neighbor object from the LLDP object, and frees it if it also has no other reference. */ - - if (!n) - return NULL; - - if (!n->lldp) - return NULL; - - /* Only remove the neighbor object from the hash table if it's in there, don't complain if it isn't. This is - * because we are used as destructor call for hashmap_clear() and thus sometimes are called to de-register - * ourselves from the hashtable and sometimes are called after we already are de-registered. */ - - (void) hashmap_remove_value(n->lldp->neighbor_by_id, &n->id, n); - - assert_se(prioq_remove(n->lldp->neighbor_by_expiry, n, &n->prioq_idx) >= 0); - - n->lldp = NULL; - - if (n->n_ref <= 0) - lldp_neighbor_free(n); - - return NULL; -} - -sd_lldp_neighbor *lldp_neighbor_new(size_t raw_size) { - sd_lldp_neighbor *n; - - n = malloc0(ALIGN(sizeof(sd_lldp_neighbor)) + raw_size); - if (!n) - return NULL; - - n->raw_size = raw_size; - n->n_ref = 1; - - return n; -} - -static int parse_string(char **s, const void *q, size_t n) { - const char *p = q; - char *k; - - assert(s); - assert(p || n == 0); - - if (*s) { - log_lldp("Found duplicate string, ignoring field."); - return 0; - } - - /* Strip trailing NULs, just to be nice */ - while (n > 0 && p[n-1] == 0) - n--; - - if (n <= 0) /* Ignore empty strings */ - return 0; - - /* Look for inner NULs */ - if (memchr(p, 0, n)) { - log_lldp("Found inner NUL in string, ignoring field."); - return 0; - } - - /* Let's escape weird chars, for security reasons */ - k = cescape_length(p, n); - if (!k) - return -ENOMEM; - - free(*s); - *s = k; - - return 1; -} - -int lldp_neighbor_parse(sd_lldp_neighbor *n) { - struct ether_header h; - const uint8_t *p; - size_t left; - int r; - - assert(n); - - if (n->raw_size < sizeof(struct ether_header)) { - log_lldp("Received truncated packet, ignoring."); - return -EBADMSG; - } - - memcpy(&h, LLDP_NEIGHBOR_RAW(n), sizeof(h)); - - if (h.ether_type != htobe16(ETHERTYPE_LLDP)) { - log_lldp("Received packet with wrong type, ignoring."); - return -EBADMSG; - } - - if (h.ether_dhost[0] != 0x01 || - h.ether_dhost[1] != 0x80 || - h.ether_dhost[2] != 0xc2 || - h.ether_dhost[3] != 0x00 || - h.ether_dhost[4] != 0x00 || - !IN_SET(h.ether_dhost[5], 0x00, 0x03, 0x0e)) { - log_lldp("Received packet with wrong destination address, ignoring."); - return -EBADMSG; - } - - memcpy(&n->source_address, h.ether_shost, sizeof(struct ether_addr)); - memcpy(&n->destination_address, h.ether_dhost, sizeof(struct ether_addr)); - - p = (const uint8_t*) LLDP_NEIGHBOR_RAW(n) + sizeof(struct ether_header); - left = n->raw_size - sizeof(struct ether_header); - - for (;;) { - uint8_t type; - uint16_t length; - - if (left < 2) { - log_lldp("TLV lacks header, ignoring."); - return -EBADMSG; - } - - type = p[0] >> 1; - length = p[1] + (((uint16_t) (p[0] & 1)) << 8); - p += 2, left -= 2; - - if (left < length) { - log_lldp("TLV truncated, ignoring datagram."); - return -EBADMSG; - } - - switch (type) { - - case SD_LLDP_TYPE_END: - if (length != 0) { - log_lldp("End marker TLV not zero-sized, ignoring datagram."); - return -EBADMSG; - } - - /* Note that after processing the SD_LLDP_TYPE_END left could still be > 0 - * as the message may contain padding (see IEEE 802.1AB-2016, sec. 8.5.12) */ - - goto end_marker; - - case SD_LLDP_TYPE_CHASSIS_ID: - if (length < 2 || length > 256) { /* includes the chassis subtype, hence one extra byte */ - log_lldp("Chassis ID field size out of range, ignoring datagram."); - return -EBADMSG; - } - if (n->id.chassis_id) { - log_lldp("Duplicate chassis ID field, ignoring datagram."); - return -EBADMSG; - } - - n->id.chassis_id = memdup(p, length); - if (!n->id.chassis_id) - return -ENOMEM; - - n->id.chassis_id_size = length; - break; - - case SD_LLDP_TYPE_PORT_ID: - if (length < 2 || length > 256) { /* includes the port subtype, hence one extra byte */ - log_lldp("Port ID field size out of range, ignoring datagram."); - return -EBADMSG; - } - if (n->id.port_id) { - log_lldp("Duplicate port ID field, ignoring datagram."); - return -EBADMSG; - } - - n->id.port_id = memdup(p, length); - if (!n->id.port_id) - return -ENOMEM; - - n->id.port_id_size = length; - break; - - case SD_LLDP_TYPE_TTL: - if (length != 2) { - log_lldp("TTL field has wrong size, ignoring datagram."); - return -EBADMSG; - } - - if (n->has_ttl) { - log_lldp("Duplicate TTL field, ignoring datagram."); - return -EBADMSG; - } - - n->ttl = unaligned_read_be16(p); - n->has_ttl = true; - break; - - case SD_LLDP_TYPE_PORT_DESCRIPTION: - r = parse_string(&n->port_description, p, length); - if (r < 0) - return r; - break; - - case SD_LLDP_TYPE_SYSTEM_NAME: - r = parse_string(&n->system_name, p, length); - if (r < 0) - return r; - break; - - case SD_LLDP_TYPE_SYSTEM_DESCRIPTION: - r = parse_string(&n->system_description, p, length); - if (r < 0) - return r; - break; - - case SD_LLDP_TYPE_SYSTEM_CAPABILITIES: - if (length != 4) - log_lldp("System capabilities field has wrong size, ignoring."); - else { - n->system_capabilities = unaligned_read_be16(p); - n->enabled_capabilities = unaligned_read_be16(p + 2); - n->has_capabilities = true; - } - - break; - - case SD_LLDP_TYPE_PRIVATE: { - if (length < 4) - log_lldp("Found private TLV that is too short, ignoring."); - else { - /* RFC 8520: MUD URL */ - if (memcmp(p, SD_LLDP_OUI_MUD, sizeof(SD_LLDP_OUI_MUD)) == 0 && - p[sizeof(SD_LLDP_OUI_MUD)] == SD_LLDP_OUI_SUBTYPE_MUD_USAGE_DESCRIPTION) { - r = parse_string(&n->mud_url, p + sizeof(SD_LLDP_OUI_MUD) + 1, - length - 1 - sizeof(SD_LLDP_OUI_MUD)); - if (r < 0) - return r; - } - } - } - - break; - } - - p += length, left -= length; - } - -end_marker: - if (!n->id.chassis_id || !n->id.port_id || !n->has_ttl) { - log_lldp("One or more mandatory TLV missing in datagram. Ignoring."); - return -EBADMSG; - - } - - n->rindex = sizeof(struct ether_header); - - return 0; -} - -void lldp_neighbor_start_ttl(sd_lldp_neighbor *n) { - assert(n); - - if (n->ttl > 0) { - usec_t base; - - /* Use the packet's timestamp if there is one known */ - base = triple_timestamp_by_clock(&n->timestamp, clock_boottime_or_monotonic()); - if (base <= 0 || base == USEC_INFINITY) - base = now(clock_boottime_or_monotonic()); /* Otherwise, take the current time */ - - n->until = usec_add(base, n->ttl * USEC_PER_SEC); - } else - n->until = 0; - - if (n->lldp) - prioq_reshuffle(n->lldp->neighbor_by_expiry, n, &n->prioq_idx); -} - -bool lldp_neighbor_equal(const sd_lldp_neighbor *a, const sd_lldp_neighbor *b) { - if (a == b) - return true; - - if (!a || !b) - return false; - - if (a->raw_size != b->raw_size) - return false; - - return memcmp(LLDP_NEIGHBOR_RAW(a), LLDP_NEIGHBOR_RAW(b), a->raw_size) == 0; -} - -_public_ int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address) { - assert_return(n, -EINVAL); - assert_return(address, -EINVAL); - - *address = n->source_address; - return 0; -} - -_public_ int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address) { - assert_return(n, -EINVAL); - assert_return(address, -EINVAL); - - *address = n->destination_address; - return 0; -} - -_public_ int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) { - assert_return(n, -EINVAL); - assert_return(ret, -EINVAL); - assert_return(size, -EINVAL); - - *ret = LLDP_NEIGHBOR_RAW(n); - *size = n->raw_size; - - return 0; -} - -_public_ int sd_lldp_neighbor_get_chassis_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) { - assert_return(n, -EINVAL); - assert_return(type, -EINVAL); - assert_return(ret, -EINVAL); - assert_return(size, -EINVAL); - - assert(n->id.chassis_id_size > 0); - - *type = *(uint8_t*) n->id.chassis_id; - *ret = (uint8_t*) n->id.chassis_id + 1; - *size = n->id.chassis_id_size - 1; - - return 0; -} - -static int format_mac_address(const void *data, size_t sz, char **ret) { - struct ether_addr a; - char *k; - - assert(data || sz <= 0); - - if (sz != 7) - return 0; - - memcpy(&a, (uint8_t*) data + 1, sizeof(a)); - - k = new(char, ETHER_ADDR_TO_STRING_MAX); - if (!k) - return -ENOMEM; - - *ret = ether_addr_to_string(&a, k); - return 1; -} - -static int format_network_address(const void *data, size_t sz, char **ret) { - union in_addr_union a; - int family, r; - - if (sz == 6 && ((uint8_t*) data)[1] == 1) { - memcpy(&a.in, (uint8_t*) data + 2, sizeof(a.in)); - family = AF_INET; - } else if (sz == 18 && ((uint8_t*) data)[1] == 2) { - memcpy(&a.in6, (uint8_t*) data + 2, sizeof(a.in6)); - family = AF_INET6; - } else - return 0; - - r = in_addr_to_string(family, &a, ret); - if (r < 0) - return r; - return 1; -} - -_public_ int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret) { - char *k; - int r; - - assert_return(n, -EINVAL); - assert_return(ret, -EINVAL); - - if (n->chassis_id_as_string) { - *ret = n->chassis_id_as_string; - return 0; - } - - assert(n->id.chassis_id_size > 0); - - switch (*(uint8_t*) n->id.chassis_id) { - - case SD_LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT: - case SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS: - case SD_LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT: - case SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME: - case SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED: - k = cescape_length((char*) n->id.chassis_id + 1, n->id.chassis_id_size - 1); - if (!k) - return -ENOMEM; - - goto done; - - case SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: - r = format_mac_address(n->id.chassis_id, n->id.chassis_id_size, &k); - if (r < 0) - return r; - if (r > 0) - goto done; - - break; - - case SD_LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS: - r = format_network_address(n->id.chassis_id, n->id.chassis_id_size, &k); - if (r < 0) - return r; - if (r > 0) - goto done; - - break; - } - - /* Generic fallback */ - k = hexmem(n->id.chassis_id, n->id.chassis_id_size); - if (!k) - return -ENOMEM; - -done: - *ret = n->chassis_id_as_string = k; - return 0; -} - -_public_ int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) { - assert_return(n, -EINVAL); - assert_return(type, -EINVAL); - assert_return(ret, -EINVAL); - assert_return(size, -EINVAL); - - assert(n->id.port_id_size > 0); - - *type = *(uint8_t*) n->id.port_id; - *ret = (uint8_t*) n->id.port_id + 1; - *size = n->id.port_id_size - 1; - - return 0; -} - -_public_ int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const char **ret) { - char *k; - int r; - - assert_return(n, -EINVAL); - assert_return(ret, -EINVAL); - - if (n->port_id_as_string) { - *ret = n->port_id_as_string; - return 0; - } - - assert(n->id.port_id_size > 0); - - switch (*(uint8_t*) n->id.port_id) { - - case SD_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS: - case SD_LLDP_PORT_SUBTYPE_PORT_COMPONENT: - case SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME: - case SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED: - k = cescape_length((char*) n->id.port_id + 1, n->id.port_id_size - 1); - if (!k) - return -ENOMEM; - - goto done; - - case SD_LLDP_PORT_SUBTYPE_MAC_ADDRESS: - r = format_mac_address(n->id.port_id, n->id.port_id_size, &k); - if (r < 0) - return r; - if (r > 0) - goto done; - - break; - - case SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS: - r = format_network_address(n->id.port_id, n->id.port_id_size, &k); - if (r < 0) - return r; - if (r > 0) - goto done; - - break; - } - - /* Generic fallback */ - k = hexmem(n->id.port_id, n->id.port_id_size); - if (!k) - return -ENOMEM; - -done: - *ret = n->port_id_as_string = k; - return 0; -} - -_public_ int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret_sec) { - assert_return(n, -EINVAL); - assert_return(ret_sec, -EINVAL); - - *ret_sec = n->ttl; - return 0; -} - -_public_ int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret) { - assert_return(n, -EINVAL); - assert_return(ret, -EINVAL); - - if (!n->system_name) - return -ENODATA; - - *ret = n->system_name; - return 0; -} - -_public_ int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret) { - assert_return(n, -EINVAL); - assert_return(ret, -EINVAL); - - if (!n->system_description) - return -ENODATA; - - *ret = n->system_description; - return 0; -} - -_public_ int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret) { - assert_return(n, -EINVAL); - assert_return(ret, -EINVAL); - - if (!n->port_description) - return -ENODATA; - - *ret = n->port_description; - return 0; -} - -_public_ int sd_lldp_neighbor_get_mud_url(sd_lldp_neighbor *n, const char **ret) { - assert_return(n, -EINVAL); - assert_return(ret, -EINVAL); - - if (!n->mud_url) - return -ENODATA; - - *ret = n->mud_url; - return 0; -} - -_public_ int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret) { - assert_return(n, -EINVAL); - assert_return(ret, -EINVAL); - - if (!n->has_capabilities) - return -ENODATA; - - *ret = n->system_capabilities; - return 0; -} - -_public_ int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret) { - assert_return(n, -EINVAL); - assert_return(ret, -EINVAL); - - if (!n->has_capabilities) - return -ENODATA; - - *ret = n->enabled_capabilities; - return 0; -} - -_public_ int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size) { - _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; - int r; - - assert_return(ret, -EINVAL); - assert_return(raw || raw_size <= 0, -EINVAL); - - n = lldp_neighbor_new(raw_size); - if (!n) - return -ENOMEM; - - memcpy(LLDP_NEIGHBOR_RAW(n), raw, raw_size); - r = lldp_neighbor_parse(n); - if (r < 0) - return r; - - *ret = TAKE_PTR(n); - - return r; -} - -_public_ int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n) { - assert_return(n, -EINVAL); - - assert(n->raw_size >= sizeof(struct ether_header)); - n->rindex = sizeof(struct ether_header); - - return n->rindex < n->raw_size; -} - -_public_ int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n) { - size_t length; - - assert_return(n, -EINVAL); - - if (n->rindex == n->raw_size) /* EOF */ - return -ESPIPE; - - if (n->rindex + 2 > n->raw_size) /* Truncated message */ - return -EBADMSG; - - length = LLDP_NEIGHBOR_TLV_LENGTH(n); - if (n->rindex + 2 + length > n->raw_size) - return -EBADMSG; - - n->rindex += 2 + length; - return n->rindex < n->raw_size; -} - -_public_ int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type) { - assert_return(n, -EINVAL); - assert_return(type, -EINVAL); - - if (n->rindex == n->raw_size) /* EOF */ - return -ESPIPE; - - if (n->rindex + 2 > n->raw_size) - return -EBADMSG; - - *type = LLDP_NEIGHBOR_TLV_TYPE(n); - return 0; -} - -_public_ int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type) { - uint8_t k; - int r; - - assert_return(n, -EINVAL); - - r = sd_lldp_neighbor_tlv_get_type(n, &k); - if (r < 0) - return r; - - return type == k; -} - -_public_ int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t *subtype) { - const uint8_t *d; - size_t length; - int r; - - assert_return(n, -EINVAL); - assert_return(oui, -EINVAL); - assert_return(subtype, -EINVAL); - - r = sd_lldp_neighbor_tlv_is_type(n, SD_LLDP_TYPE_PRIVATE); - if (r < 0) - return r; - if (r == 0) - return -ENXIO; - - length = LLDP_NEIGHBOR_TLV_LENGTH(n); - if (length < 4) - return -EBADMSG; - - if (n->rindex + 2 + length > n->raw_size) - return -EBADMSG; - - d = LLDP_NEIGHBOR_TLV_DATA(n); - memcpy(oui, d, 3); - *subtype = d[3]; - - return 0; -} - -_public_ int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t subtype) { - uint8_t k[3], st; - int r; - - r = sd_lldp_neighbor_tlv_get_oui(n, k, &st); - if (r == -ENXIO) - return 0; - if (r < 0) - return r; - - return memcmp(k, oui, 3) == 0 && st == subtype; -} - -_public_ int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) { - size_t length; - - assert_return(n, -EINVAL); - assert_return(ret, -EINVAL); - assert_return(size, -EINVAL); - - /* Note that this returns the full TLV, including the TLV header */ - - if (n->rindex + 2 > n->raw_size) - return -EBADMSG; - - length = LLDP_NEIGHBOR_TLV_LENGTH(n); - if (n->rindex + 2 + length > n->raw_size) - return -EBADMSG; - - *ret = (uint8_t*) LLDP_NEIGHBOR_RAW(n) + n->rindex; - *size = length + 2; - - return 0; -} - -_public_ int sd_lldp_neighbor_get_timestamp(sd_lldp_neighbor *n, clockid_t clock, uint64_t *ret) { - assert_return(n, -EINVAL); - assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP); - assert_return(clock_supported(clock), -EOPNOTSUPP); - assert_return(ret, -EINVAL); - - if (!triple_timestamp_is_set(&n->timestamp)) - return -ENODATA; - - *ret = triple_timestamp_by_clock(&n->timestamp, clock); - return 0; -} diff --git a/src/core/systemd/src/libsystemd-network/lldp-neighbor.h b/src/core/systemd/src/libsystemd-network/lldp-neighbor.h deleted file mode 100644 index a5718c8c..00000000 --- a/src/core/systemd/src/libsystemd-network/lldp-neighbor.h +++ /dev/null @@ -1,92 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -#include -#include -#include - -#include "sd-lldp.h" - -#include "hash-funcs.h" -#include "lldp-internal.h" -#include "time-util.h" - -typedef struct LLDPNeighborID { - /* The spec calls this an "MSAP identifier" */ - void *chassis_id; - size_t chassis_id_size; - - void *port_id; - size_t port_id_size; -} LLDPNeighborID; - -struct sd_lldp_neighbor { - /* Neighbor objects stay around as long as they are linked into an "sd_lldp" object or n_ref > 0. */ - sd_lldp *lldp; - unsigned n_ref; - - triple_timestamp timestamp; - - usec_t until; - unsigned prioq_idx; - - struct ether_addr source_address; - struct ether_addr destination_address; - - LLDPNeighborID id; - - /* The raw packet size. The data is appended to the object, accessible via LLDP_NEIGHBOR_RAW() */ - size_t raw_size; - - /* The current read index for the iterative TLV interface */ - size_t rindex; - - /* And a couple of fields parsed out. */ - bool has_ttl:1; - bool has_capabilities:1; - bool has_port_vlan_id:1; - - uint16_t ttl; - - uint16_t system_capabilities; - uint16_t enabled_capabilities; - - char *port_description; - char *system_name; - char *system_description; - char *mud_url; - - uint16_t port_vlan_id; - - char *chassis_id_as_string; - char *port_id_as_string; -}; - -static inline void *LLDP_NEIGHBOR_RAW(const sd_lldp_neighbor *n) { - return (uint8_t*) n + ALIGN(sizeof(sd_lldp_neighbor)); -} - -static inline uint8_t LLDP_NEIGHBOR_TLV_TYPE(const sd_lldp_neighbor *n) { - return ((uint8_t*) LLDP_NEIGHBOR_RAW(n))[n->rindex] >> 1; -} - -static inline size_t LLDP_NEIGHBOR_TLV_LENGTH(const sd_lldp_neighbor *n) { - uint8_t *p; - - p = (uint8_t*) LLDP_NEIGHBOR_RAW(n) + n->rindex; - return p[1] + (((size_t) (p[0] & 1)) << 8); -} - -static inline void* LLDP_NEIGHBOR_TLV_DATA(const sd_lldp_neighbor *n) { - return ((uint8_t*) LLDP_NEIGHBOR_RAW(n)) + n->rindex + 2; -} - -extern const struct hash_ops lldp_neighbor_hash_ops; -int lldp_neighbor_id_compare_func(const LLDPNeighborID *x, const LLDPNeighborID *y); -int lldp_neighbor_prioq_compare_func(const void *a, const void *b); - -sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n); -sd_lldp_neighbor *lldp_neighbor_new(size_t raw_size); -int lldp_neighbor_parse(sd_lldp_neighbor *n); -void lldp_neighbor_start_ttl(sd_lldp_neighbor *n); -bool lldp_neighbor_equal(const sd_lldp_neighbor *a, const sd_lldp_neighbor *b); diff --git a/src/core/systemd/src/libsystemd-network/lldp-network.c b/src/core/systemd/src/libsystemd-network/lldp-network.c deleted file mode 100644 index 75dce58c..00000000 --- a/src/core/systemd/src/libsystemd-network/lldp-network.c +++ /dev/null @@ -1,80 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include "nm-sd-adapt-core.h" - -#include -#include - -#include "fd-util.h" -#include "lldp-network.h" -#include "missing_network.h" -#include "socket-util.h" - -int lldp_network_bind_raw_socket(int ifindex) { - - static const struct sock_filter filter[] = { - BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ethhdr, 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(struct ethhdr, 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(struct ethhdr, 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 */ - }; - - static const struct sock_fprog fprog = { - .len = ELEMENTSOF(filter), - .filter = (struct sock_filter*) filter, - }; - - struct packet_mreq mreq = { - .mr_ifindex = ifindex, - .mr_type = PACKET_MR_MULTICAST, - .mr_alen = ETH_ALEN, - .mr_address = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x00 } - }; - - union sockaddr_union saddrll = { - .ll.sll_family = AF_PACKET, - .ll.sll_ifindex = ifindex, - }; - - _cleanup_close_ int fd = -1; - int r; - - assert(ifindex > 0); - - fd = socket(AF_PACKET, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, - htobe16(ETHERTYPE_LLDP)); - if (fd < 0) - return -errno; - - r = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)); - if (r < 0) - return -errno; - - r = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); - if (r < 0) - return -errno; - - mreq.mr_address[ETH_ALEN - 1] = 0x03; - r = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); - if (r < 0) - return -errno; - - mreq.mr_address[ETH_ALEN - 1] = 0x0E; - r = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); - if (r < 0) - return -errno; - - r = bind(fd, &saddrll.sa, sizeof(saddrll.ll)); - if (r < 0) - return -errno; - - return TAKE_FD(fd); -} diff --git a/src/core/systemd/src/libsystemd-network/lldp-network.h b/src/core/systemd/src/libsystemd-network/lldp-network.h deleted file mode 100644 index bc69b324..00000000 --- a/src/core/systemd/src/libsystemd-network/lldp-network.h +++ /dev/null @@ -1,6 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -#include "sd-event.h" - -int lldp_network_bind_raw_socket(int ifindex); diff --git a/src/core/systemd/src/libsystemd-network/network-internal.c b/src/core/systemd/src/libsystemd-network/network-internal.c deleted file mode 100644 index efa3dcfa..00000000 --- a/src/core/systemd/src/libsystemd-network/network-internal.c +++ /dev/null @@ -1,245 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include "nm-sd-adapt-core.h" - -#include -#include -#include - -#include "sd-ndisc.h" - -#include "alloc-util.h" -#include "dhcp-lease-internal.h" -#include "extract-word.h" -#include "hexdecoct.h" -#include "log.h" -#include "network-internal.h" -#include "parse-util.h" - -size_t serialize_in_addrs(FILE *f, - const struct in_addr *addresses, - size_t size, - bool *with_leading_space, - bool (*predicate)(const struct in_addr *addr)) { - assert(f); - assert(addresses); - - size_t count = 0; - bool _space = false; - if (!with_leading_space) - with_leading_space = &_space; - - for (size_t i = 0; i < size; i++) { - char sbuf[INET_ADDRSTRLEN]; - - if (predicate && !predicate(&addresses[i])) - continue; - - if (*with_leading_space) - fputc(' ', f); - fputs(inet_ntop(AF_INET, &addresses[i], sbuf, sizeof(sbuf)), f); - count++; - *with_leading_space = true; - } - - return count; -} - -int deserialize_in_addrs(struct in_addr **ret, const char *string) { - _cleanup_free_ struct in_addr *addresses = NULL; - int size = 0; - - assert(ret); - assert(string); - - for (;;) { - _cleanup_free_ char *word = NULL; - struct in_addr *new_addresses; - int r; - - r = extract_first_word(&string, &word, NULL, 0); - if (r < 0) - return r; - if (r == 0) - break; - - new_addresses = reallocarray(addresses, size + 1, sizeof(struct in_addr)); - if (!new_addresses) - return -ENOMEM; - else - addresses = new_addresses; - - r = inet_pton(AF_INET, word, &(addresses[size])); - if (r <= 0) - continue; - - size++; - } - - *ret = size > 0 ? TAKE_PTR(addresses) : NULL; - - return size; -} - -void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, size_t size, bool *with_leading_space) { - assert(f); - assert(addresses); - assert(size); - - bool _space = false; - if (!with_leading_space) - with_leading_space = &_space; - - for (size_t i = 0; i < size; i++) { - char buffer[INET6_ADDRSTRLEN]; - - if (*with_leading_space) - fputc(' ', f); - fputs(inet_ntop(AF_INET6, addresses+i, buffer, sizeof(buffer)), f); - *with_leading_space = true; - } -} - -int deserialize_in6_addrs(struct in6_addr **ret, const char *string) { - _cleanup_free_ struct in6_addr *addresses = NULL; - int size = 0; - - assert(ret); - assert(string); - - for (;;) { - _cleanup_free_ char *word = NULL; - struct in6_addr *new_addresses; - int r; - - r = extract_first_word(&string, &word, NULL, 0); - if (r < 0) - return r; - if (r == 0) - break; - - new_addresses = reallocarray(addresses, size + 1, sizeof(struct in6_addr)); - if (!new_addresses) - return -ENOMEM; - else - addresses = new_addresses; - - r = inet_pton(AF_INET6, word, &(addresses[size])); - if (r <= 0) - continue; - - size++; - } - - *ret = TAKE_PTR(addresses); - - return size; -} - -void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size) { - assert(f); - assert(key); - assert(routes); - assert(size); - - fprintf(f, "%s=", key); - - for (size_t i = 0; i < size; i++) { - char sbuf[INET_ADDRSTRLEN]; - struct in_addr dest, gw; - uint8_t length; - - assert_se(sd_dhcp_route_get_destination(routes[i], &dest) >= 0); - assert_se(sd_dhcp_route_get_gateway(routes[i], &gw) >= 0); - assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &length) >= 0); - - fprintf(f, "%s/%" PRIu8, inet_ntop(AF_INET, &dest, sbuf, sizeof sbuf), length); - fprintf(f, ",%s%s", inet_ntop(AF_INET, &gw, sbuf, sizeof sbuf), 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; - - assert(ret); - assert(ret_size); - assert(ret_allocated); - assert(string); - - /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */ - for (;;) { - _cleanup_free_ char *word = NULL; - char *tok, *tok_end; - unsigned n; - int r; - - r = extract_first_word(&string, &word, NULL, 0); - if (r < 0) - return r; - if (r == 0) - break; - - if (!GREEDY_REALLOC(routes, allocated, size + 1)) - return -ENOMEM; - - tok = word; - - /* 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 = TAKE_PTR(routes); - - 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) - return -ENOMEM; - - fprintf(f, "%s=%s\n", key, hex_buf); - - return 0; -} diff --git a/src/core/systemd/src/libsystemd-network/network-internal.h b/src/core/systemd/src/libsystemd-network/network-internal.h deleted file mode 100644 index e5b853c0..00000000 --- a/src/core/systemd/src/libsystemd-network/network-internal.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -#include -#include - -#include "sd-dhcp-lease.h" - -size_t serialize_in_addrs(FILE *f, - const struct in_addr *addresses, - size_t size, - bool *with_leading_space, - bool (*predicate)(const struct in_addr *addr)); -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, - bool *with_leading_space); -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; -struct sd_dhcp_lease; - -void serialize_dhcp_routes(FILE *f, const char *key, 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); - -/* It is not necessary to add deserialize_dhcp_option(). Use unhexmem() instead. */ -int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size); - -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/core/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/core/systemd/src/libsystemd-network/sd-dhcp-client.c deleted file mode 100644 index 27a3476f..00000000 --- a/src/core/systemd/src/libsystemd-network/sd-dhcp-client.c +++ /dev/null @@ -1,2258 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/*** - Copyright © 2013 Intel Corporation. All rights reserved. -***/ - -#include "nm-sd-adapt-core.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "sd-dhcp-client.h" - -#include "alloc-util.h" -#include "dhcp-identifier.h" -#include "dhcp-internal.h" -#include "dhcp-lease-internal.h" -#include "dhcp-protocol.h" -#include "dns-domain.h" -#include "event-util.h" -#include "fd-util.h" -#include "hostname-util.h" -#include "io-util.h" -#include "memory-util.h" -#include "random-util.h" -#include "set.h" -#include "sort-util.h" -#include "string-util.h" -#include "strv.h" -#include "time-util.h" -#include "utf8.h" -#include "web-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) - -#define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC) -#define RESTART_AFTER_NAK_MAX_USEC (30 * USEC_PER_MINUTE) - -#define TRANSIENT_FAILURE_ATTEMPTS 3 /* Arbitrary limit: how many attempts are considered enough to report - * transient failure. */ - -typedef struct sd_dhcp_client_id { - 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) */ - be32_t iaid; - struct duid duid; - } _packed_ ns; - struct { - uint8_t data[MAX_CLIENT_ID_LEN]; - } _packed_ raw; - }; -} _packed_ sd_dhcp_client_id; - -struct sd_dhcp_client { - unsigned n_ref; - - DHCPState state; - sd_event *event; - int event_priority; - sd_event_source *timeout_resend; - int ifindex; - int fd; - uint16_t port; - union sockaddr_union link; - sd_event_source *receive_message; - bool request_broadcast; - Set *req_opts; - bool anonymize; - be32_t last_addr; - uint8_t mac_addr[MAX_MAC_ADDR_LEN]; - size_t mac_addr_len; - uint8_t bcast_addr[MAX_MAC_ADDR_LEN]; - size_t bcast_addr_len; - uint16_t arp_type; - sd_dhcp_client_id client_id; - size_t client_id_len; - char *hostname; - char *vendor_class_identifier; - char *mudurl; - char **user_class; - uint32_t mtu; - uint32_t fallback_lease_lifetime; - uint32_t xid; - usec_t start_time; - usec_t t1_time; - usec_t t2_time; - usec_t expire_time; - uint64_t attempt; - uint64_t max_attempts; - OrderedHashmap *extra_options; - OrderedHashmap *vendor_options; - usec_t request_sent; - sd_event_source *timeout_t1; - sd_event_source *timeout_t2; - sd_event_source *timeout_expire; - sd_dhcp_client_callback_t callback; - void *userdata; - sd_dhcp_lease *lease; - usec_t start_delay; - int ip_service_type; -}; - -static const uint8_t default_req_opts[] = { - SD_DHCP_OPTION_SUBNET_MASK, - SD_DHCP_OPTION_ROUTER, - SD_DHCP_OPTION_HOST_NAME, - SD_DHCP_OPTION_DOMAIN_NAME, - SD_DHCP_OPTION_DOMAIN_NAME_SERVER, -}; - -/* RFC7844 section 3: - MAY contain the Parameter Request List option. - RFC7844 section 3.6: - The client intending to protect its privacy SHOULD only request a - minimal number of options in the PRL and SHOULD also randomly shuffle - the ordering of option codes in the PRL. If this random ordering - cannot be implemented, the client MAY order the option codes in the - PRL by option code number (lowest to highest). -*/ -/* NOTE: using PRL options that Windows 10 RFC7844 implementation uses */ -static const uint8_t default_req_opts_anonymize[] = { - SD_DHCP_OPTION_SUBNET_MASK, /* 1 */ - SD_DHCP_OPTION_ROUTER, /* 3 */ - SD_DHCP_OPTION_DOMAIN_NAME_SERVER, /* 6 */ - SD_DHCP_OPTION_DOMAIN_NAME, /* 15 */ - SD_DHCP_OPTION_ROUTER_DISCOVER, /* 31 */ - SD_DHCP_OPTION_STATIC_ROUTE, /* 33 */ - SD_DHCP_OPTION_VENDOR_SPECIFIC, /* 43 */ - SD_DHCP_OPTION_NETBIOS_NAMESERVER, /* 44 */ - SD_DHCP_OPTION_NETBIOS_NODETYPE, /* 46 */ - SD_DHCP_OPTION_NETBIOS_SCOPE, /* 47 */ - SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE, /* 121 */ - SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE, /* 249 */ - SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY, /* 252 */ -}; - -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_id_to_string(const void *data, size_t len, char **ret) { - const sd_dhcp_client_id *client_id = data; - _cleanup_free_ char *t = NULL; - int r = 0; - - assert_return(data, -EINVAL); - assert_return(len >= 1, -EINVAL); - assert_return(ret, -EINVAL); - - len -= 1; - if (len > MAX_CLIENT_ID_LEN) - return -EINVAL; - - switch (client_id->type) { - case 0: - if (utf8_is_printable((char *) client_id->gen.data, len)) - r = asprintf(&t, "%.*s", (int) len, client_id->gen.data); - else - r = asprintf(&t, "DATA"); - break; - case 1: - if (len != sizeof_field(sd_dhcp_client_id, eth)) - return -EINVAL; - - r = asprintf(&t, "%x:%x:%x:%x:%x:%x", - client_id->eth.haddr[0], - client_id->eth.haddr[1], - client_id->eth.haddr[2], - client_id->eth.haddr[3], - client_id->eth.haddr[4], - client_id->eth.haddr[5]); - break; - case 2 ... 254: - r = asprintf(&t, "ARP/LL"); - break; - case 255: - if (len < 6) - return -EINVAL; - - uint32_t iaid = be32toh(client_id->ns.iaid); - uint16_t duid_type = be16toh(client_id->ns.duid.type); - if (dhcp_validate_duid_len(duid_type, len - 6, true) < 0) - return -EINVAL; - - r = asprintf(&t, "IAID:0x%x/DUID", iaid); - break; - } - - if (r < 0) - return -ENOMEM; - *ret = TAKE_PTR(t); - return 0; -} - -int sd_dhcp_client_set_callback( - sd_dhcp_client *client, - sd_dhcp_client_callback_t cb, - void *userdata) { - - assert_return(client, -EINVAL); - - client->callback = 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) { - assert_return(client, -EINVAL); - assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY); - - switch(option) { - - case SD_DHCP_OPTION_PAD: - case SD_DHCP_OPTION_OVERLOAD: - case SD_DHCP_OPTION_MESSAGE_TYPE: - case SD_DHCP_OPTION_PARAMETER_REQUEST_LIST: - case SD_DHCP_OPTION_END: - return -EINVAL; - - default: - break; - } - - return set_ensure_put(&client->req_opts, NULL, UINT8_TO_PTR(option)); -} - -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_ifindex(sd_dhcp_client *client, int ifindex) { - - assert_return(client, -EINVAL); - assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY); - assert_return(ifindex > 0, -EINVAL); - - client->ifindex = ifindex; - return 0; -} - -int sd_dhcp_client_set_mac( - sd_dhcp_client *client, - const uint8_t *addr, - const uint8_t *bcast_addr, - size_t addr_len, - uint16_t arp_type) { - - DHCP_CLIENT_DONT_DESTROY(client); - bool need_restart = false; - int r; - - 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 && - (client->bcast_addr_len > 0) == !!bcast_addr && - (!bcast_addr || memcmp(&client->bcast_addr, bcast_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; - client->bcast_addr_len = 0; - - if (bcast_addr) { - memcpy(&client->bcast_addr, bcast_addr, addr_len); - client->bcast_addr_len = addr_len; - } - - if (need_restart && client->state != DHCP_STATE_STOPPED) { - r = sd_dhcp_client_start(client); - if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to restart DHCPv4 client: %m"); - } - - 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; - int r; - - assert_return(client, -EINVAL); - assert_return(data, -EINVAL); - assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL); - G_STATIC_ASSERT_EXPR (_NM_SD_MAX_CLIENT_ID_LEN == MAX_CLIENT_ID_LEN); - - 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; - - /* For hardware types, log debug message about unexpected data length. - * - * Note that infiniband's INFINIBAND_ALEN is 20 bytes long, but only - * the last 8 bytes of the address are stable and suitable to put into - * the client-id. The caller is advised to account for that. */ - if ((type == ARPHRD_ETHER && data_len != ETH_ALEN) || - (type == ARPHRD_INFINIBAND && data_len != 8)) - log_dhcp_client(client, "Changing client ID to hardware type %u with " - "unexpected address length %zu", - type, data_len); - - 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) { - r = sd_dhcp_client_start(client); - if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to restart DHCPv4 client: %m"); - } - - return 0; -} - -#if 0 /* NM_IGNORED */ -/** - * Sets IAID and DUID. If duid is non-null, the DUID is set to duid_type + duid - * without further modification. Otherwise, if duid_type is supported, DUID - * is set based on that type. Otherwise, an error is returned. - */ -static int dhcp_client_set_iaid_duid_internal( - sd_dhcp_client *client, - bool iaid_append, - bool iaid_set, - uint32_t iaid, - uint16_t duid_type, - const void *duid, - size_t duid_len, - usec_t llt_time) { - - DHCP_CLIENT_DONT_DESTROY(client); - int r; - size_t len; - - assert_return(client, -EINVAL); - assert_return(duid_len == 0 || duid, -EINVAL); - - if (duid) { - r = dhcp_validate_duid_len(duid_type, duid_len, true); - if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to validate length of DUID: %m"); - } - - zero(client->client_id); - client->client_id.type = 255; - - if (iaid_append) { - if (iaid_set) - client->client_id.ns.iaid = htobe32(iaid); - else { - r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, - client->mac_addr_len, - true, - &client->client_id.ns.iaid); - if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to set IAID: %m"); - } - } - - if (duid) { - client->client_id.ns.duid.type = htobe16(duid_type); - memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len); - len = sizeof(client->client_id.ns.duid.type) + duid_len; - } else - switch (duid_type) { - case DUID_TYPE_LLT: - if (client->mac_addr_len == 0) - return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EOPNOTSUPP), "Failed to set DUID-LLT, MAC address is not set."); - - r = dhcp_identifier_set_duid_llt(&client->client_id.ns.duid, llt_time, client->mac_addr, client->mac_addr_len, client->arp_type, &len); - if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to set DUID-LLT: %m"); - break; - case DUID_TYPE_EN: - r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len); - if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to set DUID-EN: %m"); - break; - case DUID_TYPE_LL: - if (client->mac_addr_len == 0) - return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EOPNOTSUPP), "Failed to set DUID-LL, MAC address is not set."); - - r = dhcp_identifier_set_duid_ll(&client->client_id.ns.duid, client->mac_addr, client->mac_addr_len, client->arp_type, &len); - if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to set DUID-LL: %m"); - break; - case DUID_TYPE_UUID: - r = dhcp_identifier_set_duid_uuid(&client->client_id.ns.duid, &len); - if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to set DUID-UUID: %m"); - break; - default: - return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "Invalid DUID type"); - } - - client->client_id_len = sizeof(client->client_id.type) + len + - (iaid_append ? sizeof(client->client_id.ns.iaid) : 0); - - if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { - log_dhcp_client(client, "Configured %sDUID, restarting.", iaid_append ? "IAID+" : ""); - client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); - r = sd_dhcp_client_start(client); - if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to restart DHCPv4 client: %m"); - } - - return 0; -} - -int sd_dhcp_client_set_iaid_duid( - sd_dhcp_client *client, - bool iaid_set, - uint32_t iaid, - uint16_t duid_type, - const void *duid, - size_t duid_len) { - return dhcp_client_set_iaid_duid_internal(client, true, iaid_set, iaid, duid_type, duid, duid_len, 0); -} - -int sd_dhcp_client_set_iaid_duid_llt( - sd_dhcp_client *client, - bool iaid_set, - uint32_t iaid, - usec_t llt_time) { - return dhcp_client_set_iaid_duid_internal(client, true, iaid_set, iaid, DUID_TYPE_LLT, NULL, 0, llt_time); -} - -int sd_dhcp_client_set_duid( - sd_dhcp_client *client, - uint16_t duid_type, - const void *duid, - size_t duid_len) { - return dhcp_client_set_iaid_duid_internal(client, false, false, 0, duid_type, duid, duid_len, 0); -} - -int sd_dhcp_client_set_duid_llt( - sd_dhcp_client *client, - usec_t llt_time) { - return dhcp_client_set_iaid_duid_internal(client, false, false, 0, DUID_TYPE_LLT, NULL, 0, llt_time); -} -#endif /* NM_IGNORED */ - -int sd_dhcp_client_set_hostname( - sd_dhcp_client *client, - const char *hostname) { - - assert_return(client, -EINVAL); - - /* Make sure hostnames qualify as DNS and as Linux hostnames */ - if (hostname && - !(hostname_is_valid(hostname, 0) && dns_name_is_valid(hostname) > 0)) - return -EINVAL; - - return free_and_strdup(&client->hostname, hostname); -} - -int sd_dhcp_client_set_vendor_class_identifier( - sd_dhcp_client *client, - const char *vci) { - - assert_return(client, -EINVAL); - - return free_and_strdup(&client->vendor_class_identifier, vci); -} - -int sd_dhcp_client_set_mud_url( - sd_dhcp_client *client, - const char *mudurl) { - - assert_return(client, -EINVAL); - assert_return(mudurl, -EINVAL); - assert_return(strlen(mudurl) <= 255, -EINVAL); - assert_return(http_url_is_valid(mudurl), -EINVAL); - - return free_and_strdup(&client->mudurl, mudurl); -} - -int sd_dhcp_client_set_user_class( - sd_dhcp_client *client, - const char* const* user_class) { - - _cleanup_strv_free_ char **s = NULL; - char **p; - - STRV_FOREACH(p, (char **) user_class) - if (strlen(*p) > 255) - return -ENAMETOOLONG; - - s = strv_copy((char **) user_class); - if (!s) - return -ENOMEM; - - client->user_class = TAKE_PTR(s); - - return 0; -} - -int sd_dhcp_client_set_client_port( - sd_dhcp_client *client, - uint16_t port) { - - assert_return(client, -EINVAL); - - client->port = port; - - 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_set_max_attempts(sd_dhcp_client *client, uint64_t max_attempts) { - assert_return(client, -EINVAL); - - client->max_attempts = max_attempts; - - return 0; -} - -int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v) { - int r; - - assert_return(client, -EINVAL); - assert_return(v, -EINVAL); - - r = ordered_hashmap_ensure_allocated(&client->extra_options, &dhcp_option_hash_ops); - if (r < 0) - return r; - - r = ordered_hashmap_put(client->extra_options, UINT_TO_PTR(v->option), v); - if (r < 0) - return r; - - sd_dhcp_option_ref(v); - return 0; -} - -int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v) { - int r; - - assert_return(client, -EINVAL); - assert_return(v, -EINVAL); - - r = ordered_hashmap_ensure_allocated(&client->vendor_options, &dhcp_option_hash_ops); - if (r < 0) - return -ENOMEM; - - r = ordered_hashmap_put(client->vendor_options, v, v); - if (r < 0) - return r; - - sd_dhcp_option_ref(v); - - return 1; -} - -int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) { - assert_return(client, -EINVAL); - - if (!IN_SET(client->state, DHCP_STATE_SELECTING, DHCP_STATE_BOUND, DHCP_STATE_RENEWING, DHCP_STATE_REBINDING)) - return -EADDRNOTAVAIL; - - if (ret) - *ret = client->lease; - - return 0; -} - -int sd_dhcp_client_set_service_type(sd_dhcp_client *client, int type) { - assert_return(client, -EINVAL); - - client->ip_service_type = type; - - return 0; -} - -int sd_dhcp_client_set_fallback_lease_lifetime(sd_dhcp_client *client, uint32_t fallback_lease_lifetime) { - assert_return(client, -EINVAL); - assert_return(fallback_lease_lifetime > 0, -EINVAL); - - client->fallback_lease_lifetime = fallback_lease_lifetime; - - return 0; -} - -static int client_notify(sd_dhcp_client *client, int event) { - assert(client); - - if (client->callback) - return client->callback(client, event, client->userdata); - - return 0; -} - -static int client_initialize(sd_dhcp_client *client) { - assert_return(client, -EINVAL); - - client->receive_message = sd_event_source_unref(client->receive_message); - - client->fd = safe_close(client->fd); - - (void) event_source_disable(client->timeout_resend); - (void) event_source_disable(client->timeout_t1); - (void) event_source_disable(client->timeout_t2); - (void) event_source_disable(client->timeout_expire); - - client->attempt = 0; - - 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_errno(client, error, "STOPPED: %m"); - 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); -} - -/* RFC2131 section 4.1: - * retransmission delays should include -1 to +1 sec of random 'fuzz'. */ -#define RFC2131_RANDOM_FUZZ \ - ((int64_t)(random_u64() % (2 * USEC_PER_SEC)) - (int64_t)USEC_PER_SEC) - -/* RFC2131 section 4.1: - * for retransmission delays, timeout should start at 4s then double - * each attempt with max of 64s, with -1 to +1 sec of random 'fuzz' added. - * This assumes the first call will be using attempt 1. */ -static usec_t client_compute_request_timeout(usec_t now, uint64_t attempt) { - usec_t timeout = (UINT64_C(1) << MIN(attempt + 1, UINT64_C(6))) * USEC_PER_SEC; - - return usec_sub_signed(usec_add(now, timeout), RFC2131_RANDOM_FUZZ); -} - -/* RFC2131 section 4.4.5: - * T1 defaults to (0.5 * duration_of_lease). - * T2 defaults to (0.875 * duration_of_lease). */ -#define T1_DEFAULT(lifetime) ((lifetime) / 2) -#define T2_DEFAULT(lifetime) (((lifetime) * 7) / 8) - -/* RFC2131 section 4.4.5: - * the client SHOULD wait one-half of the remaining time until T2 (in RENEWING state) - * and one-half of the remaining lease time (in REBINDING state), down to a minimum - * of 60 seconds. - * Note that while the default T1/T2 initial times do have random 'fuzz' applied, - * the RFC sec 4.4.5 does not mention adding any fuzz to retries. */ -static usec_t client_compute_reacquisition_timeout(usec_t now, usec_t expire) { - return now + MAX(usec_sub_unsigned(expire, now) / 2, 60 * USEC_PER_SEC); -} - -static int cmp_uint8(const uint8_t *a, const uint8_t *b) { - return CMP(*a, *b); -} - -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(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST, DHCP_RELEASE, DHCP_DECLINE)); - - 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->ifindex, client->mac_addr, client->mac_addr_len, - true, &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, - SD_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. - */ - - /* RFC7844 section 3: - MAY contain the Parameter Request List option. */ - /* NOTE: in case that there would be an option to do not send - * any PRL at all, the size should be checked before sending */ - if (!set_isempty(client->req_opts) && type != DHCP_RELEASE) { - _cleanup_free_ uint8_t *opts = NULL; - size_t n_opts, i = 0; - void *val; - - n_opts = set_size(client->req_opts); - opts = new(uint8_t, n_opts); - if (!opts) - return -ENOMEM; - - SET_FOREACH(val, client->req_opts) - opts[i++] = PTR_TO_UINT8(val); - assert(i == n_opts); - - /* For anonymizing the request, let's sort the options. */ - typesafe_qsort(opts, n_opts, cmp_uint8); - - r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0, - SD_DHCP_OPTION_PARAMETER_REQUEST_LIST, - n_opts, 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 Message 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.) - */ - /* RFC7844 section 3: - SHOULD NOT contain any other option. */ - if (!client->anonymize && type != DHCP_RELEASE) { - max_size = htobe16(size); - r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0, - SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE, - 2, &max_size); - if (r < 0) - return r; - } - - *_optlen = optlen; - *_optoffset = optoffset; - *ret = TAKE_PTR(packet); - - 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, - SD_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, client->port, - INADDR_BROADCAST, DHCP_PORT_SERVER, len, client->ip_service_type); - - return dhcp_network_send_raw_socket(client->fd, &client->link, - packet, len); -} - -static int client_append_common_discover_request_options(sd_dhcp_client *client, DHCPPacket *packet, size_t *optoffset, size_t optlen) { - sd_dhcp_option *j; - int r; - - assert(client); - - 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(&packet->dhcp, optlen, optoffset, 0, - SD_DHCP_OPTION_HOST_NAME, - strlen(client->hostname), client->hostname); - } else - r = client_append_fqdn_option(&packet->dhcp, optlen, optoffset, - client->hostname); - if (r < 0) - return r; - } - - if (client->vendor_class_identifier) { - r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0, - SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER, - strlen(client->vendor_class_identifier), - client->vendor_class_identifier); - if (r < 0) - return r; - } - - if (client->mudurl) { - r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0, - SD_DHCP_OPTION_MUD_URL, - strlen(client->mudurl), - client->mudurl); - if (r < 0) - return r; - } - - if (client->user_class) { - r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0, - SD_DHCP_OPTION_USER_CLASS, - strv_length(client->user_class), - client->user_class); - if (r < 0) - return r; - } - - ORDERED_HASHMAP_FOREACH(j, client->extra_options) { - r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0, - j->option, j->length, j->data); - if (r < 0) - return r; - } - - if (!ordered_hashmap_isempty(client->vendor_options)) { - r = dhcp_option_append( - &packet->dhcp, optlen, optoffset, 0, - SD_DHCP_OPTION_VENDOR_SPECIFIC, - ordered_hashmap_size(client->vendor_options), client->vendor_options); - if (r < 0) - return r; - } - - - return 0; -} - -static int client_send_discover(sd_dhcp_client *client) { - _cleanup_free_ DHCPPacket *discover = NULL; - size_t optoffset, optlen; - int r; - - assert(client); - assert(IN_SET(client->state, DHCP_STATE_INIT, 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. - */ - /* RFC7844 section 3: - SHOULD NOT contain any other option. */ - if (!client->anonymize && client->last_addr != INADDR_ANY) { - r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, - SD_DHCP_OPTION_REQUESTED_IP_ADDRESS, - 4, &client->last_addr); - if (r < 0) - return r; - } - - r = client_append_common_discover_request_options(client, discover, &optoffset, optlen); - if (r < 0) - return r; - - r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, - SD_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; - - assert(client); - - 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, - SD_DHCP_OPTION_SERVER_IDENTIFIER, - 4, &client->lease->server_address); - if (r < 0) - return r; - - r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, - SD_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, - SD_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. - */ - - 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; - } - - r = client_append_common_discover_request_options(client, request, &optoffset, optlen); - if (r < 0) - return r; - - r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, - SD_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; - uint64_t time_now; - 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: - next_timeout = client_compute_reacquisition_timeout(time_now, client->t2_time); - break; - - case DHCP_STATE_REBINDING: - next_timeout = client_compute_reacquisition_timeout(time_now, client->expire_time); - 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; - - 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 >= client->max_attempts) - goto error; - - client->attempt++; - next_timeout = client_compute_request_timeout(time_now, client->attempt); - break; - - case DHCP_STATE_STOPPED: - r = -EINVAL; - goto error; - - default: - assert_not_reached("Unhandled choice"); - } - - r = event_reset_time(client->event, &client->timeout_resend, - clock_boottime_or_monotonic(), - next_timeout, 10 * USEC_PER_MSEC, - client_timeout_resend, client, - client->event_priority, "dhcp4-resend-timer", true); - 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 = 0; - } else if (client->attempt >= client->max_attempts) - goto error; - - break; - - case DHCP_STATE_SELECTING: - r = client_send_discover(client); - if (r < 0 && client->attempt >= client->max_attempts) - 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 >= client->max_attempts) - 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; - } - - if (client->attempt >= TRANSIENT_FAILURE_ATTEMPTS) - client_notify(client, SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE); - - 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) { - uint64_t usec = 0; - int r; - - assert(client); - assert(client->event); - - if (client->start_delay > 0) { - assert_se(sd_event_now(client->event, clock_boottime_or_monotonic(), &usec) >= 0); - usec += client->start_delay; - } - - r = event_reset_time(client->event, &client->timeout_resend, - clock_boottime_or_monotonic(), - usec, 0, - client_timeout_resend, client, - client->event_priority, "dhcp4-resend-timer", true); - 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_delayed(sd_dhcp_client *client) { - int r; - - assert_return(client, -EINVAL); - assert_return(client->event, -EINVAL); - assert_return(client->ifindex > 0, -EINVAL); - assert_return(client->fd < 0, -EBUSY); - assert_return(client->xid == 0, -EINVAL); - assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT), -EBUSY); - - client->xid = random_u32(); - - r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid, - client->mac_addr, client->mac_addr_len, - client->bcast_addr, client->bcast_addr_len, - client->arp_type, client->port); - if (r < 0) { - client_stop(client, r); - return r; - } - client->fd = r; - - if (IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT)) - client->start_time = now(clock_boottime_or_monotonic()); - - return client_initialize_events(client, client_receive_message_raw); -} - -static int client_start(sd_dhcp_client *client) { - client->start_delay = 0; - return client_start_delayed(client); -} - -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; - - assert(client); - - client->receive_message = sd_event_source_unref(client->receive_message); - client->fd = safe_close(client->fd); - - client->state = DHCP_STATE_REBINDING; - client->attempt = 0; - - r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid, - client->mac_addr, client->mac_addr_len, - client->bcast_addr, client->bcast_addr_len, - client->arp_type, client->port); - 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); - - if (client->lease) - client->state = DHCP_STATE_RENEWING; - else if (client->state != DHCP_STATE_INIT) - client->state = DHCP_STATE_INIT_REBOOT; - client->attempt = 0; - - 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->lifetime == 0 && client->fallback_lease_lifetime > 0) - lease->lifetime = client->fallback_lease_lifetime; - - 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 cannot be generated, ignoring"); - return -ENOMSG; - } - } - - sd_dhcp_lease_unref(client->lease); - client->lease = TAKE_PTR(lease); - - if (client_notify(client, SD_DHCP_CLIENT_EVENT_SELECTING) < 0) - return -ENOMSG; - - 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 bool lease_equal(const sd_dhcp_lease *a, const sd_dhcp_lease *b) { - if (a->address != b->address) - return false; - - if (a->subnet_mask != b->subnet_mask) - return false; - - if (a->router_size != b->router_size) - return false; - - for (size_t i = 0; i < a->router_size; i++) - if (a->router[i].s_addr != b->router[i].s_addr) - return false; - - return true; -} - -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 cannot be generated, ignoring"); - return -ENOMSG; - } - } - - r = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE; - if (client->lease) { - if (lease_equal(client->lease, lease)) - r = SD_DHCP_CLIENT_EVENT_RENEW; - else - r = SD_DHCP_CLIENT_EVENT_IP_CHANGE; - - client->lease = sd_dhcp_lease_unref(client->lease); - } - - client->lease = TAKE_PTR(lease); - - log_dhcp_client(client, "ACK"); - - return r; -} - -static int client_set_lease_timeouts(sd_dhcp_client *client) { - usec_t time_now; - char time_string[FORMAT_TIMESPAN_MAX]; - int r; - - assert(client); - assert(client->event); - assert(client->lease); - assert(client->lease->lifetime); - - /* don't set timers for infinite leases */ - if (client->lease->lifetime == 0xffffffff) { - (void) event_source_disable(client->timeout_t1); - (void) event_source_disable(client->timeout_t2); - (void) event_source_disable(client->timeout_expire); - - 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); - - /* verify that 0 < t2 < lifetime */ - if (client->lease->t2 == 0 || client->lease->t2 >= client->lease->lifetime) - client->lease->t2 = T2_DEFAULT(client->lease->lifetime); - /* verify that 0 < t1 < lifetime */ - if (client->lease->t1 == 0 || client->lease->t1 >= client->lease->t2) - client->lease->t1 = T1_DEFAULT(client->lease->lifetime); - /* now, if t1 >= t2, t1 *must* be T1_DEFAULT, since the previous check - * could not evalate to false if t1 >= t2; so setting t2 to T2_DEFAULT - * guarantees t1 < t2. */ - if (client->lease->t1 >= client->lease->t2) - client->lease->t2 = T2_DEFAULT(client->lease->lifetime); - - client->expire_time = client->request_sent + client->lease->lifetime * USEC_PER_SEC; - client->t1_time = client->request_sent + client->lease->t1 * USEC_PER_SEC; - client->t2_time = client->request_sent + client->lease->t2 * USEC_PER_SEC; - - /* RFC2131 section 4.4.5: - * Times T1 and T2 SHOULD be chosen with some random "fuzz". - * Since the RFC doesn't specify here the exact 'fuzz' to use, - * we use the range from section 4.1: -1 to +1 sec. */ - client->t1_time = usec_sub_signed(client->t1_time, RFC2131_RANDOM_FUZZ); - client->t2_time = usec_sub_signed(client->t2_time, RFC2131_RANDOM_FUZZ); - - /* after fuzzing, ensure t2 is still >= t1 */ - client->t2_time = MAX(client->t1_time, client->t2_time); - - /* arm lifetime timeout */ - r = event_reset_time(client->event, &client->timeout_expire, - clock_boottime_or_monotonic(), - client->expire_time, 10 * USEC_PER_MSEC, - client_timeout_expire, client, - client->event_priority, "dhcp4-lifetime", true); - if (r < 0) - return r; - - /* don't arm earlier timeouts if this has already expired */ - if (client->expire_time <= time_now) - return 0; - - log_dhcp_client(client, "lease expires in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->expire_time - time_now, USEC_PER_SEC)); - - /* arm T2 timeout */ - r = event_reset_time(client->event, &client->timeout_t2, - clock_boottime_or_monotonic(), - client->t2_time, 10 * USEC_PER_MSEC, - client_timeout_t2, client, - client->event_priority, "dhcp4-t2-timeout", true); - if (r < 0) - return r; - - /* don't arm earlier timeout if this has already expired */ - if (client->t2_time <= time_now) - return 0; - - log_dhcp_client(client, "T2 expires in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->t2_time - time_now, USEC_PER_SEC)); - - /* arm T1 timeout */ - r = event_reset_time(client->event, &client->timeout_t1, - clock_boottime_or_monotonic(), - client->t1_time, 10 * USEC_PER_MSEC, - client_timeout_t1, client, - client->event_priority, "dhcp4-t1-timer", true); - if (r < 0) - return r; - - if (client->t1_time > time_now) - log_dhcp_client(client, "T1 expires in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->t1_time - 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); - char time_string[FORMAT_TIMESPAN_MAX]; - 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->state = DHCP_STATE_REQUESTING; - client->attempt = 0; - - r = event_reset_time(client->event, &client->timeout_resend, - clock_boottime_or_monotonic(), - 0, 0, - client_timeout_resend, client, - client->event_priority, "dhcp4-resend-timer", true); - 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->start_delay = 0; - (void) event_source_disable(client->timeout_resend); - client->receive_message = - sd_event_source_unref(client->receive_message); - client->fd = safe_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 = 0; - - 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->ifindex, client->lease->address, client->port, client->ip_service_type); - 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_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED); - - r = client_initialize(client); - if (r < 0) - goto error; - - r = client_start_delayed(client); - if (r < 0) - goto error; - - log_dhcp_client(client, "REBOOT in %s", format_timespan(time_string, FORMAT_TIMESPAN_MAX, - client->start_delay, USEC_PER_SEC)); - - client->start_delay = CLAMP(client->start_delay * 2, - RESTART_AFTER_NAK_MIN_USEC, RESTART_AFTER_NAK_MAX_USEC); - - 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; - const uint8_t *expected_chaddr = NULL; - uint8_t expected_hlen = 0; - ssize_t len, buflen; - - assert(s); - assert(client); - - buflen = next_datagram_size_fd(fd); - if (buflen == -ENETDOWN) - /* the link is down. Don't return an error or the I/O event - source will be disconnected and we won't be able to receive - packets again when the link comes back. */ - return 0; - if (buflen < 0) - return buflen; - - message = malloc0(buflen); - if (!message) - return -ENOMEM; - - len = recv(fd, message, buflen, 0); - if (len < 0) { - /* see comment above for why we shouldn't error out on ENETDOWN. */ - if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN)) - return 0; - - return log_dhcp_client_errno(client, errno, - "Could not receive message from UDP socket: %m"); - } - 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 = &client->mac_addr[0]; - } - - if (message->hlen != expected_hlen) { - log_dhcp_client(client, "Unexpected packet hlen %d", message->hlen); - return 0; - } - - if (expected_hlen > 0 && memcmp(&message->chaddr[0], expected_chaddr, expected_hlen)) { - 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; - CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct tpacket_auxdata))) control; - struct iovec iov = {}; - struct msghdr msg = { - .msg_iov = &iov, - .msg_iovlen = 1, - .msg_control = &control, - .msg_controllen = sizeof(control), - }; - struct cmsghdr *cmsg; - bool checksum = true; - ssize_t buflen, len; - int r; - - assert(s); - assert(client); - - buflen = next_datagram_size_fd(fd); - if (buflen == -ENETDOWN) - return 0; - if (buflen < 0) - return buflen; - - packet = malloc0(buflen); - if (!packet) - return -ENOMEM; - - iov = IOVEC_MAKE(packet, buflen); - - len = recvmsg_safe(fd, &msg, 0); - if (IN_SET(len, -EAGAIN, -EINTR, -ENETDOWN)) - return 0; - if (len < 0) - return log_dhcp_client_errno(client, len, - "Could not receive message from raw socket: %m"); - - if ((size_t) len < sizeof(DHCPPacket)) - return 0; - - cmsg = cmsg_find(&msg, SOL_PACKET, PACKET_AUXDATA, CMSG_LEN(sizeof(struct tpacket_auxdata))); - if (cmsg) { - struct tpacket_auxdata *aux = (struct tpacket_auxdata*) CMSG_DATA(cmsg); - checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY); - } - - r = dhcp_packet_verify_headers(packet, len, checksum, client->port); - if (r < 0) - return 0; - - len -= DHCP_IP_UDP_SIZE; - - return client_handle_message(client, &packet->dhcp, len); -} - -int sd_dhcp_client_send_renew(sd_dhcp_client *client) { - assert_return(client, -EINVAL); - assert_return(client->fd >= 0, -EINVAL); - - if (!client->lease) - return 0; - - client->start_delay = 0; - client->attempt = 1; - client->state = DHCP_STATE_RENEWING; - - return client_initialize_time_events(client); -} - -int sd_dhcp_client_start(sd_dhcp_client *client) { - int r; - - assert_return(client, -EINVAL); - - r = client_initialize(client); - if (r < 0) - return r; - - /* RFC7844 section 3.3: - SHOULD perform a complete four-way handshake, starting with a - DHCPDISCOVER, to obtain a new address lease. If the client can - ascertain that this is exactly the same network to which it was - previously connected, and if the link-layer address did not change, - the client MAY issue a DHCPREQUEST to try to reclaim the current - address. */ - if (client->last_addr && !client->anonymize) - client->state = DHCP_STATE_INIT_REBOOT; - - r = client_start(client); - if (r >= 0) - log_dhcp_client(client, "STARTED on ifindex %i", client->ifindex); - - return r; -} - -int sd_dhcp_client_send_release(sd_dhcp_client *client) { - assert_return(client, -EINVAL); - assert_return(client->state != DHCP_STATE_STOPPED, -ESTALE); - assert_return(client->lease, -EUNATCH); - - _cleanup_free_ DHCPPacket *release = NULL; - size_t optoffset, optlen; - int r; - - r = client_message_init(client, &release, DHCP_RELEASE, &optlen, &optoffset); - if (r < 0) - return r; - - /* Fill up release IP and MAC */ - release->dhcp.ciaddr = client->lease->address; - memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len); - - r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0, - SD_DHCP_OPTION_END, 0, NULL); - if (r < 0) - return r; - - r = dhcp_network_send_udp_socket(client->fd, - client->lease->server_address, - DHCP_PORT_SERVER, - &release->dhcp, - sizeof(DHCPMessage) + optoffset); - if (r < 0) - return r; - - log_dhcp_client(client, "RELEASE"); - - return 0; -} - -int sd_dhcp_client_send_decline(sd_dhcp_client *client) { - assert_return(client, -EINVAL); - assert_return(client->state != DHCP_STATE_STOPPED, -ESTALE); - assert_return(client->lease, -EUNATCH); - - _cleanup_free_ DHCPPacket *release = NULL; - size_t optoffset, optlen; - int r; - - r = client_message_init(client, &release, DHCP_DECLINE, &optlen, &optoffset); - if (r < 0) - return r; - - release->dhcp.ciaddr = client->lease->address; - memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len); - - r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0, - SD_DHCP_OPTION_END, 0, NULL); - if (r < 0) - return r; - - r = dhcp_network_send_udp_socket(client->fd, - client->lease->server_address, - DHCP_PORT_SERVER, - &release->dhcp, - sizeof(DHCPMessage) + optoffset); - if (r < 0) - return r; - - log_dhcp_client(client, "DECLINE"); - - client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); - - if (client->state != DHCP_STATE_STOPPED) { - r = sd_dhcp_client_start(client); - if (r < 0) - return r; - } - - return 0; -} - -int sd_dhcp_client_stop(sd_dhcp_client *client) { - if (!client) - return 0; - - DHCP_CLIENT_DONT_DESTROY(client); - - 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, int64_t 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) { - assert_return(client, NULL); - - return client->event; -} - -static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) { - if (!client) - return NULL; - - log_dhcp_client(client, "FREE"); - - 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_initialize(client); - - sd_dhcp_client_detach_event(client); - - sd_dhcp_lease_unref(client->lease); - - set_free(client->req_opts); - free(client->hostname); - free(client->vendor_class_identifier); - free(client->mudurl); - client->user_class = strv_free(client->user_class); - ordered_hashmap_free(client->extra_options); - ordered_hashmap_free(client->vendor_options); - return mfree(client); -} - -DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_client, sd_dhcp_client, dhcp_client_free); - -int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) { - const uint8_t *opts; - size_t n_opts; - int r; - - assert_return(ret, -EINVAL); - - _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = new(sd_dhcp_client, 1); - if (!client) - return -ENOMEM; - - *client = (sd_dhcp_client) { - .n_ref = 1, - .state = DHCP_STATE_INIT, - .ifindex = -1, - .fd = -1, - .mtu = DHCP_DEFAULT_MIN_SIZE, - .port = DHCP_PORT_CLIENT, - .anonymize = !!anonymize, - .max_attempts = (uint64_t) -1, - .ip_service_type = -1, - }; - /* NOTE: this could be moved to a function. */ - if (anonymize) { - n_opts = ELEMENTSOF(default_req_opts_anonymize); - opts = default_req_opts_anonymize; - } else { - n_opts = ELEMENTSOF(default_req_opts); - opts = default_req_opts; - } - - for (size_t i = 0; i < n_opts; i++) { - r = sd_dhcp_client_set_request_option(client, opts[i]); - if (r < 0) - return r; - } - - *ret = TAKE_PTR(client); - - return 0; -} diff --git a/src/core/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/core/systemd/src/libsystemd-network/sd-dhcp-lease.c deleted file mode 100644 index 94b0d35c..00000000 --- a/src/core/systemd/src/libsystemd-network/sd-dhcp-lease.c +++ /dev/null @@ -1,1401 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/*** - Copyright © 2013 Intel Corporation. All rights reserved. -***/ - -#include "nm-sd-adapt-core.h" - -#include -#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 "env-file.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 "stdio-util.h" -#include "string-util.h" -#include "strv.h" -#include "tmpfile-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_servers( - sd_dhcp_lease *lease, - sd_dhcp_lease_server_type what, - const struct in_addr **addr) { - - assert_return(lease, -EINVAL); - assert_return(what >= 0, -EINVAL); - assert_return(what < _SD_DHCP_LEASE_SERVER_TYPE_MAX, -EINVAL); - assert_return(addr, -EINVAL); - - if (lease->servers[what].size <= 0) - return -ENODATA; - - *addr = lease->servers[what].addr; - return (int) lease->servers[what].size; -} - -int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr) { - return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_DNS, addr); -} -int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) { - return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_NTP, addr); -} -int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr) { - return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_SIP, addr); -} -int sd_dhcp_lease_get_pop3(sd_dhcp_lease *lease, const struct in_addr **addr) { - return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_POP3, addr); -} -int sd_dhcp_lease_get_smtp(sd_dhcp_lease *lease, const struct in_addr **addr) { - return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_SMTP, addr); -} -int sd_dhcp_lease_get_lpr(sd_dhcp_lease *lease, const struct in_addr **addr) { - return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_LPR, addr); -} - -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, const struct in_addr **addr) { - assert_return(lease, -EINVAL); - assert_return(addr, -EINVAL); - - if (lease->router_size <= 0) - return -ENODATA; - - *addr = lease->router; - return (int) lease->router_size; -} - -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; -} - -/* - * The returned routes array must be freed by the caller. - * Route objects have the same lifetime of the lease and must not be freed. - */ -int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, sd_dhcp_route ***routes) { - sd_dhcp_route **ret; - unsigned i; - - assert_return(lease, -EINVAL); - assert_return(routes, -EINVAL); - - if (lease->static_route_size <= 0) - return -ENODATA; - - ret = new(sd_dhcp_route *, lease->static_route_size); - if (!ret) - return -ENOMEM; - - for (i = 0; i < lease->static_route_size; i++) - ret[i] = &lease->static_route[i]; - - *routes = ret; - return (int) lease->static_route_size; -} - -int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains) { - size_t r; - - assert_return(lease, -EINVAL); - assert_return(domains, -EINVAL); - - r = strv_length(lease->search_domains); - if (r > 0) { - *domains = lease->search_domains; - return (int) r; - } - - return -ENODATA; -} - -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; -} - -static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) { - assert(lease); - - 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->root_path); - free(lease->router); - free(lease->timezone); - free(lease->hostname); - free(lease->domainname); - - for (sd_dhcp_lease_server_type i = 0; i < _SD_DHCP_LEASE_SERVER_TYPE_MAX; i++) - free(lease->servers[i].addr); - - free(lease->static_route); - free(lease->client_id); - free(lease->vendor_specific); - strv_free(lease->search_domains); - return mfree(lease); -} - -DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_lease, sd_dhcp_lease, dhcp_lease_free); - -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 = memdup_suffix0((const char *) option, len); - if (!string) - return -ENOMEM; - - free_and_replace(*ret, string); - } - - return 0; -} - -static int lease_parse_domain(const uint8_t *option, size_t len, char **ret) { - _cleanup_free_ char *name = NULL, *normalized = NULL; - int r; - - assert(option); - assert(ret); - - r = lease_parse_string(option, len, &name); - if (r < 0) - return r; - if (!name) { - *ret = mfree(*ret); - return 0; - } - - r = dns_name_normalize(name, 0, &normalized); - if (r < 0) - return r; - - if (is_localhost(normalized)) - return -EINVAL; - - if (dns_name_is_root(normalized)) - return -EINVAL; - - free_and_replace(*ret, normalized); - - 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 || len == 0); - 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_sip_server(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) { - assert(option || len == 0); - assert(ret); - assert(n_ret); - - if (len <= 0) - return -EINVAL; - - /* The SIP record is like the other, regular server records, but prefixed with a single "encoding" - * byte that is either 0 or 1. We only support it to be 1 for now. Let's drop it and parse it like - * the other fields */ - - if (option[0] != 1) { /* We only support IP address encoding for now */ - *ret = mfree(*ret); - *n_ret = 0; - return 0; - } - - return lease_parse_in_addrs(option + 1, len - 1, ret, n_ret); -} - -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; - - route->option = SD_DHCP_OPTION_STATIC_ROUTE; - r = in4_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; - route->option = SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE; - - 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; - - assert_se(lease_parse_be32(option, 4, &route->gw_addr.s_addr) >= 0); - 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 SD_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 SD_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 SD_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 SD_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 SD_DHCP_OPTION_ROUTER: - r = lease_parse_in_addrs(option, len, &lease->router, &lease->router_size); - if (r < 0) - log_debug_errno(r, "Failed to parse router addresses, ignoring: %m"); - break; - - case SD_DHCP_OPTION_DOMAIN_NAME_SERVER: - r = lease_parse_in_addrs(option, len, &lease->servers[SD_DHCP_LEASE_DNS].addr, &lease->servers[SD_DHCP_LEASE_DNS].size); - if (r < 0) - log_debug_errno(r, "Failed to parse DNS server, ignoring: %m"); - break; - - case SD_DHCP_OPTION_NTP_SERVER: - r = lease_parse_in_addrs(option, len, &lease->servers[SD_DHCP_LEASE_NTP].addr, &lease->servers[SD_DHCP_LEASE_NTP].size); - if (r < 0) - log_debug_errno(r, "Failed to parse NTP server, ignoring: %m"); - break; - - case SD_DHCP_OPTION_SIP_SERVER: - r = lease_parse_sip_server(option, len, &lease->servers[SD_DHCP_LEASE_SIP].addr, &lease->servers[SD_DHCP_LEASE_SIP].size); - if (r < 0) - log_debug_errno(r, "Failed to parse SIP server, ignoring: %m"); - break; - - case SD_DHCP_OPTION_POP3_SERVER: - r = lease_parse_in_addrs(option, len, &lease->servers[SD_DHCP_LEASE_POP3].addr, &lease->servers[SD_DHCP_LEASE_POP3].size); - if (r < 0) - log_debug_errno(r, "Failed to parse POP3 server, ignoring: %m"); - break; - - case SD_DHCP_OPTION_SMTP_SERVER: - r = lease_parse_in_addrs(option, len, &lease->servers[SD_DHCP_LEASE_SMTP].addr, &lease->servers[SD_DHCP_LEASE_SMTP].size); - if (r < 0) - log_debug_errno(r, "Failed to parse SMTP server, ignoring: %m"); - break; - - case SD_DHCP_OPTION_LPR_SERVER: - r = lease_parse_in_addrs(option, len, &lease->servers[SD_DHCP_LEASE_LPR].addr, &lease->servers[SD_DHCP_LEASE_LPR].size); - if (r < 0) - log_debug_errno(r, "Failed to parse LPR server, ignoring: %m"); - break; - - case SD_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 SD_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"); - if (lease->mtu < DHCP_DEFAULT_MIN_SIZE) { - log_debug("MTU value of %" PRIu16 " too small. Using default MTU value of %d instead.", lease->mtu, DHCP_DEFAULT_MIN_SIZE); - lease->mtu = DHCP_DEFAULT_MIN_SIZE; - } - - break; - - case SD_DHCP_OPTION_DOMAIN_NAME: - r = lease_parse_domain(option, len, &lease->domainname); - if (r < 0) { - log_debug_errno(r, "Failed to parse domain name, ignoring: %m"); - return 0; - } - - break; - - case SD_DHCP_OPTION_DOMAIN_SEARCH_LIST: - r = dhcp_lease_parse_search_domains(option, len, &lease->search_domains); - if (r < 0) - log_debug_errno(r, "Failed to parse Domain Search List, ignoring: %m"); - break; - - case SD_DHCP_OPTION_HOST_NAME: - r = lease_parse_domain(option, len, &lease->hostname); - if (r < 0) { - log_debug_errno(r, "Failed to parse hostname, ignoring: %m"); - return 0; - } - - break; - - case SD_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 SD_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 SD_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 SD_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 SD_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)) { - log_debug_errno(r, "Timezone is not valid, ignoring: %m"); - return 0; - } - - free_and_replace(lease->timezone, tz); - - break; - } - - case SD_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 SD_DHCP_OPTION_PRIVATE_BASE ... SD_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; -} - -/* Parses compressed domain names. */ -int dhcp_lease_parse_search_domains(const uint8_t *option, size_t len, char ***domains) { - _cleanup_strv_free_ char **names = NULL; - size_t pos = 0, cnt = 0; - int r; - - assert(domains); - assert_return(option && len > 0, -ENODATA); - - while (pos < len) { - _cleanup_free_ char *name = NULL; - size_t n = 0, allocated = 0; - size_t jump_barrier = pos, next_chunk = 0; - bool first = true; - - for (;;) { - uint8_t c; - c = option[pos++]; - - if (c == 0) { - /* End of name */ - break; - } else if (c <= 63) { - const char *label; - - /* Literal label */ - label = (const char*) (option + pos); - pos += c; - if (pos >= len) - return -EBADMSG; - - if (!GREEDY_REALLOC(name, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) - return -ENOMEM; - - if (first) - first = false; - else - name[n++] = '.'; - - r = dns_label_escape(label, c, name + n, DNS_LABEL_ESCAPED_MAX); - if (r < 0) - return r; - - n += r; - } else if (FLAGS_SET(c, 0xc0)) { - /* Pointer */ - - uint8_t d; - uint16_t ptr; - - if (pos >= len) - return -EBADMSG; - - d = option[pos++]; - ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d; - - /* Jumps are limited to a "prior occurrence" (RFC-1035 4.1.4) */ - if (ptr >= jump_barrier) - return -EBADMSG; - jump_barrier = ptr; - - /* Save current location so we don't end up re-parsing what's parsed so far. */ - if (next_chunk == 0) - next_chunk = pos; - - pos = ptr; - } else - return -EBADMSG; - } - - if (!GREEDY_REALLOC(name, allocated, n + 1)) - return -ENOMEM; - name[n] = 0; - - r = strv_extend(&names, name); - if (r < 0) - return r; - - cnt++; - - if (next_chunk != 0) - pos = next_chunk; - } - - *domains = TAKE_PTR(names); - - return cnt; -} - -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->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; - char sbuf[INET_ADDRSTRLEN]; - const char *string; - uint16_t mtu; - _cleanup_free_ sd_dhcp_route **routes = NULL; - char **search_domains = NULL; - 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; - - (void) 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_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); - - r = sd_dhcp_lease_get_netmask(lease, &address); - if (r >= 0) - fprintf(f, "NETMASK=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); - - r = sd_dhcp_lease_get_router(lease, &addresses); - if (r > 0) { - fputs("ROUTER=", f); - serialize_in_addrs(f, addresses, r, false, NULL); - fputc('\n', f); - } - - r = sd_dhcp_lease_get_server_identifier(lease, &address); - if (r >= 0) - fprintf(f, "SERVER_ADDRESS=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); - - r = sd_dhcp_lease_get_next_server(lease, &address); - if (r >= 0) - fprintf(f, "NEXT_SERVER=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); - - r = sd_dhcp_lease_get_broadcast(lease, &address); - if (r >= 0) - fprintf(f, "BROADCAST=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); - - 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, false, NULL); - fputc('\n', f); - } - - r = sd_dhcp_lease_get_ntp(lease, &addresses); - if (r > 0) { - fputs("NTP=", f); - serialize_in_addrs(f, addresses, r, false, NULL); - fputc('\n', f); - } - - r = sd_dhcp_lease_get_sip(lease, &addresses); - if (r > 0) { - fputs("SIP=", f); - serialize_in_addrs(f, addresses, r, false, NULL); - fputc('\n', f); - } - - r = sd_dhcp_lease_get_domainname(lease, &string); - if (r >= 0) - fprintf(f, "DOMAINNAME=%s\n", string); - - r = sd_dhcp_lease_get_search_domains(lease, &search_domains); - if (r > 0) { - fputs("DOMAIN_SEARCH_LIST=", f); - fputstrv(f, search_domains, NULL, NULL); - fputc('\n', f); - } - - 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]; - - xsprintf(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, - *sip = NULL, - *pop3 = NULL, - *smtp = NULL, - *lpr = NULL, - *mtu = NULL, - *routes = NULL, - *domains = NULL, - *client_id_hex = NULL, - *vendor_specific_hex = NULL, - *lifetime = NULL, - *t1 = NULL, - *t2 = NULL, - *options[SD_DHCP_OPTION_PRIVATE_LAST - SD_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(NULL, lease_file, - "ADDRESS", &address, - "ROUTER", &router, - "NETMASK", &netmask, - "SERVER_ADDRESS", &server_address, - "NEXT_SERVER", &next_server, - "BROADCAST", &broadcast, - "DNS", &dns, - "NTP", &ntp, - "SIP", &sip, - "POP3", &pop3, - "SMTP", &smtp, - "LPR", &lpr, - "MTU", &mtu, - "DOMAINNAME", &lease->domainname, - "HOSTNAME", &lease->hostname, - "DOMAIN_SEARCH_LIST", &domains, - "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]); - 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 = deserialize_in_addrs(&lease->router, router); - if (r < 0) - log_debug_errno(r, "Failed to deserialize router addresses %s, ignoring: %m", router); - else - lease->router_size = r; - } - - 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->servers[SD_DHCP_LEASE_DNS].addr, dns); - if (r < 0) - log_debug_errno(r, "Failed to deserialize DNS servers %s, ignoring: %m", dns); - else - lease->servers[SD_DHCP_LEASE_DNS].size = r; - } - - if (ntp) { - r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_NTP].addr, ntp); - if (r < 0) - log_debug_errno(r, "Failed to deserialize NTP servers %s, ignoring: %m", ntp); - else - lease->servers[SD_DHCP_LEASE_NTP].size = r; - } - - if (sip) { - r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_SIP].addr, sip); - if (r < 0) - log_debug_errno(r, "Failed to deserialize SIP servers %s, ignoring: %m", sip); - else - lease->servers[SD_DHCP_LEASE_SIP].size = r; - } - - if (pop3) { - r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_POP3].addr, pop3); - if (r < 0) - log_debug_errno(r, "Failed to deserialize POP3 server %s, ignoring: %m", pop3); - else - lease->servers[SD_DHCP_LEASE_POP3].size = r; - } - - if (smtp) { - r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_SMTP].addr, smtp); - if (r < 0) - log_debug_errno(r, "Failed to deserialize SMTP server %s, ignoring: %m", smtp); - else - lease->servers[SD_DHCP_LEASE_SMTP].size = r; - } - - if (lpr) { - r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_LPR].addr, lpr); - if (r < 0) - log_debug_errno(r, "Failed to deserialize LPR server %s, ignoring: %m", lpr); - else - lease->servers[SD_DHCP_LEASE_LPR].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 (domains) { - _cleanup_strv_free_ char **a = NULL; - a = strv_split(domains, " "); - if (!a) - return -ENOMEM; - - if (!strv_isempty(a)) - lease->search_domains = TAKE_PTR(a); - } - - 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 = unhexmem(client_id_hex, (size_t) -1, &lease->client_id, &lease->client_id_len); - if (r < 0) - log_debug_errno(r, "Failed to parse client ID %s, ignoring: %m", client_id_hex); - } - - if (vendor_specific_hex) { - r = unhexmem(vendor_specific_hex, (size_t) -1, &lease->vendor_specific, &lease->vendor_specific_len); - if (r < 0) - log_debug_errno(r, "Failed to parse vendor specific data %s, ignoring: %m", vendor_specific_hex); - } - - for (i = 0; i <= SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE; i++) { - _cleanup_free_ void *data = NULL; - size_t len; - - if (!options[i]) - continue; - - r = unhexmem(options[i], (size_t) -1, &data, &len); - 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, SD_DHCP_OPTION_PRIVATE_BASE + i, data, len); - if (r < 0) - return r; - } - - *ret = TAKE_PTR(lease); - - 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 = in4_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; -} - -int sd_dhcp_route_get_destination(sd_dhcp_route *route, struct in_addr *destination) { - assert_return(route, -EINVAL); - assert_return(destination, -EINVAL); - - *destination = route->dst_addr; - return 0; -} - -int sd_dhcp_route_get_destination_prefix_length(sd_dhcp_route *route, uint8_t *length) { - assert_return(route, -EINVAL); - assert_return(length, -EINVAL); - - *length = route->dst_prefixlen; - return 0; -} - -int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway) { - assert_return(route, -EINVAL); - assert_return(gateway, -EINVAL); - - *gateway = route->gw_addr; - return 0; -} - -int sd_dhcp_route_get_option(sd_dhcp_route *route) { - assert_return(route, -EINVAL); - - return route->option; -} diff --git a/src/core/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/core/systemd/src/libsystemd-network/sd-dhcp6-client.c deleted file mode 100644 index 3fafd3c0..00000000 --- a/src/core/systemd/src/libsystemd-network/sd-dhcp6-client.c +++ /dev/null @@ -1,1857 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/*** - Copyright © 2014-2015 Intel Corporation. All rights reserved. -***/ - -#include "nm-sd-adapt-core.h" - -#include -#include -#if 0 /* NM_IGNORED */ -#include -#else /* NM_IGNORED */ -#include -#endif /* NM_IGNORED */ -#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 "dns-domain.h" -#include "event-util.h" -#include "fd-util.h" -#include "hexdecoct.h" -#include "hostname-util.h" -#include "in-addr-util.h" -#include "random-util.h" -#include "socket-util.h" -#include "string-table.h" -#include "strv.h" -#include "util.h" -#include "web-util.h" - -#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN - -#define IRT_DEFAULT (1 * USEC_PER_DAY) -#define IRT_MINIMUM (600 * USEC_PER_SEC) - -/* what to request from the server, addresses (IA_NA) and/or prefixes (IA_PD) */ -enum { - DHCP6_REQUEST_IA_NA = 1, - DHCP6_REQUEST_IA_TA = 2, /* currently not used */ - DHCP6_REQUEST_IA_PD = 4, -}; - -struct sd_dhcp6_client { - unsigned n_ref; - - enum DHCP6State state; - sd_event *event; - int event_priority; - int ifindex; - DHCP6Address hint_pd_prefix; - 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; - DHCP6IA ia_pd; - sd_event_source *timeout_t1; - sd_event_source *timeout_t2; - unsigned request; - be32_t transaction_id; - usec_t transaction_start; - struct sd_dhcp6_lease *lease; - int fd; - bool information_request; - bool iaid_set; - be16_t *req_opts; - size_t req_opts_allocated; - size_t req_opts_len; - char *fqdn; - char *mudurl; - char **user_class; - char **vendor_class; - 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_callback_t callback; - void *userdata; - struct duid duid; - size_t duid_len; - usec_t information_request_time_usec; - usec_t information_refresh_time_usec; - OrderedHashmap *extra_options; - OrderedHashmap *vendor_options; -}; - -static const uint16_t default_req_opts[] = { - SD_DHCP6_OPTION_DNS_SERVERS, - SD_DHCP6_OPTION_DOMAIN_LIST, - SD_DHCP6_OPTION_NTP_SERVER, - SD_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", - [DHCP6_STATUS_NO_PREFIX_AVAIL] = "No prefix available", - [DHCP6_STATUS_UNKNOWN_QUERY_TYPE] = "Unknown query type", - [DHCP6_STATUS_MALFORMED_QUERY] = "Malformed query", - [DHCP6_STATUS_NOT_CONFIGURED] = "Not configured", - [DHCP6_STATUS_NOT_ALLOWED] = "Not allowed", - [DHCP6_STATUS_QUERY_TERMINATED] = "Query terminated", - [DHCP6_STATUS_DATA_MISSING] = "Data missing", - [DHCP6_STATUS_CATCHUP_COMPLETE] = "Catch up complete", - [DHCP6_STATUS_NOT_SUPPORTED] = "Not supported", - [DHCP6_STATUS_TLS_CONNECTION_REFUSED] = "TLS connection refused", - [DHCP6_STATUS_ADDRESS_IN_USE] = "Address in use", - [DHCP6_STATUS_CONFIGURATION_CONFLICT] = "Configuration conflict", - [DHCP6_STATUS_MISSING_BINDING_INFORMATION] = "Missing binding information", - [DHCP6_STATUS_OUTDATED_BINDING_INFORMATION] = "Outdated binding information", - [DHCP6_STATUS_SERVER_SHUTTING_DOWN] = "Server shutting down", - [DHCP6_STATUS_DNS_UPDATE_NOT_SUPPORTED] = "DNS update not supported", - [DHCP6_STATUS_EXCESSIVE_TIME_SKEW] = "Excessive time skew", -}; - -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_callback_t cb, - void *userdata) { - - assert_return(client, -EINVAL); - - client->callback = cb; - client->userdata = userdata; - - return 0; -} - -int sd_dhcp6_client_set_ifindex(sd_dhcp6_client *client, int ifindex) { - - assert_return(client, -EINVAL); - assert_return(ifindex > 0, -EINVAL); - assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); - - client->ifindex = ifindex; - 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 <= MAX_MAC_ADDR_LEN, -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 { - client->arp_type = ARPHRD_NONE; - client->mac_addr_len = 0; - return 0; - } - - 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_prefix_delegation_hint( - sd_dhcp6_client *client, - uint8_t prefixlen, - const struct in6_addr *pd_address) { - - assert_return(client, -EINVAL); - assert_return(pd_address, -EINVAL); - - assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); - - client->hint_pd_prefix.iapdprefix.address = *pd_address; - client->hint_pd_prefix.iapdprefix.prefixlen = prefixlen; - - return 0; -} - -int sd_dhcp6_client_add_vendor_option(sd_dhcp6_client *client, sd_dhcp6_option *v) { - int r; - - assert_return(client, -EINVAL); - assert_return(v, -EINVAL); - - r = ordered_hashmap_ensure_allocated(&client->vendor_options, &dhcp6_option_hash_ops); - if (r < 0) - return r; - - r = ordered_hashmap_put(client->vendor_options, v, v); - if (r < 0) - return r; - - sd_dhcp6_option_ref(v); - - return 1; -} - -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); -} - -/** - * Sets DUID. If duid is non-null, the DUID is set to duid_type + duid - * without further modification. Otherwise, if duid_type is supported, DUID - * is set based on that type. Otherwise, an error is returned. - */ -static int dhcp6_client_set_duid_internal( - sd_dhcp6_client *client, - uint16_t duid_type, - const void *duid, - size_t duid_len, - usec_t llt_time) { - int r; - - assert_return(client, -EINVAL); - assert_return(duid_len == 0 || duid != NULL, -EINVAL); - assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); - - if (duid) { - r = dhcp_validate_duid_len(duid_type, duid_len, true); - if (r < 0) { - r = dhcp_validate_duid_len(duid_type, duid_len, false); - if (r < 0) - return log_dhcp6_client_errno(client, r, "Failed to validate length of DUID: %m"); - - log_dhcp6_client(client, "Using DUID of type %u of incorrect length, proceeding.", duid_type); - } - - client->duid.type = htobe16(duid_type); - memcpy(&client->duid.raw.data, duid, duid_len); - client->duid_len = sizeof(client->duid.type) + duid_len; - } else -#if 0 /* NM_IGNORED */ - switch (duid_type) { - case DUID_TYPE_LLT: - if (client->mac_addr_len == 0) - return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EOPNOTSUPP), "Failed to set DUID-LLT, MAC address is not set."); - - r = dhcp_identifier_set_duid_llt(&client->duid, llt_time, client->mac_addr, client->mac_addr_len, client->arp_type, &client->duid_len); - if (r < 0) - return log_dhcp6_client_errno(client, r, "Failed to set DUID-LLT: %m"); - break; - case DUID_TYPE_EN: - r = dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); - if (r < 0) - return log_dhcp6_client_errno(client, r, "Failed to set DUID-EN: %m"); - break; - case DUID_TYPE_LL: - if (client->mac_addr_len == 0) - return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EOPNOTSUPP), "Failed to set DUID-LL, MAC address is not set."); - - r = dhcp_identifier_set_duid_ll(&client->duid, client->mac_addr, client->mac_addr_len, client->arp_type, &client->duid_len); - if (r < 0) - return log_dhcp6_client_errno(client, r, "Failed to set DUID-LL: %m"); - break; - case DUID_TYPE_UUID: - r = dhcp_identifier_set_duid_uuid(&client->duid, &client->duid_len); - if (r < 0) - return log_dhcp6_client_errno(client, r, "Failed to set DUID-UUID: %m"); - break; - default: - return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "Invalid DUID type"); - } -#else /* NM_IGNORED */ - g_return_val_if_reached (-EINVAL); -#endif /* NM_IGNORED */ - - return 0; -} - -int sd_dhcp6_client_set_duid( - sd_dhcp6_client *client, - uint16_t duid_type, - const void *duid, - size_t duid_len) { - return dhcp6_client_set_duid_internal(client, duid_type, duid, duid_len, 0); -} - -int sd_dhcp6_client_set_duid_llt( - sd_dhcp6_client *client, - usec_t llt_time) { - return dhcp6_client_set_duid_internal(client, DUID_TYPE_LLT, NULL, 0, llt_time); -} - -static const char* const dhcp6_duid_type_table[_DUID_TYPE_MAX] = { - [DUID_TYPE_LLT] = "DUID-LLT", - [DUID_TYPE_EN] = "DUID-EN/Vendor", - [DUID_TYPE_LL] = "DUID-LL", - [DUID_TYPE_UUID] = "UUID", -}; -DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(dhcp6_duid_type, DUIDType); - -int sd_dhcp6_client_duid_as_string( - sd_dhcp6_client *client, - char **duid) { - _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL; - const char *v; - int r; - - assert_return(client, -EINVAL); - assert_return(client->duid_len > 0, -ENODATA); - - v = dhcp6_duid_type_to_string(be16toh(client->duid.type)); - if (v) { - s = strdup(v); - if (!s) - return -ENOMEM; - } else { - r = asprintf(&s, "%0x", client->duid.type); - if (r < 0) - return -ENOMEM; - } - - t = hexmem(&client->duid.raw.data, client->duid_len); - if (!t) - return -ENOMEM; - - p = strjoin(s, ":", t); - if (!p) - return -ENOMEM; - - *duid = TAKE_PTR(p); - - return 0; -} - -int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid) { - assert_return(client, -EINVAL); - assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); - - client->ia_na.ia_na.id = htobe32(iaid); - client->ia_pd.ia_pd.id = htobe32(iaid); - client->iaid_set = true; - - return 0; -} - -int sd_dhcp6_client_get_iaid(sd_dhcp6_client *client, uint32_t *iaid) { - assert_return(client, -EINVAL); - assert_return(iaid, -EINVAL); - - if (!client->iaid_set) - return -ENODATA; - - *iaid = be32toh(client->ia_na.ia_na.id); - - return 0; -} - -int sd_dhcp6_client_set_fqdn( - sd_dhcp6_client *client, - const char *fqdn) { - - assert_return(client, -EINVAL); - - /* Make sure FQDN qualifies as DNS and as Linux hostname */ - if (fqdn && - !(hostname_is_valid(fqdn, 0) && dns_name_is_valid(fqdn) > 0)) - return -EINVAL; - - return free_and_strdup(&client->fqdn, fqdn); -} - -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); - - if (option <= 0 || option >= UINT8_MAX) - 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_set_request_mud_url(sd_dhcp6_client *client, const char *mudurl) { - - assert_return(client, -EINVAL); - assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY); - assert_return(mudurl, -EINVAL); - assert_return(strlen(mudurl) <= UINT8_MAX, -EINVAL); - assert_return(http_url_is_valid(mudurl), -EINVAL); - - return free_and_strdup(&client->mudurl, mudurl); -} - -int sd_dhcp6_client_set_request_user_class(sd_dhcp6_client *client, char **user_class) { - _cleanup_strv_free_ char **s = NULL; - char **p; - - assert_return(client, -EINVAL); - assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY); - - assert_return(user_class, -EINVAL); - - STRV_FOREACH(p, user_class) - if (strlen(*p) > UINT16_MAX) - return -ENAMETOOLONG; - - s = strv_copy(user_class); - if (!s) - return -ENOMEM; - - client->user_class = TAKE_PTR(s); - - return 0; -} - -int sd_dhcp6_client_set_request_vendor_class(sd_dhcp6_client *client, char **vendor_class) { - _cleanup_strv_free_ char **s = NULL; - char **p; - - assert_return(client, -EINVAL); - assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY); - assert_return(vendor_class, -EINVAL); - - STRV_FOREACH(p, vendor_class) - if (strlen(*p) > UINT8_MAX) - return -ENAMETOOLONG; - - s = strv_copy(vendor_class); - if (!s) - return -ENOMEM; - - client->vendor_class = TAKE_PTR(s); - - return 0; -} - -int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegation) { - assert_return(client, -EINVAL); - assert_return(delegation, -EINVAL); - - *delegation = FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD); - - return 0; -} - -int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client, int delegation) { - assert_return(client, -EINVAL); - - SET_FLAG(client->request, DHCP6_REQUEST_IA_PD, delegation); - - return 0; -} - -int sd_dhcp6_client_get_address_request(sd_dhcp6_client *client, int *request) { - assert_return(client, -EINVAL); - assert_return(request, -EINVAL); - - *request = FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA); - - return 0; -} - -int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client, int request) { - assert_return(client, -EINVAL); - - SET_FLAG(client->request, DHCP6_REQUEST_IA_NA, request); - - return 0; -} - -int sd_dhcp6_client_set_transaction_id(sd_dhcp6_client *client, uint32_t transaction_id) { - assert_return(client, -EINVAL); - - client->transaction_id = transaction_id; - - 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; -} - -int sd_dhcp6_client_add_option(sd_dhcp6_client *client, sd_dhcp6_option *v) { - int r; - - assert_return(client, -EINVAL); - assert_return(v, -EINVAL); - - r = ordered_hashmap_ensure_allocated(&client->extra_options, &dhcp6_option_hash_ops); - if (r < 0) - return r; - - r = ordered_hashmap_put(client->extra_options, UINT_TO_PTR(v->option), v); - if (r < 0) - return r; - - sd_dhcp6_option_ref(v); - return 0; -} - -static void client_notify(sd_dhcp6_client *client, int event) { - assert(client); - - if (client->callback) - client->callback(client, event, client->userdata); -} - -static int client_reset(sd_dhcp6_client *client) { - assert(client); - - client->lease = sd_dhcp6_lease_unref(client->lease); - - client->receive_message = - sd_event_source_unref(client->receive_message); - - client->transaction_id = 0; - client->transaction_start = 0; - - client->retransmit_time = 0; - client->retransmit_count = 0; - - (void) event_source_disable(client->timeout_resend); - (void) event_source_disable(client->timeout_resend_expire); - (void) event_source_disable(client->timeout_t1); - (void) event_source_disable(client->timeout_t2); - - 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; - struct sd_dhcp6_option *j; - size_t len, optlen = 512; - uint8_t *opt; - int r; - usec_t elapsed_usec; - be16_t elapsed_time; - - assert(client); - - 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; - - if (client->mudurl) { - r = dhcp6_option_append(&opt, &optlen, - SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl), - client->mudurl); - if (r < 0) - return r; - } - - break; - - case DHCP6_STATE_SOLICITATION: - message->type = DHCP6_SOLICIT; - - r = dhcp6_option_append(&opt, &optlen, - SD_DHCP6_OPTION_RAPID_COMMIT, 0, NULL); - if (r < 0) - return r; - - if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) { - r = dhcp6_option_append_ia(&opt, &optlen, - &client->ia_na); - if (r < 0) - return r; - } - - if (client->fqdn) { - r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn); - if (r < 0) - return r; - } - - if (client->mudurl) { - r = dhcp6_option_append(&opt, &optlen, - SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl), - client->mudurl); - if (r < 0) - return r; - } - - if (client->user_class) { - r = dhcp6_option_append_user_class(&opt, &optlen, client->user_class); - if (r < 0) - return r; - } - - if (client->vendor_class) { - r = dhcp6_option_append_vendor_class(&opt, &optlen, client->vendor_class); - if (r < 0) - return r; - } - - if (!ordered_hashmap_isempty(client->vendor_options)) { - r = dhcp6_option_append_vendor_option(&opt, &optlen, - client->vendor_options); - if (r < 0) - return r; - } - - if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) { - r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd, &client->hint_pd_prefix); - if (r < 0) - return r; - - opt += r; - optlen -= 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, SD_DHCP6_OPTION_SERVERID, - client->lease->serverid_len, - client->lease->serverid); - if (r < 0) - return r; - - if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA) && client->lease->ia.addresses) { - r = dhcp6_option_append_ia(&opt, &optlen, - &client->lease->ia); - if (r < 0) - return r; - } - - if (client->fqdn) { - r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn); - if (r < 0) - return r; - } - - if (client->mudurl) { - r = dhcp6_option_append(&opt, &optlen, - SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl), - client->mudurl); - if (r < 0) - return r; - } - - if (client->user_class) { - r = dhcp6_option_append_user_class(&opt, &optlen, client->user_class); - if (r < 0) - return r; - } - - if (client->vendor_class) { - r = dhcp6_option_append_vendor_class(&opt, &optlen, client->vendor_class); - if (r < 0) - return r; - } - - if (!ordered_hashmap_isempty(client->vendor_options)) { - r = dhcp6_option_append_vendor_option(&opt, &optlen, client->vendor_options); - if (r < 0) - return r; - } - - if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD) && client->lease->pd.addresses) { - r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL); - if (r < 0) - return r; - - opt += r; - optlen -= r; - } - - break; - - case DHCP6_STATE_REBIND: - message->type = DHCP6_REBIND; - - if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA)) { - r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia); - if (r < 0) - return r; - } - - if (client->fqdn) { - r = dhcp6_option_append_fqdn(&opt, &optlen, client->fqdn); - if (r < 0) - return r; - } - - if (client->mudurl) { - r = dhcp6_option_append(&opt, &optlen, - SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl), - client->mudurl); - if (r < 0) - return r; - } - - if (client->user_class) { - r = dhcp6_option_append_user_class(&opt, &optlen, client->user_class); - if (r < 0) - return r; - } - - if (client->vendor_class) { - r = dhcp6_option_append_vendor_class(&opt, &optlen, client->vendor_class); - if (r < 0) - return r; - } - - if (!ordered_hashmap_isempty(client->vendor_options)) { - r = dhcp6_option_append_vendor_option(&opt, &optlen, client->vendor_options); - if (r < 0) - return r; - } - - if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) { - r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL); - if (r < 0) - return r; - - opt += r; - optlen -= r; - } - - break; - - case DHCP6_STATE_STOPPED: - case DHCP6_STATE_BOUND: - return -EINVAL; - } - - r = dhcp6_option_append(&opt, &optlen, SD_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, SD_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, SD_DHCP6_OPTION_ELAPSED_TIME, - sizeof(elapsed_time), &elapsed_time); - if (r < 0) - return r; - - ORDERED_HASHMAP_FOREACH(j, client->extra_options) { - r = dhcp6_option_append(&opt, &optlen, j->option, j->length, j->data); - 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(s); - assert(client); - assert(client->lease); - - (void) event_source_disable(client->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(s); - assert(client); - assert(client->lease); - - (void) event_source_disable(client->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 - (random_u32() % 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]; - - assert(s); - assert(client); - assert(client->event); - - (void) event_source_disable(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 (event_source_is_enabled(client->timeout_resend_expire) <= 0) { - uint32_t expire = 0; - - 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 > 0 && - 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 == 0) { - 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 > 0 && - 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 = event_reset_time(client->event, &client->timeout_resend, - clock_boottime_or_monotonic(), - time_now + client->retransmit_time, 10 * USEC_PER_MSEC, - client_timeout_resend, client, - client->event_priority, "dhcp6-resend-timer", true); - if (r < 0) - goto error; - - if (max_retransmit_duration > 0 && event_source_is_enabled(client->timeout_resend_expire) <= 0) { - - log_dhcp6_client(client, "Max retransmission duration %"PRIu64" secs", - max_retransmit_duration / USEC_PER_SEC); - - r = event_reset_time(client->event, &client->timeout_resend_expire, - clock_boottime_or_monotonic(), - time_now + max_retransmit_duration, USEC_PER_SEC, - client_timeout_resend_expire, client, - client->event_priority, "dhcp6-resend-expire-timer", true); - 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; - uint32_t iaid; - - assert(client); - - if (client->iaid_set) - return 0; - - r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, true, &iaid); - if (r < 0) - return r; - - client->ia_na.ia_na.id = iaid; - client->ia_pd.ia_pd.id = iaid; - client->iaid_set = true; - - return 0; -} - -static int client_parse_message( - sd_dhcp6_client *client, - DHCP6Message *message, - size_t len, - sd_dhcp6_lease *lease) { - - uint16_t ia_na_status = 0, ia_pd_status = 0; - uint32_t lt_t1 = ~0, lt_t2 = ~0; - usec_t irt = IRT_DEFAULT; - bool clientid = false; - size_t pos = 0; - int r; - - assert(client); - assert(message); - assert(len >= sizeof(DHCP6Message)); - assert(lease); - - len -= sizeof(DHCP6Message); - - while (pos < len) { - DHCP6Option *option = (DHCP6Option *) &message->options[pos]; - uint16_t optcode, optlen; - be32_t iaid_lease; - int status; - uint8_t *optval; - - if (len < pos + offsetof(DHCP6Option, data)) - return -ENOBUFS; - - optcode = be16toh(option->code); - optlen = be16toh(option->len); - optval = option->data; - - if (len < pos + offsetof(DHCP6Option, data) + optlen) - return -ENOBUFS; - - switch (optcode) { - case SD_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 SD_DHCP6_OPTION_SERVERID: - r = dhcp6_lease_get_serverid(lease, NULL, NULL); - if (r >= 0) { - 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 SD_DHCP6_OPTION_PREFERENCE: - if (optlen != 1) - return -EINVAL; - - r = dhcp6_lease_set_preference(lease, optval[0]); - if (r < 0) - return r; - - break; - - case SD_DHCP6_OPTION_STATUS_CODE: - status = dhcp6_option_parse_status(option, optlen + sizeof(DHCP6Option)); - if (status < 0) - return status; - - if (status > 0) { - log_dhcp6_client(client, "%s Status %s", - dhcp6_message_type_to_string(message->type), - dhcp6_message_status_to_string(status)); - - return -EINVAL; - } - - break; - - case SD_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(option, &lease->ia, &ia_na_status); - if (r < 0 && r != -ENOMSG) - return r; - - if (ia_na_status == DHCP6_STATUS_NO_ADDRS_AVAIL) { - pos += offsetof(DHCP6Option, data) + optlen; - continue; - } - - r = dhcp6_lease_get_iaid(lease, &iaid_lease); - if (r < 0) - return r; - - if (client->ia_na.ia_na.id != iaid_lease) { - log_dhcp6_client(client, "%s has wrong IAID for IA NA", - dhcp6_message_type_to_string(message->type)); - return -EINVAL; - } - - if (lease->ia.addresses) { - lt_t1 = MIN(lt_t1, be32toh(lease->ia.ia_na.lifetime_t1)); - lt_t2 = MIN(lt_t2, be32toh(lease->ia.ia_na.lifetime_t1)); - } - - break; - - case SD_DHCP6_OPTION_IA_PD: - if (client->state == DHCP6_STATE_INFORMATION_REQUEST) { - log_dhcp6_client(client, "Information request ignoring IA PD option"); - - break; - } - - r = dhcp6_option_parse_ia(option, &lease->pd, &ia_pd_status); - if (r < 0 && r != -ENOMSG) - return r; - - if (ia_pd_status == DHCP6_STATUS_NO_PREFIX_AVAIL) { - pos += offsetof(DHCP6Option, data) + optlen; - continue; - } - - r = dhcp6_lease_get_pd_iaid(lease, &iaid_lease); - if (r < 0) - return r; - - if (client->ia_pd.ia_pd.id != iaid_lease) { - log_dhcp6_client(client, "%s has wrong IAID for IA PD", - dhcp6_message_type_to_string(message->type)); - return -EINVAL; - } - - if (lease->pd.addresses) { - lt_t1 = MIN(lt_t1, be32toh(lease->pd.ia_pd.lifetime_t1)); - lt_t2 = MIN(lt_t2, be32toh(lease->pd.ia_pd.lifetime_t2)); - } - - break; - - case SD_DHCP6_OPTION_RAPID_COMMIT: - r = dhcp6_lease_set_rapid_commit(lease); - if (r < 0) - return r; - - break; - - case SD_DHCP6_OPTION_DNS_SERVERS: - r = dhcp6_lease_set_dns(lease, optval, optlen); - if (r < 0) - return r; - - break; - - case SD_DHCP6_OPTION_DOMAIN_LIST: - r = dhcp6_lease_set_domains(lease, optval, optlen); - if (r < 0) - return r; - - break; - - case SD_DHCP6_OPTION_NTP_SERVER: - r = dhcp6_lease_set_ntp(lease, optval, optlen); - if (r < 0) - return r; - - break; - - case SD_DHCP6_OPTION_SNTP_SERVERS: - r = dhcp6_lease_set_sntp(lease, optval, optlen); - if (r < 0) - return r; - - break; - - case SD_DHCP6_OPTION_FQDN: - r = dhcp6_lease_set_fqdn(lease, optval, optlen); - if (r < 0) - return r; - - break; - - case SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME: - if (optlen != 4) - return -EINVAL; - - irt = unaligned_read_be32((be32_t *) optval) * USEC_PER_SEC; - break; - } - - pos += offsetof(DHCP6Option, data) + optlen; - } - - if (ia_na_status > 0 && ia_pd_status > 0) { - log_dhcp6_client(client, "No IA_PD prefix or IA_NA address received. Ignoring."); - return -EINVAL; - } - - if (!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, NULL, NULL); - if (r < 0) { - log_dhcp6_client(client, "%s has no server id", - dhcp6_message_type_to_string(message->type)); - return -EINVAL; - } - - } else { - if (lease->ia.addresses) { - lease->ia.ia_na.lifetime_t1 = htobe32(lt_t1); - lease->ia.ia_na.lifetime_t2 = htobe32(lt_t2); - } - - if (lease->pd.addresses) { - lease->pd.ia_pd.lifetime_t1 = htobe32(lt_t1); - lease->pd.ia_pd.lifetime_t2 = htobe32(lt_t2); - } - } - - client->information_refresh_time_usec = MAX(irt, IRT_MINIMUM); - - return 0; -} - -static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, size_t len) { - _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL; - bool rapid_commit; - int r; - - assert(client); - assert(reply); - - 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; - } - - sd_dhcp6_lease_unref(client->lease); - client->lease = TAKE_PTR(lease); - - return DHCP6_STATE_BOUND; -} - -static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *advertise, size_t len) { - _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL; - uint8_t pref_advertise = 0, pref_lease = 0; - int r; - - 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) { - sd_dhcp6_lease_unref(client->lease); - client->lease = TAKE_PTR(lease); - 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; - ssize_t buflen, len; - int r = 0; - - assert(s); - assert(client); - assert(client->event); - - buflen = next_datagram_size_fd(fd); - if (buflen == -ENETDOWN) - /* the link is down. Don't return an error or the I/O event - source will be disconnected and we won't be able to receive - packets again when the link comes back. */ - return 0; - if (buflen < 0) - return buflen; - - message = malloc(buflen); - if (!message) - return -ENOMEM; - - len = recv(fd, message, buflen, 0); - if (len < 0) { - /* see comment above for why we shouldn't error out on ENETDOWN. */ - if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN)) - return 0; - - return log_dhcp6_client_errno(client, errno, "Could not receive message from UDP socket: %m"); - - } - if ((size_t) len < sizeof(DHCP6Message)) { - log_dhcp6_client(client, "Too small to be DHCP6 message: ignoring"); - 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; - } - - _fallthrough_; /* for Solicitation 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; - } - - log_dhcp6_client(client, "Recv %s", - dhcp6_message_type_to_string(message->type)); - - return 0; -} - -static int client_get_lifetime(sd_dhcp6_client *client, uint32_t *lifetime_t1, - uint32_t *lifetime_t2) { - assert_return(client, -EINVAL); - assert_return(client->lease, -EINVAL); - - if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_NA) && client->lease->ia.addresses) { - *lifetime_t1 = be32toh(client->lease->ia.ia_na.lifetime_t1); - *lifetime_t2 = be32toh(client->lease->ia.ia_na.lifetime_t2); - - return 0; - } - - if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD) && client->lease->pd.addresses) { - *lifetime_t1 = be32toh(client->lease->pd.ia_pd.lifetime_t1); - *lifetime_t2 = be32toh(client->lease->pd.ia_pd.lifetime_t2); - - return 0; - } - - return -ENOMSG; -} - -static int client_start(sd_dhcp6_client *client, enum DHCP6State state) { - int r; - usec_t timeout, time_now; - char time_string[FORMAT_TIMESPAN_MAX]; - uint32_t lifetime_t1, lifetime_t2; - - assert_return(client, -EINVAL); - assert_return(client->event, -EINVAL); - assert_return(client->ifindex > 0, -EINVAL); - assert_return(client->state != state, -EINVAL); - - (void) event_source_disable(client->timeout_resend_expire); - (void) event_source_disable(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; - - if (!client->receive_message) { - 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; - } - - switch (state) { - case DHCP6_STATE_STOPPED: - if (client->state == DHCP6_STATE_INFORMATION_REQUEST) { - client->state = DHCP6_STATE_STOPPED; - - return 0; - } - - _fallthrough_; - 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: - - r = client_get_lifetime(client, &lifetime_t1, &lifetime_t2); - if (r < 0) - goto error; - - if (lifetime_t1 == 0xffffffff || lifetime_t2 == 0xffffffff) { - log_dhcp6_client(client, "Infinite T1 0x%08x or T2 0x%08x", - lifetime_t1, lifetime_t2); - - return 0; - } - - timeout = client_timeout_compute_random(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 = event_reset_time(client->event, &client->timeout_t1, - clock_boottime_or_monotonic(), - time_now + timeout, 10 * USEC_PER_SEC, - client_timeout_t1, client, - client->event_priority, "dhcp6-t1-timeout", true); - if (r < 0) - goto error; - - timeout = client_timeout_compute_random(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 = event_reset_time(client->event, &client->timeout_t2, - clock_boottime_or_monotonic(), - time_now + timeout, 10 * USEC_PER_SEC, - client_timeout_t2, client, - client->event_priority, "dhcp6-t2-timeout", true); - if (r < 0) - goto error; - - client->state = state; - - return 0; - } - - client->transaction_id = random_u32() & htobe32(0x00ffffff); - client->transaction_start = time_now; - - r = event_reset_time(client->event, &client->timeout_resend, - clock_boottime_or_monotonic(), - 0, 0, - client_timeout_resend, client, - client->event_priority, "dhcp6-resend-timeout", true); - if (r < 0) - goto error; - - return 0; - - error: - client_reset(client); - return r; -} - -int sd_dhcp6_client_stop(sd_dhcp6_client *client) { - if (!client) - return 0; - - client_stop(client, SD_DHCP6_CLIENT_EVENT_STOP); - - client->fd = safe_close(client->fd); - - 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) { - enum DHCP6State state = DHCP6_STATE_SOLICITATION; - int r; - - assert_return(client, -EINVAL); - assert_return(client->event, -EINVAL); - assert_return(client->ifindex > 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; - - if (!client->information_request && !client->request) - return -EINVAL; - - 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; - - if (client->fd < 0) { - r = dhcp6_network_bind_udp_socket(client->ifindex, &client->local_address); - if (r < 0) { - _cleanup_free_ char *p = NULL; - - (void) in_addr_to_string(AF_INET6, (const union in_addr_union*) &client->local_address, &p); - return log_dhcp6_client_errno(client, r, - "Failed to bind to UDP socket at address %s: %m", strna(p)); - } - - client->fd = r; - } - - if (client->information_request) { - usec_t t = now(CLOCK_MONOTONIC); - - if (t < usec_add(client->information_request_time_usec, client->information_refresh_time_usec)) - return 0; - - client->information_request_time_usec = t; - state = DHCP6_STATE_INFORMATION_REQUEST; - } - - log_dhcp6_client(client, "Started in %s mode", - client->information_request ? "Information request" : "Managed"); - - return client_start(client, state); -} - -int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int64_t 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) { - assert_return(client, NULL); - - return client->event; -} - -static sd_dhcp6_client *dhcp6_client_free(sd_dhcp6_client *client) { - assert(client); - - client->timeout_resend = sd_event_source_unref(client->timeout_resend); - client->timeout_resend_expire = sd_event_source_unref(client->timeout_resend_expire); - client->timeout_t1 = sd_event_source_unref(client->timeout_t1); - client->timeout_t2 = sd_event_source_unref(client->timeout_t2); - - client_reset(client); - - client->fd = safe_close(client->fd); - - sd_dhcp6_client_detach_event(client); - - free(client->req_opts); - free(client->fqdn); - free(client->mudurl); - - ordered_hashmap_free(client->extra_options); - strv_free(client->user_class); - strv_free(client->vendor_class); - - return mfree(client); -} - -DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_client, sd_dhcp6_client, dhcp6_client_free); - -int sd_dhcp6_client_new(sd_dhcp6_client **ret) { - _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL; - _cleanup_free_ be16_t *req_opts = NULL; - size_t t; - - assert_return(ret, -EINVAL); - - req_opts = new(be16_t, ELEMENTSOF(default_req_opts)); - if (!req_opts) - return -ENOMEM; - - for (t = 0; t < ELEMENTSOF(default_req_opts); t++) - req_opts[t] = htobe16(default_req_opts[t]); - - client = new(sd_dhcp6_client, 1); - if (!client) - return -ENOMEM; - - *client = (sd_dhcp6_client) { - .n_ref = 1, - .ia_na.type = SD_DHCP6_OPTION_IA_NA, - .ia_pd.type = SD_DHCP6_OPTION_IA_PD, - .ifindex = -1, - .request = DHCP6_REQUEST_IA_NA, - .fd = -1, - .req_opts_len = ELEMENTSOF(default_req_opts), - .hint_pd_prefix.iapdprefix.lifetime_preferred = (be32_t) -1, - .hint_pd_prefix.iapdprefix.lifetime_valid = (be32_t) -1, - .req_opts = TAKE_PTR(req_opts), - }; - - *ret = TAKE_PTR(client); - - return 0; -} diff --git a/src/core/systemd/src/libsystemd-network/sd-dhcp6-lease.c b/src/core/systemd/src/libsystemd-network/sd-dhcp6-lease.c deleted file mode 100644 index 5792f688..00000000 --- a/src/core/systemd/src/libsystemd-network/sd-dhcp6-lease.c +++ /dev/null @@ -1,435 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/*** - Copyright © 2014-2015 Intel Corporation. All rights reserved. -***/ - -#include "nm-sd-adapt-core.h" - -#include - -#include "alloc-util.h" -#include "dhcp6-lease-internal.h" -#include "dhcp6-protocol.h" -#include "strv.h" -#include "util.h" - -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->ia_na.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; - - 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) { - uint8_t *serverid; - - assert_return(lease, -EINVAL); - assert_return(id, -EINVAL); - - serverid = memdup(id, len); - if (!serverid) - return -ENOMEM; - - free_and_replace(lease->serverid, serverid); - 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); - - if (!lease->serverid) - return -ENOMSG; - - if (id) - *id = lease->serverid; - if (len) - *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.ia_na.id; - - return 0; -} - -int dhcp6_lease_get_pd_iaid(sd_dhcp6_lease *lease, be32_t *iaid) { - assert_return(lease, -EINVAL); - assert_return(iaid, -EINVAL); - - *iaid = lease->pd.ia_pd.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 sd_dhcp6_lease_get_pd(sd_dhcp6_lease *lease, struct in6_addr *prefix, - uint8_t *prefix_len, - uint32_t *lifetime_preferred, - uint32_t *lifetime_valid) { - assert_return(lease, -EINVAL); - assert_return(prefix, -EINVAL); - assert_return(prefix_len, -EINVAL); - assert_return(lifetime_preferred, -EINVAL); - assert_return(lifetime_valid, -EINVAL); - - if (!lease->prefix_iter) - return -ENOMSG; - - memcpy(prefix, &lease->prefix_iter->iapdprefix.address, - sizeof(struct in6_addr)); - *prefix_len = lease->prefix_iter->iapdprefix.prefixlen; - *lifetime_preferred = - be32toh(lease->prefix_iter->iapdprefix.lifetime_preferred); - *lifetime_valid = - be32toh(lease->prefix_iter->iapdprefix.lifetime_valid); - - lease->prefix_iter = lease->prefix_iter->addresses_next; - - return 0; -} - -void sd_dhcp6_lease_reset_pd_prefix_iter(sd_dhcp6_lease *lease) { - if (lease) - lease->prefix_iter = lease->pd.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) - return log_dhcp6_client_errno(client, r, "Invalid DNS server option: %m"); - - lease->dns_count = r; - - return 0; -} - -int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, const 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_list(optval, optlen, &domains); - if (r < 0) - return 0; - - strv_free_and_replace(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); - - lease->ntp = mfree(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_list(subval, sublen, - &servers); - if (r < 0) - return 0; - - strv_free_and_replace(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) - return log_dhcp6_client_errno(client, r, "Invalid SNTP server option: %m"); - - lease->ntp_count = r; - - return 0; -} - -int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease, - const 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; -} - -int dhcp6_lease_set_fqdn(sd_dhcp6_lease *lease, const uint8_t *optval, - size_t optlen) { - int r; - char *fqdn; - - assert_return(lease, -EINVAL); - assert_return(optval, -EINVAL); - - if (optlen < 2) - return -ENODATA; - - /* Ignore the flags field, it doesn't carry any useful - information for clients. */ - r = dhcp6_option_parse_domainname(optval + 1, optlen - 1, &fqdn); - if (r < 0) - return r; - - return free_and_replace(lease->fqdn, fqdn); -} - -int sd_dhcp6_lease_get_fqdn(sd_dhcp6_lease *lease, const char **fqdn) { - assert_return(lease, -EINVAL); - assert_return(fqdn, -EINVAL); - - if (lease->fqdn) { - *fqdn = lease->fqdn; - return 0; - } - - return -ENOENT; -} - -static sd_dhcp6_lease *dhcp6_lease_free(sd_dhcp6_lease *lease) { - assert(lease); - - free(lease->serverid); - dhcp6_lease_free_ia(&lease->ia); - dhcp6_lease_free_ia(&lease->pd); - - free(lease->dns); - free(lease->fqdn); - - lease->domains = strv_free(lease->domains); - - free(lease->ntp); - - lease->ntp_fqdn = strv_free(lease->ntp_fqdn); - return mfree(lease); -} - -DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_lease, sd_dhcp6_lease, dhcp6_lease_free); - -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/core/systemd/src/libsystemd-network/sd-ipv4acd.c b/src/core/systemd/src/libsystemd-network/sd-ipv4acd.c deleted file mode 100644 index 096afbd8..00000000 --- a/src/core/systemd/src/libsystemd-network/sd-ipv4acd.c +++ /dev/null @@ -1,543 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/*** - Copyright © 2014 Axis Communications AB. All rights reserved. -***/ - -#include "nm-sd-adapt-core.h" - -#include -#include -#include -#include -#include - -#include "sd-ipv4acd.h" - -#include "alloc-util.h" -#include "arp-util.h" -#include "ether-addr-util.h" -#include "event-util.h" -#include "fd-util.h" -#include "format-util.h" -#include "in-addr-util.h" -#include "log-link.h" -#include "random-util.h" -#include "siphash24.h" -#include "string-table.h" -#include "string-util.h" -#include "time-util.h" - -/* Constants from the RFC */ -#define PROBE_WAIT_USEC (1U * USEC_PER_SEC) -#define PROBE_NUM 3U -#define PROBE_MIN_USEC (1U * USEC_PER_SEC) -#define PROBE_MAX_USEC (2U * USEC_PER_SEC) -#define ANNOUNCE_WAIT_USEC (2U * USEC_PER_SEC) -#define ANNOUNCE_NUM 2U -#define ANNOUNCE_INTERVAL_USEC (2U * USEC_PER_SEC) -#define MAX_CONFLICTS 10U -#define RATE_LIMIT_INTERVAL_USEC (60U * USEC_PER_SEC) -#define DEFEND_INTERVAL_USEC (10U * USEC_PER_SEC) - -typedef enum IPv4ACDState { - IPV4ACD_STATE_INIT, - IPV4ACD_STATE_STARTED, - 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 { - unsigned n_ref; - - IPv4ACDState state; - int ifindex; - int fd; - - char ifname[IF_NAMESIZE + 1]; - unsigned n_iteration; - unsigned n_conflict; - - sd_event_source *receive_message_event_source; - sd_event_source *timer_event_source; - - usec_t defend_window; - be32_t address; - - /* External */ - struct ether_addr mac_addr; - - sd_event *event; - int event_priority; - sd_ipv4acd_callback_t callback; - void* userdata; -}; - -#define log_ipv4acd_errno(acd, error, fmt, ...) \ - log_interface_full_errno(sd_ipv4acd_get_ifname(acd), LOG_DEBUG, error, "IPV4ACD: " fmt, ##__VA_ARGS__) -#define log_ipv4acd(acd, fmt, ...) \ - log_ipv4acd_errno(acd, 0, fmt, ##__VA_ARGS__) - -static const char * const ipv4acd_state_table[_IPV4ACD_STATE_MAX] = { - [IPV4ACD_STATE_INIT] = "init", - [IPV4ACD_STATE_STARTED] = "started", - [IPV4ACD_STATE_WAITING_PROBE] = "waiting-probe", - [IPV4ACD_STATE_PROBING] = "probing", - [IPV4ACD_STATE_WAITING_ANNOUNCE] = "waiting-announce", - [IPV4ACD_STATE_ANNOUNCING] = "announcing", - [IPV4ACD_STATE_RUNNING] = "running", -}; - -DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(ipv4acd_state, IPv4ACDState); - -static void ipv4acd_set_state(sd_ipv4acd *acd, IPv4ACDState st, bool reset_counter) { - assert(acd); - assert(st < _IPV4ACD_STATE_MAX); - - if (st != acd->state) - log_ipv4acd(acd, "%s -> %s", ipv4acd_state_to_string(acd->state), ipv4acd_state_to_string(st)); - - if (st == acd->state && !reset_counter) - acd->n_iteration++; - else { - acd->state = st; - acd->n_iteration = 0; - } -} - -static void ipv4acd_reset(sd_ipv4acd *acd) { - assert(acd); - - (void) event_source_disable(acd->timer_event_source); - acd->receive_message_event_source = sd_event_source_unref(acd->receive_message_event_source); - - acd->fd = safe_close(acd->fd); - - ipv4acd_set_state(acd, IPV4ACD_STATE_INIT, true); -} - -static sd_ipv4acd *ipv4acd_free(sd_ipv4acd *acd) { - assert(acd); - - acd->timer_event_source = sd_event_source_unref(acd->timer_event_source); - - ipv4acd_reset(acd); - sd_ipv4acd_detach_event(acd); - - return mfree(acd); -} - -DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_ipv4acd, sd_ipv4acd, ipv4acd_free); - -int sd_ipv4acd_new(sd_ipv4acd **ret) { - _cleanup_(sd_ipv4acd_unrefp) sd_ipv4acd *acd = NULL; - - assert_return(ret, -EINVAL); - - acd = new(sd_ipv4acd, 1); - if (!acd) - return -ENOMEM; - - *acd = (sd_ipv4acd) { - .n_ref = 1, - .state = IPV4ACD_STATE_INIT, - .ifindex = -1, - .fd = -1, - }; - - *ret = TAKE_PTR(acd); - - return 0; -} - -static void ipv4acd_client_notify(sd_ipv4acd *acd, int event) { - assert(acd); - - if (!acd->callback) - return; - - acd->callback(acd, event, acd->userdata); -} - -int sd_ipv4acd_stop(sd_ipv4acd *acd) { - IPv4ACDState old_state; - - if (!acd) - return 0; - - old_state = acd->state; - - ipv4acd_reset(acd); - - if (old_state == IPV4ACD_STATE_INIT) - return 0; - - log_ipv4acd(acd, "STOPPED"); - - ipv4acd_client_notify(acd, 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 *acd, usec_t usec, usec_t random_usec) { - usec_t next_timeout, time_now; - - assert(acd); - - next_timeout = usec; - - if (random_usec > 0) - next_timeout += (usec_t) random_u64() % random_usec; - - assert_se(sd_event_now(acd->event, clock_boottime_or_monotonic(), &time_now) >= 0); - - return event_reset_time(acd->event, &acd->timer_event_source, - clock_boottime_or_monotonic(), - time_now + next_timeout, 0, - ipv4acd_on_timeout, acd, - acd->event_priority, "ipv4acd-timer", true); -} - -static bool ipv4acd_arp_conflict(sd_ipv4acd *acd, struct ether_arp *arp) { - assert(acd); - assert(arp); - - /* see the BPF */ - if (memcmp(arp->arp_spa, &acd->address, sizeof(acd->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 *acd = userdata; - int r = 0; - - assert(acd); - - switch (acd->state) { - - case IPV4ACD_STATE_STARTED: - ipv4acd_set_state(acd, IPV4ACD_STATE_WAITING_PROBE, true); - - if (acd->n_conflict >= MAX_CONFLICTS) { - char ts[FORMAT_TIMESPAN_MAX]; - log_ipv4acd(acd, "Max conflicts reached, delaying by %s", format_timespan(ts, sizeof(ts), RATE_LIMIT_INTERVAL_USEC, 0)); - - r = ipv4acd_set_next_wakeup(acd, RATE_LIMIT_INTERVAL_USEC, PROBE_WAIT_USEC); - if (r < 0) - goto fail; - } else { - r = ipv4acd_set_next_wakeup(acd, 0, PROBE_WAIT_USEC); - if (r < 0) - goto fail; - } - - break; - - case IPV4ACD_STATE_WAITING_PROBE: - case IPV4ACD_STATE_PROBING: - /* Send a probe */ - r = arp_send_probe(acd->fd, acd->ifindex, acd->address, &acd->mac_addr); - if (r < 0) { - log_ipv4acd_errno(acd, r, "Failed to send ARP probe: %m"); - goto fail; - } else { - _cleanup_free_ char *address = NULL; - union in_addr_union addr = { .in.s_addr = acd->address }; - - (void) in_addr_to_string(AF_INET, &addr, &address); - log_ipv4acd(acd, "Probing %s", strna(address)); - } - - if (acd->n_iteration < PROBE_NUM - 2) { - ipv4acd_set_state(acd, IPV4ACD_STATE_PROBING, false); - - r = ipv4acd_set_next_wakeup(acd, PROBE_MIN_USEC, (PROBE_MAX_USEC-PROBE_MIN_USEC)); - if (r < 0) - goto fail; - } else { - ipv4acd_set_state(acd, IPV4ACD_STATE_WAITING_ANNOUNCE, true); - - r = ipv4acd_set_next_wakeup(acd, ANNOUNCE_WAIT_USEC, 0); - if (r < 0) - goto fail; - } - - break; - - case IPV4ACD_STATE_ANNOUNCING: - if (acd->n_iteration >= ANNOUNCE_NUM - 1) { - ipv4acd_set_state(acd, IPV4ACD_STATE_RUNNING, false); - break; - } - - _fallthrough_; - case IPV4ACD_STATE_WAITING_ANNOUNCE: - /* Send announcement packet */ - r = arp_send_announcement(acd->fd, acd->ifindex, acd->address, &acd->mac_addr); - if (r < 0) { - log_ipv4acd_errno(acd, r, "Failed to send ARP announcement: %m"); - goto fail; - } else - log_ipv4acd(acd, "ANNOUNCE"); - - ipv4acd_set_state(acd, IPV4ACD_STATE_ANNOUNCING, false); - - r = ipv4acd_set_next_wakeup(acd, ANNOUNCE_INTERVAL_USEC, 0); - if (r < 0) - goto fail; - - if (acd->n_iteration == 0) { - acd->n_conflict = 0; - ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_BIND); - } - - break; - - default: - assert_not_reached("Invalid state."); - } - - return 0; - -fail: - sd_ipv4acd_stop(acd); - return 0; -} - -static void ipv4acd_on_conflict(sd_ipv4acd *acd) { - _cleanup_free_ char *address = NULL; - union in_addr_union addr = { .in.s_addr = acd->address }; - - assert(acd); - - acd->n_conflict++; - - (void) in_addr_to_string(AF_INET, &addr, &address); - log_ipv4acd(acd, "Conflict on %s (%u)", strna(address), acd->n_conflict); - - ipv4acd_reset(acd); - ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_CONFLICT); -} - -static int ipv4acd_on_packet( - sd_event_source *s, - int fd, - uint32_t revents, - void *userdata) { - - sd_ipv4acd *acd = userdata; - struct ether_arp packet; - ssize_t n; - int r; - - assert(s); - assert(acd); - assert(fd >= 0); - - n = recv(fd, &packet, sizeof(struct ether_arp), 0); - if (n < 0) { - if (IN_SET(errno, EAGAIN, EINTR)) - return 0; - - log_ipv4acd_errno(acd, errno, "Failed to read ARP packet: %m"); - goto fail; - } - if ((size_t) n != sizeof(struct ether_arp)) { - log_ipv4acd(acd, "Ignoring too short ARP packet."); - return 0; - } - - switch (acd->state) { - - case IPV4ACD_STATE_ANNOUNCING: - case IPV4ACD_STATE_RUNNING: - - if (ipv4acd_arp_conflict(acd, &packet)) { - usec_t ts; - - assert_se(sd_event_now(acd->event, clock_boottime_or_monotonic(), &ts) >= 0); - - /* Defend address */ - if (ts > acd->defend_window) { - acd->defend_window = ts + DEFEND_INTERVAL_USEC; - r = arp_send_announcement(acd->fd, acd->ifindex, acd->address, &acd->mac_addr); - if (r < 0) { - log_ipv4acd_errno(acd, r, "Failed to send ARP announcement: %m"); - goto fail; - } else - log_ipv4acd(acd, "DEFEND"); - - } else - ipv4acd_on_conflict(acd); - } - 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(acd); - break; - - default: - assert_not_reached("Invalid state."); - } - - return 0; - -fail: - sd_ipv4acd_stop(acd); - return 0; -} - -int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int ifindex) { - char ifname[IF_NAMESIZE + 1]; - - assert_return(acd, -EINVAL); - assert_return(ifindex > 0, -EINVAL); - assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY); - - if (!format_ifname(ifindex, ifname)) - return -ENODEV; - - strcpy(acd->ifname, ifname); - acd->ifindex = ifindex; - - return 0; -} - -int sd_ipv4acd_get_ifindex(sd_ipv4acd *acd) { - if (!acd) - return -EINVAL; - - return acd->ifindex; -} - -const char *sd_ipv4acd_get_ifname(sd_ipv4acd *acd) { - if (!acd) - return NULL; - - return empty_to_null(acd->ifname); -} - -int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr) { - assert_return(acd, -EINVAL); - assert_return(addr, -EINVAL); - assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY); - - acd->mac_addr = *addr; - - return 0; -} - -int sd_ipv4acd_detach_event(sd_ipv4acd *acd) { - assert_return(acd, -EINVAL); - - acd->event = sd_event_unref(acd->event); - - return 0; -} - -int sd_ipv4acd_attach_event(sd_ipv4acd *acd, sd_event *event, int64_t priority) { - int r; - - assert_return(acd, -EINVAL); - assert_return(!acd->event, -EBUSY); - - if (event) - acd->event = sd_event_ref(event); - else { - r = sd_event_default(&acd->event); - if (r < 0) - return r; - } - - acd->event_priority = priority; - - return 0; -} - -int sd_ipv4acd_set_callback(sd_ipv4acd *acd, sd_ipv4acd_callback_t cb, void *userdata) { - assert_return(acd, -EINVAL); - - acd->callback = cb; - acd->userdata = userdata; - - return 0; -} - -int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address) { - assert_return(acd, -EINVAL); - assert_return(address, -EINVAL); - assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY); - - acd->address = address->s_addr; - - return 0; -} - -int sd_ipv4acd_get_address(sd_ipv4acd *acd, struct in_addr *address) { - assert_return(acd, -EINVAL); - assert_return(address, -EINVAL); - - address->s_addr = acd->address; - - return 0; -} - -int sd_ipv4acd_is_running(sd_ipv4acd *acd) { - assert_return(acd, false); - - return acd->state != IPV4ACD_STATE_INIT; -} - -int sd_ipv4acd_start(sd_ipv4acd *acd, bool reset_conflicts) { - int r; - - assert_return(acd, -EINVAL); - assert_return(acd->event, -EINVAL); - assert_return(acd->ifindex > 0, -EINVAL); - assert_return(acd->address != 0, -EINVAL); - assert_return(!ether_addr_is_null(&acd->mac_addr), -EINVAL); - assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY); - - r = arp_network_bind_raw_socket(acd->ifindex, acd->address, &acd->mac_addr); - if (r < 0) - return r; - - CLOSE_AND_REPLACE(acd->fd, r); - acd->defend_window = 0; - - if (reset_conflicts) - acd->n_conflict = 0; - - r = sd_event_add_io(acd->event, &acd->receive_message_event_source, acd->fd, EPOLLIN, ipv4acd_on_packet, acd); - if (r < 0) - goto fail; - - r = sd_event_source_set_priority(acd->receive_message_event_source, acd->event_priority); - if (r < 0) - goto fail; - - (void) sd_event_source_set_description(acd->receive_message_event_source, "ipv4acd-receive-message"); - - r = ipv4acd_set_next_wakeup(acd, 0, 0); - if (r < 0) - goto fail; - - ipv4acd_set_state(acd, IPV4ACD_STATE_STARTED, true); - return 0; - -fail: - ipv4acd_reset(acd); - return r; -} diff --git a/src/core/systemd/src/libsystemd-network/sd-ipv4ll.c b/src/core/systemd/src/libsystemd-network/sd-ipv4ll.c deleted file mode 100644 index c5e7a91f..00000000 --- a/src/core/systemd/src/libsystemd-network/sd-ipv4ll.c +++ /dev/null @@ -1,342 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/*** - Copyright © 2014 Axis Communications AB. All rights reserved. -***/ - -#include "nm-sd-adapt-core.h" - -#include -#include -#include -#include - -#include "sd-id128.h" -#include "sd-ipv4acd.h" -#include "sd-ipv4ll.h" - -#include "alloc-util.h" -#include "ether-addr-util.h" -#include "in-addr-util.h" -#include "log-link.h" -#include "random-util.h" -#include "siphash24.h" -#include "sparse-endian.h" -#include "string-util.h" -#include "util.h" - -#define IPV4LL_NETWORK UINT32_C(0xA9FE0000) -#define IPV4LL_NETMASK UINT32_C(0xFFFF0000) - -#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 ether_addr mac; - - struct { - le64_t value; - le64_t generation; - } seed; - bool seed_set; - - /* External */ - be32_t claimed_address; - - sd_ipv4ll_callback_t callback; - void* userdata; -}; - -#define log_ipv4ll_errno(ll, error, fmt, ...) \ - log_interface_full_errno(sd_ipv4ll_get_ifname(ll), LOG_DEBUG, error, "IPV4LL: " fmt, ##__VA_ARGS__) -#define log_ipv4ll(ll, fmt, ...) \ - log_ipv4ll_errno(ll, 0, fmt, ##__VA_ARGS__) - -static void ipv4ll_on_acd(sd_ipv4acd *ll, int event, void *userdata); - -static sd_ipv4ll *ipv4ll_free(sd_ipv4ll *ll) { - assert(ll); - - sd_ipv4acd_unref(ll->acd); - return mfree(ll); -} - -DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_ipv4ll, sd_ipv4ll, ipv4ll_free); - -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 = TAKE_PTR(ll); - - return 0; -} - -int sd_ipv4ll_stop(sd_ipv4ll *ll) { - if (!ll) - return 0; - - return sd_ipv4acd_stop(ll->acd); -} - -int sd_ipv4ll_set_ifindex(sd_ipv4ll *ll, int ifindex) { - assert_return(ll, -EINVAL); - assert_return(ifindex > 0, -EINVAL); - assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY); - - return sd_ipv4acd_set_ifindex(ll->acd, ifindex); -} - -int sd_ipv4ll_get_ifindex(sd_ipv4ll *ll) { - if (!ll) - return -EINVAL; - - return sd_ipv4acd_get_ifindex(ll->acd); -} - -const char *sd_ipv4ll_get_ifname(sd_ipv4ll *ll) { - if (!ll) - return NULL; - - return sd_ipv4acd_get_ifname(ll->acd); -} - -int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr) { - int r; - - assert_return(ll, -EINVAL); - assert_return(addr, -EINVAL); - assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY); - - r = sd_ipv4acd_set_mac(ll->acd, addr); - if (r < 0) - return r; - - ll->mac = *addr; - return 0; -} - -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, int64_t priority) { - assert_return(ll, -EINVAL); - - return sd_ipv4acd_attach_event(ll->acd, event, priority); -} - -int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata) { - assert_return(ll, -EINVAL); - - ll->callback = 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, uint64_t seed) { - assert_return(ll, -EINVAL); - assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY); - - ll->seed.value = htole64(seed); - ll->seed_set = true; - - 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) { - assert(address); - - if (!in_addr_is_link_local(AF_INET, (const union in_addr_union *) address)) - return false; - - return !IN_SET(be32toh(address->s_addr) & 0x0000FF00U, 0x0000U, 0xFF00U); -} - -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; -} - -#define PICK_HASH_KEY SD_ID128_MAKE(15,ac,82,a6,d6,3f,49,78,98,77,5d,0c,69,02,94,0b) - -static int ipv4ll_pick_address(sd_ipv4ll *ll) { - _cleanup_free_ char *address = NULL; - be32_t addr; - - assert(ll); - - do { - uint64_t h; - - h = siphash24(&ll->seed, sizeof(ll->seed), PICK_HASH_KEY.bytes); - - /* Increase the generation counter by one */ - ll->seed.generation = htole64(le64toh(ll->seed.generation) + 1); - - addr = htobe32((h & UINT32_C(0x0000FFFF)) | IPV4LL_NETWORK); - } while (addr == ll->address || - IN_SET(be32toh(addr) & 0x0000FF00U, 0x0000U, 0xFF00U)); - - (void) in_addr_to_string(AF_INET, &(union in_addr_union) { .in.s_addr = addr }, &address); - log_ipv4ll(ll, "Picked new IP address %s.", strna(address)); - - return sd_ipv4ll_set_address(ll, &(struct in_addr) { addr }); -} - -#define MAC_HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2) - -static int ipv4ll_start_internal(sd_ipv4ll *ll, bool reset_generation) { - int r; - bool picked_address = false; - - assert_return(ll, -EINVAL); - assert_return(!ether_addr_is_null(&ll->mac), -EINVAL); - - /* If no random seed is set, generate some from the MAC address */ - if (!ll->seed_set) - ll->seed.value = htole64(siphash24(ll->mac.ether_addr_octet, ETH_ALEN, MAC_HASH_KEY.bytes)); - - if (reset_generation) - ll->seed.generation = 0; - - if (ll->address == 0) { - r = ipv4ll_pick_address(ll); - if (r < 0) - return r; - - picked_address = true; - } - - r = sd_ipv4acd_start(ll->acd, reset_generation); - if (r < 0) { - - /* We couldn't start? If so, let's forget the picked address again, the user might make a change and - * retry, and we want the new data to take effect when picking an address. */ - if (picked_address) - ll->address = 0; - - return r; - } - - return 1; -} - -int sd_ipv4ll_start(sd_ipv4ll *ll) { - assert_return(ll, -EINVAL); - - if (sd_ipv4ll_is_running(ll)) - return 0; - - return ipv4ll_start_internal(ll, true); -} - -int sd_ipv4ll_restart(sd_ipv4ll *ll) { - ll->address = 0; - - return ipv4ll_start_internal(ll, false); -} - -static void ipv4ll_client_notify(sd_ipv4ll *ll, int event) { - assert(ll); - - if (ll->callback) - ll->callback(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 = sd_ipv4ll_restart(ll); - 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/core/systemd/src/libsystemd-network/sd-lldp.c b/src/core/systemd/src/libsystemd-network/sd-lldp.c deleted file mode 100644 index b12d8e27..00000000 --- a/src/core/systemd/src/libsystemd-network/sd-lldp.c +++ /dev/null @@ -1,500 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include "nm-sd-adapt-core.h" - -#include -#include -#include - -#include "sd-lldp.h" - -#include "alloc-util.h" -#include "ether-addr-util.h" -#include "event-util.h" -#include "fd-util.h" -#include "lldp-internal.h" -#include "lldp-neighbor.h" -#include "lldp-network.h" -#include "memory-util.h" -#include "socket-util.h" -#include "sort-util.h" -#include "string-table.h" - -#define LLDP_DEFAULT_NEIGHBORS_MAX 128U - -static const char * const lldp_event_table[_SD_LLDP_EVENT_MAX] = { - [SD_LLDP_EVENT_ADDED] = "added", - [SD_LLDP_EVENT_REMOVED] = "removed", - [SD_LLDP_EVENT_UPDATED] = "updated", - [SD_LLDP_EVENT_REFRESHED] = "refreshed", -}; - -DEFINE_STRING_TABLE_LOOKUP(lldp_event, sd_lldp_event); - -static void lldp_flush_neighbors(sd_lldp *lldp) { - assert(lldp); - - hashmap_clear(lldp->neighbor_by_id); -} - -static void lldp_callback(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n) { - assert(lldp); - assert(event >= 0 && event < _SD_LLDP_EVENT_MAX); - - if (!lldp->callback) { - log_lldp("Received '%s' event.", lldp_event_to_string(event)); - return; - } - - log_lldp("Invoking callback for '%s' event.", lldp_event_to_string(event)); - lldp->callback(lldp, event, n, lldp->userdata); -} - -static int lldp_make_space(sd_lldp *lldp, size_t extra) { - usec_t t = USEC_INFINITY; - bool changed = false; - - assert(lldp); - - /* Remove all entries that are past their TTL, and more until at least the specified number of extra entries - * are free. */ - - for (;;) { - _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; - - n = prioq_peek(lldp->neighbor_by_expiry); - if (!n) - break; - - sd_lldp_neighbor_ref(n); - - if (hashmap_size(lldp->neighbor_by_id) > LESS_BY(lldp->neighbors_max, extra)) - goto remove_one; - - if (t == USEC_INFINITY) - t = now(clock_boottime_or_monotonic()); - - if (n->until > t) - break; - - remove_one: - lldp_neighbor_unlink(n); - lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, n); - changed = true; - } - - return changed; -} - -static bool lldp_keep_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { - assert(lldp); - assert(n); - - /* Don't keep data with a zero TTL */ - if (n->ttl <= 0) - return false; - - /* Filter out data from the filter address */ - if (!ether_addr_is_null(&lldp->filter_address) && - ether_addr_equal(&lldp->filter_address, &n->source_address)) - return false; - - /* Only add if the neighbor has a capability we are interested in. Note that we also store all neighbors with - * no caps field set. */ - if (n->has_capabilities && - (n->enabled_capabilities & lldp->capability_mask) == 0) - return false; - - /* Keep everything else */ - return true; -} - -static int lldp_start_timer(sd_lldp *lldp, sd_lldp_neighbor *neighbor); - -static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { - _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *old = NULL; - bool keep; - int r; - - assert(lldp); - assert(n); - assert(!n->lldp); - - keep = lldp_keep_neighbor(lldp, n); - - /* First retrieve the old entry for this MSAP */ - old = hashmap_get(lldp->neighbor_by_id, &n->id); - if (old) { - sd_lldp_neighbor_ref(old); - - if (!keep) { - lldp_neighbor_unlink(old); - lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, old); - return 0; - } - - if (lldp_neighbor_equal(n, old)) { - /* Is this equal, then restart the TTL counter, but don't do anything else. */ - old->timestamp = n->timestamp; - lldp_start_timer(lldp, old); - lldp_callback(lldp, SD_LLDP_EVENT_REFRESHED, old); - return 0; - } - - /* Data changed, remove the old entry, and add a new one */ - lldp_neighbor_unlink(old); - - } else if (!keep) - return 0; - - /* Then, make room for at least one new neighbor */ - lldp_make_space(lldp, 1); - - r = hashmap_put(lldp->neighbor_by_id, &n->id, n); - if (r < 0) - goto finish; - - r = prioq_put(lldp->neighbor_by_expiry, n, &n->prioq_idx); - if (r < 0) { - assert_se(hashmap_remove(lldp->neighbor_by_id, &n->id) == n); - goto finish; - } - - n->lldp = lldp; - - lldp_start_timer(lldp, n); - lldp_callback(lldp, old ? SD_LLDP_EVENT_UPDATED : SD_LLDP_EVENT_ADDED, n); - - return 1; - -finish: - if (old) - lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, old); - - return r; -} - -static int lldp_handle_datagram(sd_lldp *lldp, sd_lldp_neighbor *n) { - int r; - - assert(lldp); - assert(n); - - r = lldp_neighbor_parse(n); - if (r == -EBADMSG) /* Ignore bad messages */ - return 0; - if (r < 0) - return r; - - r = lldp_add_neighbor(lldp, n); - if (r < 0) { - log_lldp_errno(r, "Failed to add datagram. Ignoring."); - return 0; - } - - log_lldp("Successfully processed LLDP datagram."); - return 0; -} - -static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; - ssize_t space, length; - sd_lldp *lldp = userdata; - struct timespec ts; - - assert(fd >= 0); - assert(lldp); - - space = next_datagram_size_fd(fd); - if (space < 0) - return log_lldp_errno(space, "Failed to determine datagram size to read: %m"); - - n = lldp_neighbor_new(space); - if (!n) - return -ENOMEM; - - length = recv(fd, LLDP_NEIGHBOR_RAW(n), n->raw_size, MSG_DONTWAIT); - if (length < 0) { - if (IN_SET(errno, EAGAIN, EINTR)) - return 0; - - return log_lldp_errno(errno, "Failed to read LLDP datagram: %m"); - } - - if ((size_t) length != n->raw_size) { - log_lldp("Packet size mismatch."); - return -EINVAL; - } - - /* Try to get the timestamp of this packet if it is known */ - if (ioctl(fd, SIOCGSTAMPNS, &ts) >= 0) - triple_timestamp_from_realtime(&n->timestamp, timespec_load(&ts)); - else - triple_timestamp_get(&n->timestamp); - - return lldp_handle_datagram(lldp, n); -} - -static void lldp_reset(sd_lldp *lldp) { - assert(lldp); - - (void) event_source_disable(lldp->timer_event_source); - lldp->io_event_source = sd_event_source_unref(lldp->io_event_source); - lldp->fd = safe_close(lldp->fd); -} - -_public_ int sd_lldp_start(sd_lldp *lldp) { - int r; - - assert_return(lldp, -EINVAL); - assert_return(lldp->event, -EINVAL); - assert_return(lldp->ifindex > 0, -EINVAL); - - if (lldp->fd >= 0) - return 0; - - assert(!lldp->io_event_source); - - lldp->fd = lldp_network_bind_raw_socket(lldp->ifindex); - if (lldp->fd < 0) - return lldp->fd; - - r = sd_event_add_io(lldp->event, &lldp->io_event_source, lldp->fd, EPOLLIN, lldp_receive_datagram, lldp); - if (r < 0) - goto fail; - - r = sd_event_source_set_priority(lldp->io_event_source, lldp->event_priority); - if (r < 0) - goto fail; - - (void) sd_event_source_set_description(lldp->io_event_source, "lldp-io"); - - log_lldp("Started LLDP client"); - return 1; - -fail: - lldp_reset(lldp); - return r; -} - -_public_ int sd_lldp_stop(sd_lldp *lldp) { - if (!lldp) - return 0; - - if (lldp->fd < 0) - return 0; - - log_lldp("Stopping LLDP client"); - - lldp_reset(lldp); - lldp_flush_neighbors(lldp); - - return 1; -} - -_public_ int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int64_t priority) { - int r; - - assert_return(lldp, -EINVAL); - assert_return(lldp->fd < 0, -EBUSY); - assert_return(!lldp->event, -EBUSY); - - if (event) - lldp->event = sd_event_ref(event); - else { - r = sd_event_default(&lldp->event); - if (r < 0) - return r; - } - - lldp->event_priority = priority; - - return 0; -} - -_public_ int sd_lldp_detach_event(sd_lldp *lldp) { - - assert_return(lldp, -EINVAL); - assert_return(lldp->fd < 0, -EBUSY); - - lldp->event = sd_event_unref(lldp->event); - return 0; -} - -_public_ sd_event* sd_lldp_get_event(sd_lldp *lldp) { - assert_return(lldp, NULL); - - return lldp->event; -} - -_public_ int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata) { - assert_return(lldp, -EINVAL); - - lldp->callback = cb; - lldp->userdata = userdata; - - return 0; -} - -_public_ int sd_lldp_set_ifindex(sd_lldp *lldp, int ifindex) { - assert_return(lldp, -EINVAL); - assert_return(ifindex > 0, -EINVAL); - assert_return(lldp->fd < 0, -EBUSY); - - lldp->ifindex = ifindex; - return 0; -} - -static sd_lldp* lldp_free(sd_lldp *lldp) { - assert(lldp); - - lldp->timer_event_source = sd_event_source_unref(lldp->timer_event_source); - - lldp_reset(lldp); - sd_lldp_detach_event(lldp); - lldp_flush_neighbors(lldp); - - hashmap_free(lldp->neighbor_by_id); - prioq_free(lldp->neighbor_by_expiry); - return mfree(lldp); -} - -DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_lldp, sd_lldp, lldp_free); - -_public_ int sd_lldp_new(sd_lldp **ret) { - _cleanup_(sd_lldp_unrefp) sd_lldp *lldp = NULL; - int r; - - assert_return(ret, -EINVAL); - - lldp = new(sd_lldp, 1); - if (!lldp) - return -ENOMEM; - - *lldp = (sd_lldp) { - .n_ref = 1, - .fd = -1, - .neighbors_max = LLDP_DEFAULT_NEIGHBORS_MAX, - .capability_mask = (uint16_t) -1, - }; - - lldp->neighbor_by_id = hashmap_new(&lldp_neighbor_hash_ops); - if (!lldp->neighbor_by_id) - return -ENOMEM; - - r = prioq_ensure_allocated(&lldp->neighbor_by_expiry, lldp_neighbor_prioq_compare_func); - if (r < 0) - return r; - - *ret = TAKE_PTR(lldp); - - return 0; -} - -static int neighbor_compare_func(sd_lldp_neighbor * const *a, sd_lldp_neighbor * const *b) { - return lldp_neighbor_id_compare_func(&(*a)->id, &(*b)->id); -} - -static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) { - sd_lldp *lldp = userdata; - int r; - - r = lldp_make_space(lldp, 0); - if (r < 0) - return log_lldp_errno(r, "Failed to make space: %m"); - - r = lldp_start_timer(lldp, NULL); - if (r < 0) - return log_lldp_errno(r, "Failed to restart timer: %m"); - - return 0; -} - -static int lldp_start_timer(sd_lldp *lldp, sd_lldp_neighbor *neighbor) { - sd_lldp_neighbor *n; - - assert(lldp); - - if (neighbor) - lldp_neighbor_start_ttl(neighbor); - - n = prioq_peek(lldp->neighbor_by_expiry); - if (!n) - return event_source_disable(lldp->timer_event_source); - - if (!lldp->event) - return 0; - - return event_reset_time(lldp->event, &lldp->timer_event_source, - clock_boottime_or_monotonic(), - n->until, 0, - on_timer_event, lldp, - lldp->event_priority, "lldp-timer", true); -} - -_public_ int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***ret) { - sd_lldp_neighbor **l = NULL, *n; - int k = 0, r; - - assert_return(lldp, -EINVAL); - assert_return(ret, -EINVAL); - - if (hashmap_isempty(lldp->neighbor_by_id)) { /* Special shortcut */ - *ret = NULL; - return 0; - } - - l = new0(sd_lldp_neighbor*, hashmap_size(lldp->neighbor_by_id)); - if (!l) - return -ENOMEM; - - r = lldp_start_timer(lldp, NULL); - if (r < 0) { - free(l); - return r; - } - - HASHMAP_FOREACH(n, lldp->neighbor_by_id) - l[k++] = sd_lldp_neighbor_ref(n); - - assert((size_t) k == hashmap_size(lldp->neighbor_by_id)); - - /* Return things in a stable order */ - typesafe_qsort(l, k, neighbor_compare_func); - *ret = l; - - return k; -} - -_public_ int sd_lldp_set_neighbors_max(sd_lldp *lldp, uint64_t m) { - assert_return(lldp, -EINVAL); - assert_return(m > 0, -EINVAL); - - lldp->neighbors_max = m; - lldp_make_space(lldp, 0); - - return 0; -} - -_public_ int sd_lldp_match_capabilities(sd_lldp *lldp, uint16_t mask) { - assert_return(lldp, -EINVAL); - assert_return(mask != 0, -EINVAL); - - lldp->capability_mask = mask; - - return 0; -} - -_public_ int sd_lldp_set_filter_address(sd_lldp *lldp, const struct ether_addr *addr) { - assert_return(lldp, -EINVAL); - - /* In order to deal nicely with bridges that send back our own packets, allow one address to be filtered, so - * that our own can be filtered out here. */ - - if (addr) - lldp->filter_address = *addr; - else - zero(lldp->filter_address); - - return 0; -} diff --git a/src/core/systemd/src/libsystemd/sd-event/event-source.h b/src/core/systemd/src/libsystemd/sd-event/event-source.h deleted file mode 100644 index f0d2a1b9..00000000 --- a/src/core/systemd/src/libsystemd/sd-event/event-source.h +++ /dev/null @@ -1,220 +0,0 @@ -#pragma once -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include -#include -#include - -#include "sd-event.h" - -#include "fs-util.h" -#include "hashmap.h" -#include "list.h" -#include "prioq.h" -#include "ratelimit.h" - -typedef enum EventSourceType { - SOURCE_IO, - SOURCE_TIME_REALTIME, - SOURCE_TIME_BOOTTIME, - SOURCE_TIME_MONOTONIC, - SOURCE_TIME_REALTIME_ALARM, - SOURCE_TIME_BOOTTIME_ALARM, - SOURCE_SIGNAL, - SOURCE_CHILD, - SOURCE_DEFER, - SOURCE_POST, - SOURCE_EXIT, - SOURCE_WATCHDOG, - SOURCE_INOTIFY, - _SOURCE_EVENT_SOURCE_TYPE_MAX, - _SOURCE_EVENT_SOURCE_TYPE_INVALID = -1 -} EventSourceType; - -/* All objects we use in epoll events start with this value, so that - * we know how to dispatch it */ -typedef enum WakeupType { - WAKEUP_NONE, - WAKEUP_EVENT_SOURCE, /* either I/O or pidfd wakeup */ - WAKEUP_CLOCK_DATA, - WAKEUP_SIGNAL_DATA, - WAKEUP_INOTIFY_DATA, - _WAKEUP_TYPE_MAX, - _WAKEUP_TYPE_INVALID = -1, -} WakeupType; - -struct inode_data; - -struct sd_event_source { - WakeupType wakeup; - - unsigned n_ref; - - sd_event *event; - void *userdata; - sd_event_handler_t prepare; - - char *description; - - EventSourceType type:5; - signed int enabled:3; - bool pending:1; - bool dispatching:1; - bool floating:1; - bool exit_on_failure:1; - bool ratelimited:1; - - int64_t priority; - unsigned pending_index; - unsigned prepare_index; - uint64_t pending_iteration; - uint64_t prepare_iteration; - - sd_event_destroy_t destroy_callback; - - LIST_FIELDS(sd_event_source, sources); - - RateLimit rate_limit; - - /* These are primarily fields relevant for time event sources, but since any event source can - * effectively become one when rate-limited, this is part of the common fields. */ - unsigned earliest_index; - unsigned latest_index; - - union { - struct { - sd_event_io_handler_t callback; - int fd; - uint32_t events; - uint32_t revents; - bool registered:1; - bool owned:1; - } io; - struct { - sd_event_time_handler_t callback; - usec_t next, accuracy; - } time; - struct { - sd_event_signal_handler_t callback; - struct signalfd_siginfo siginfo; - int sig; - } signal; - struct { - sd_event_child_handler_t callback; - siginfo_t siginfo; - pid_t pid; - int options; - int pidfd; - bool registered:1; /* whether the pidfd is registered in the epoll */ - bool pidfd_owned:1; /* close pidfd when event source is freed */ - bool process_owned:1; /* kill+reap process when event source is freed */ - bool exited:1; /* true if process exited (i.e. if there's value in SIGKILLing it if we want to get rid of it) */ - bool waited:1; /* true if process was waited for (i.e. if there's value in waitid(P_PID)'ing it if we want to get rid of it) */ - } child; - struct { - sd_event_handler_t callback; - } defer; - struct { - sd_event_handler_t callback; - } post; - struct { - sd_event_handler_t callback; - unsigned prioq_index; - } exit; - struct { - sd_event_inotify_handler_t callback; - uint32_t mask; - struct inode_data *inode_data; - LIST_FIELDS(sd_event_source, by_inode_data); - } inotify; - }; -}; - -struct clock_data { - WakeupType wakeup; - int fd; - - /* For all clocks we maintain two priority queues each, one - * ordered for the earliest times the events may be - * dispatched, and one ordered by the latest times they must - * have been dispatched. The range between the top entries in - * the two prioqs is the time window we can freely schedule - * wakeups in */ - - Prioq *earliest; - Prioq *latest; - usec_t next; - - bool needs_rearm:1; -}; - -struct signal_data { - WakeupType wakeup; - - /* For each priority we maintain one signal fd, so that we - * only have to dequeue a single event per priority at a - * time. */ - - int fd; - int64_t priority; - sigset_t sigset; - sd_event_source *current; -}; - -/* A structure listing all event sources currently watching a specific inode */ -struct inode_data { - /* The identifier for the inode, the combination of the .st_dev + .st_ino fields of the file */ - ino_t ino; - dev_t dev; - - /* An fd of the inode to watch. The fd is kept open until the next iteration of the loop, so that we can - * rearrange the priority still until then, as we need the original inode to change the priority as we need to - * add a watch descriptor to the right inotify for the priority which we can only do if we have a handle to the - * original inode. We keep a list of all inode_data objects with an open fd in the to_close list (see below) of - * the sd-event object, so that it is efficient to close everything, before entering the next event loop - * iteration. */ - int fd; - - /* The inotify "watch descriptor" */ - int wd; - - /* The combination of the mask of all inotify watches on this inode we manage. This is also the mask that has - * most recently been set on the watch descriptor. */ - uint32_t combined_mask; - - /* All event sources subscribed to this inode */ - LIST_HEAD(sd_event_source, event_sources); - - /* The inotify object we watch this inode with */ - struct inotify_data *inotify_data; - - /* A linked list of all inode data objects with fds to close (see above) */ - LIST_FIELDS(struct inode_data, to_close); -}; - -/* A structure encapsulating an inotify fd */ -struct inotify_data { - WakeupType wakeup; - - /* For each priority we maintain one inotify fd, so that we only have to dequeue a single event per priority at - * a time */ - - int fd; - int64_t priority; - - Hashmap *inodes; /* The inode_data structures keyed by dev+ino */ - Hashmap *wd; /* The inode_data structures keyed by the watch descriptor for each */ - - /* The buffer we read inotify events into */ - union inotify_event_buffer buffer; - size_t buffer_filled; /* fill level of the buffer */ - - /* How many event sources are currently marked pending for this inotify. We won't read new events off the - * inotify fd as long as there are still pending events on the inotify (because we have no strategy of queuing - * the events locally if they can't be coalesced). */ - unsigned n_pending; - - /* A linked list of all inotify objects with data already read, that still need processing. We keep this list - * to make it efficient to figure out what inotify objects to process data on next. */ - LIST_FIELDS(struct inotify_data, buffered); -}; diff --git a/src/core/systemd/src/libsystemd/sd-event/event-util.c b/src/core/systemd/src/libsystemd/sd-event/event-util.c deleted file mode 100644 index 7cc55be1..00000000 --- a/src/core/systemd/src/libsystemd/sd-event/event-util.c +++ /dev/null @@ -1,101 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include "nm-sd-adapt-core.h" - -#include - -#include "event-source.h" -#include "event-util.h" -#include "log.h" -#include "string-util.h" - -int event_reset_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, - int64_t priority, - const char *description, - bool force_reset) { - - bool created = false; - int enabled, r; - clockid_t c; - - assert(e); - assert(s); - - if (*s) { - if (!force_reset) { - r = sd_event_source_get_enabled(*s, &enabled); - if (r < 0) - return log_debug_errno(r, "sd-event: Failed to query whether event source \"%s\" is enabled or not: %m", - strna((*s)->description ?: description)); - - if (enabled != SD_EVENT_OFF) - return 0; - } - - r = sd_event_source_get_time_clock(*s, &c); - if (r < 0) - return log_debug_errno(r, "sd-event: Failed to get clock id of event source \"%s\": %m", strna((*s)->description ?: description)); - - if (c != clock) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "sd-event: Current clock id %i of event source \"%s\" is different from specified one %i.", - (int)c, - strna((*s)->description ? : description), - (int)clock); - - r = sd_event_source_set_time(*s, usec); - if (r < 0) - return log_debug_errno(r, "sd-event: Failed to set time for event source \"%s\": %m", strna((*s)->description ?: description)); - - r = sd_event_source_set_time_accuracy(*s, accuracy); - if (r < 0) - return log_debug_errno(r, "sd-event: Failed to set accuracy for event source \"%s\": %m", strna((*s)->description ?: description)); - - /* callback function is not updated, as we do not have sd_event_source_set_time_callback(). */ - - (void) sd_event_source_set_userdata(*s, userdata); - - r = sd_event_source_set_enabled(*s, SD_EVENT_ONESHOT); - if (r < 0) - return log_debug_errno(r, "sd-event: Failed to enable event source \"%s\": %m", strna((*s)->description ?: description)); - } else { - r = sd_event_add_time(e, s, clock, usec, accuracy, callback, userdata); - if (r < 0) - return log_debug_errno(r, "sd-event: Failed to create timer event \"%s\": %m", strna(description)); - - created = true; - } - - r = sd_event_source_set_priority(*s, priority); - if (r < 0) - return log_debug_errno(r, "sd-event: Failed to set priority for event source \"%s\": %m", strna((*s)->description ?: description)); - - if (description) { - r = sd_event_source_set_description(*s, description); - if (r < 0) - return log_debug_errno(r, "sd-event: Failed to set description for event source \"%s\": %m", description); - } - - return created; -} - -int event_source_disable(sd_event_source *s) { - if (!s) - return 0; - - return sd_event_source_set_enabled(s, SD_EVENT_OFF); -} - -int event_source_is_enabled(sd_event_source *s) { - if (!s) - return false; - - return sd_event_source_get_enabled(s, NULL); -} diff --git a/src/core/systemd/src/libsystemd/sd-event/event-util.h b/src/core/systemd/src/libsystemd/sd-event/event-util.h deleted file mode 100644 index c8f97bc8..00000000 --- a/src/core/systemd/src/libsystemd/sd-event/event-util.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -#include - -#include "sd-event.h" - -int event_reset_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, - int64_t priority, const char *description, bool force_reset); -int event_source_disable(sd_event_source *s); -int event_source_is_enabled(sd_event_source *s); diff --git a/src/core/systemd/src/libsystemd/sd-event/sd-event.c b/src/core/systemd/src/libsystemd/sd-event/sd-event.c deleted file mode 100644 index dda4be00..00000000 --- a/src/core/systemd/src/libsystemd/sd-event/sd-event.c +++ /dev/null @@ -1,4329 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include "nm-sd-adapt-core.h" - -#include -#include -#include - -#include "sd-daemon.h" -#include "sd-event.h" -#include "sd-id128.h" - -#include "alloc-util.h" -#include "env-util.h" -#include "event-source.h" -#include "fd-util.h" -#include "fs-util.h" -#include "hashmap.h" -#include "list.h" -#include "macro.h" -#include "memory-util.h" -#include "missing_syscall.h" -#include "prioq.h" -#include "process-util.h" -#include "set.h" -#include "signal-util.h" -#include "string-table.h" -#include "string-util.h" -#include "strxcpyx.h" -#include "time-util.h" - -#define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC) - -static bool EVENT_SOURCE_WATCH_PIDFD(sd_event_source *s) { - /* Returns true if this is a PID event source and can be implemented by watching EPOLLIN */ - return s && - s->type == SOURCE_CHILD && - s->child.pidfd >= 0 && - s->child.options == WEXITED; -} - -static bool event_source_is_online(sd_event_source *s) { - assert(s); - return s->enabled != SD_EVENT_OFF && !s->ratelimited; -} - -static bool event_source_is_offline(sd_event_source *s) { - assert(s); - return s->enabled == SD_EVENT_OFF || s->ratelimited; -} - -static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] = { - [SOURCE_IO] = "io", - [SOURCE_TIME_REALTIME] = "realtime", - [SOURCE_TIME_BOOTTIME] = "bootime", - [SOURCE_TIME_MONOTONIC] = "monotonic", - [SOURCE_TIME_REALTIME_ALARM] = "realtime-alarm", - [SOURCE_TIME_BOOTTIME_ALARM] = "boottime-alarm", - [SOURCE_SIGNAL] = "signal", - [SOURCE_CHILD] = "child", - [SOURCE_DEFER] = "defer", - [SOURCE_POST] = "post", - [SOURCE_EXIT] = "exit", - [SOURCE_WATCHDOG] = "watchdog", - [SOURCE_INOTIFY] = "inotify", -}; - -DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(event_source_type, int); - -#define EVENT_SOURCE_IS_TIME(t) \ - IN_SET((t), \ - SOURCE_TIME_REALTIME, \ - SOURCE_TIME_BOOTTIME, \ - SOURCE_TIME_MONOTONIC, \ - SOURCE_TIME_REALTIME_ALARM, \ - SOURCE_TIME_BOOTTIME_ALARM) - -#define EVENT_SOURCE_CAN_RATE_LIMIT(t) \ - IN_SET((t), \ - SOURCE_IO, \ - SOURCE_TIME_REALTIME, \ - SOURCE_TIME_BOOTTIME, \ - SOURCE_TIME_MONOTONIC, \ - SOURCE_TIME_REALTIME_ALARM, \ - SOURCE_TIME_BOOTTIME_ALARM, \ - SOURCE_SIGNAL, \ - SOURCE_DEFER, \ - SOURCE_INOTIFY) - -struct sd_event { - unsigned n_ref; - - int epoll_fd; - int watchdog_fd; - - Prioq *pending; - Prioq *prepare; - - /* timerfd_create() only supports these five clocks so far. We - * can add support for more clocks when the kernel learns to - * deal with them, too. */ - struct clock_data realtime; - struct clock_data boottime; - struct clock_data monotonic; - struct clock_data realtime_alarm; - struct clock_data boottime_alarm; - - usec_t perturb; - - sd_event_source **signal_sources; /* indexed by signal number */ - Hashmap *signal_data; /* indexed by priority */ - - Hashmap *child_sources; - unsigned n_online_child_sources; - - Set *post_sources; - - Prioq *exit; - - Hashmap *inotify_data; /* indexed by priority */ - - /* A list of inode structures that still have an fd open, that we need to close before the next loop iteration */ - LIST_HEAD(struct inode_data, inode_data_to_close); - - /* A list of inotify objects that already have events buffered which aren't processed yet */ - LIST_HEAD(struct inotify_data, inotify_data_buffered); - - pid_t original_pid; - - uint64_t iteration; - triple_timestamp timestamp; - int state; - - bool exit_requested:1; - bool need_process_child:1; - bool watchdog:1; - bool profile_delays:1; - - int exit_code; - - pid_t tid; - sd_event **default_event_ptr; - - usec_t watchdog_last, watchdog_period; - - unsigned n_sources; - - struct epoll_event *event_queue; - size_t event_queue_allocated; - - LIST_HEAD(sd_event_source, sources); - - usec_t last_run_usec, last_log_usec; - unsigned delays[sizeof(usec_t) * 8]; -}; - -static thread_local sd_event *default_event = NULL; - -static void source_disconnect(sd_event_source *s); -static void event_gc_inode_data(sd_event *e, struct inode_data *d); - -static sd_event *event_resolve(sd_event *e) { - return e == SD_EVENT_DEFAULT ? default_event : e; -} - -static int pending_prioq_compare(const void *a, const void *b) { - const sd_event_source *x = a, *y = b; - int r; - - assert(x->pending); - assert(y->pending); - - /* Enabled ones first */ - if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) - return -1; - if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) - return 1; - - /* Non rate-limited ones first. */ - r = CMP(!!x->ratelimited, !!y->ratelimited); - if (r != 0) - return r; - - /* Lower priority values first */ - r = CMP(x->priority, y->priority); - if (r != 0) - return r; - - /* Older entries first */ - return CMP(x->pending_iteration, y->pending_iteration); -} - -static int prepare_prioq_compare(const void *a, const void *b) { - const sd_event_source *x = a, *y = b; - int r; - - assert(x->prepare); - assert(y->prepare); - - /* Enabled ones first */ - if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) - return -1; - if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) - return 1; - - /* Non rate-limited ones first. */ - r = CMP(!!x->ratelimited, !!y->ratelimited); - if (r != 0) - return r; - - /* Move most recently prepared ones last, so that we can stop - * preparing as soon as we hit one that has already been - * prepared in the current iteration */ - r = CMP(x->prepare_iteration, y->prepare_iteration); - if (r != 0) - return r; - - /* Lower priority values first */ - return CMP(x->priority, y->priority); -} - -static usec_t time_event_source_next(const sd_event_source *s) { - assert(s); - - /* We have two kinds of event sources that have elapsation times associated with them: the actual - * time based ones and the ones for which a ratelimit can be in effect (where we want to be notified - * once the ratelimit time window ends). Let's return the next elapsing time depending on what we are - * looking at here. */ - - if (s->ratelimited) { /* If rate-limited the next elapsation is when the ratelimit time window ends */ - assert(s->rate_limit.begin != 0); - assert(s->rate_limit.interval != 0); - return usec_add(s->rate_limit.begin, s->rate_limit.interval); - } - - /* Otherwise this must be a time event source, if not ratelimited */ - if (EVENT_SOURCE_IS_TIME(s->type)) - return s->time.next; - - return USEC_INFINITY; -} - -static int earliest_time_prioq_compare(const void *a, const void *b) { - const sd_event_source *x = a, *y = b; - - /* Enabled ones first */ - if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) - return -1; - if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) - return 1; - - /* Move the pending ones to the end */ - if (!x->pending && y->pending) - return -1; - if (x->pending && !y->pending) - return 1; - - /* Order by time */ - return CMP(time_event_source_next(x), time_event_source_next(y)); -} - -static usec_t time_event_source_latest(const sd_event_source *s) { - assert(s); - - if (s->ratelimited) { /* For ratelimited stuff the earliest and the latest time shall actually be the - * same, as we should avoid adding additional inaccuracy on an inaccuracy time - * window */ - assert(s->rate_limit.begin != 0); - assert(s->rate_limit.interval != 0); - return usec_add(s->rate_limit.begin, s->rate_limit.interval); - } - - /* Must be a time event source, if not ratelimited */ - if (EVENT_SOURCE_IS_TIME(s->type)) - return usec_add(s->time.next, s->time.accuracy); - - return USEC_INFINITY; -} - -static int latest_time_prioq_compare(const void *a, const void *b) { - const sd_event_source *x = a, *y = b; - - /* Enabled ones first */ - if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) - return -1; - if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) - return 1; - - /* Move the pending ones to the end */ - if (!x->pending && y->pending) - return -1; - if (x->pending && !y->pending) - return 1; - - /* Order by time */ - return CMP(time_event_source_latest(x), time_event_source_latest(y)); -} - -static int exit_prioq_compare(const void *a, const void *b) { - const sd_event_source *x = a, *y = b; - - assert(x->type == SOURCE_EXIT); - assert(y->type == SOURCE_EXIT); - - /* Enabled ones first */ - if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) - return -1; - if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) - return 1; - - /* Lower priority values first */ - return CMP(x->priority, y->priority); -} - -static void free_clock_data(struct clock_data *d) { - assert(d); - assert(d->wakeup == WAKEUP_CLOCK_DATA); - - safe_close(d->fd); - prioq_free(d->earliest); - prioq_free(d->latest); -} - -static sd_event *event_free(sd_event *e) { - sd_event_source *s; - - assert(e); - - while ((s = e->sources)) { - assert(s->floating); - source_disconnect(s); - sd_event_source_unref(s); - } - - assert(e->n_sources == 0); - - if (e->default_event_ptr) - *(e->default_event_ptr) = NULL; - - safe_close(e->epoll_fd); - safe_close(e->watchdog_fd); - - free_clock_data(&e->realtime); - free_clock_data(&e->boottime); - free_clock_data(&e->monotonic); - free_clock_data(&e->realtime_alarm); - free_clock_data(&e->boottime_alarm); - - prioq_free(e->pending); - prioq_free(e->prepare); - prioq_free(e->exit); - - free(e->signal_sources); - hashmap_free(e->signal_data); - - hashmap_free(e->inotify_data); - - hashmap_free(e->child_sources); - set_free(e->post_sources); - - free(e->event_queue); - - return mfree(e); -} - -_public_ int sd_event_new(sd_event** ret) { - sd_event *e; - int r; - - assert_return(ret, -EINVAL); - - e = new(sd_event, 1); - if (!e) - return -ENOMEM; - - *e = (sd_event) { - .n_ref = 1, - .epoll_fd = -1, - .watchdog_fd = -1, - .realtime.wakeup = WAKEUP_CLOCK_DATA, - .realtime.fd = -1, - .realtime.next = USEC_INFINITY, - .boottime.wakeup = WAKEUP_CLOCK_DATA, - .boottime.fd = -1, - .boottime.next = USEC_INFINITY, - .monotonic.wakeup = WAKEUP_CLOCK_DATA, - .monotonic.fd = -1, - .monotonic.next = USEC_INFINITY, - .realtime_alarm.wakeup = WAKEUP_CLOCK_DATA, - .realtime_alarm.fd = -1, - .realtime_alarm.next = USEC_INFINITY, - .boottime_alarm.wakeup = WAKEUP_CLOCK_DATA, - .boottime_alarm.fd = -1, - .boottime_alarm.next = USEC_INFINITY, - .perturb = USEC_INFINITY, - .original_pid = getpid_cached(), - }; - - r = prioq_ensure_allocated(&e->pending, pending_prioq_compare); - if (r < 0) - goto fail; - - e->epoll_fd = epoll_create1(EPOLL_CLOEXEC); - if (e->epoll_fd < 0) { - r = -errno; - goto fail; - } - - e->epoll_fd = fd_move_above_stdio(e->epoll_fd); - - if (secure_getenv("SD_EVENT_PROFILE_DELAYS")) { - log_debug("Event loop profiling enabled. Logarithmic histogram of event loop iterations in the range 2^0 ... 2^63 us will be logged every 5s."); - e->profile_delays = true; - } - - *ret = e; - return 0; - -fail: - event_free(e); - return r; -} - -DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_event, sd_event, event_free); - -_public_ sd_event_source* sd_event_source_disable_unref(sd_event_source *s) { - if (s) - (void) sd_event_source_set_enabled(s, SD_EVENT_OFF); - return sd_event_source_unref(s); -} - -static bool event_pid_changed(sd_event *e) { - assert(e); - - /* We don't support people creating an event loop and keeping - * it around over a fork(). Let's complain. */ - - return e->original_pid != getpid_cached(); -} - -static void source_io_unregister(sd_event_source *s) { - assert(s); - assert(s->type == SOURCE_IO); - - if (event_pid_changed(s->event)) - return; - - if (!s->io.registered) - return; - - if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL) < 0) - log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll, ignoring: %m", - strna(s->description), event_source_type_to_string(s->type)); - - s->io.registered = false; -} - -static int source_io_register( - sd_event_source *s, - int enabled, - uint32_t events) { - - assert(s); - assert(s->type == SOURCE_IO); - assert(enabled != SD_EVENT_OFF); - - struct epoll_event ev = { - .events = events | (enabled == SD_EVENT_ONESHOT ? EPOLLONESHOT : 0), - .data.ptr = s, - }; - - if (epoll_ctl(s->event->epoll_fd, - s->io.registered ? EPOLL_CTL_MOD : EPOLL_CTL_ADD, - s->io.fd, &ev) < 0) - return -errno; - - s->io.registered = true; - - return 0; -} - -static void source_child_pidfd_unregister(sd_event_source *s) { - assert(s); - assert(s->type == SOURCE_CHILD); - - if (event_pid_changed(s->event)) - return; - - if (!s->child.registered) - return; - - if (EVENT_SOURCE_WATCH_PIDFD(s)) - if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->child.pidfd, NULL) < 0) - log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll, ignoring: %m", - strna(s->description), event_source_type_to_string(s->type)); - - s->child.registered = false; -} - -static int source_child_pidfd_register(sd_event_source *s, int enabled) { - assert(s); - assert(s->type == SOURCE_CHILD); - assert(enabled != SD_EVENT_OFF); - - if (EVENT_SOURCE_WATCH_PIDFD(s)) { - struct epoll_event ev = { - .events = EPOLLIN | (enabled == SD_EVENT_ONESHOT ? EPOLLONESHOT : 0), - .data.ptr = s, - }; - - if (epoll_ctl(s->event->epoll_fd, - s->child.registered ? EPOLL_CTL_MOD : EPOLL_CTL_ADD, - s->child.pidfd, &ev) < 0) - return -errno; - } - - s->child.registered = true; - return 0; -} - -static clockid_t event_source_type_to_clock(EventSourceType t) { - - switch (t) { - - case SOURCE_TIME_REALTIME: - return CLOCK_REALTIME; - - case SOURCE_TIME_BOOTTIME: - return CLOCK_BOOTTIME; - - case SOURCE_TIME_MONOTONIC: - return CLOCK_MONOTONIC; - - case SOURCE_TIME_REALTIME_ALARM: - return CLOCK_REALTIME_ALARM; - - case SOURCE_TIME_BOOTTIME_ALARM: - return CLOCK_BOOTTIME_ALARM; - - default: - return (clockid_t) -1; - } -} - -static EventSourceType clock_to_event_source_type(clockid_t clock) { - - switch (clock) { - - case CLOCK_REALTIME: - return SOURCE_TIME_REALTIME; - - case CLOCK_BOOTTIME: - return SOURCE_TIME_BOOTTIME; - - case CLOCK_MONOTONIC: - return SOURCE_TIME_MONOTONIC; - - case CLOCK_REALTIME_ALARM: - return SOURCE_TIME_REALTIME_ALARM; - - case CLOCK_BOOTTIME_ALARM: - return SOURCE_TIME_BOOTTIME_ALARM; - - default: - return _SOURCE_EVENT_SOURCE_TYPE_INVALID; - } -} - -static struct clock_data* event_get_clock_data(sd_event *e, EventSourceType t) { - assert(e); - - switch (t) { - - case SOURCE_TIME_REALTIME: - return &e->realtime; - - case SOURCE_TIME_BOOTTIME: - return &e->boottime; - - case SOURCE_TIME_MONOTONIC: - return &e->monotonic; - - case SOURCE_TIME_REALTIME_ALARM: - return &e->realtime_alarm; - - case SOURCE_TIME_BOOTTIME_ALARM: - return &e->boottime_alarm; - - default: - return NULL; - } -} - -static void event_free_signal_data(sd_event *e, struct signal_data *d) { - assert(e); - - if (!d) - return; - - hashmap_remove(e->signal_data, &d->priority); - safe_close(d->fd); - free(d); -} - -static int event_make_signal_data( - sd_event *e, - int sig, - struct signal_data **ret) { - - struct signal_data *d; - bool added = false; - sigset_t ss_copy; - int64_t priority; - int r; - - assert(e); - - if (event_pid_changed(e)) - return -ECHILD; - - if (e->signal_sources && e->signal_sources[sig]) - priority = e->signal_sources[sig]->priority; - else - priority = SD_EVENT_PRIORITY_NORMAL; - - d = hashmap_get(e->signal_data, &priority); - if (d) { - if (sigismember(&d->sigset, sig) > 0) { - if (ret) - *ret = d; - return 0; - } - } else { - r = hashmap_ensure_allocated(&e->signal_data, &uint64_hash_ops); - if (r < 0) - return r; - - d = new(struct signal_data, 1); - if (!d) - return -ENOMEM; - - *d = (struct signal_data) { - .wakeup = WAKEUP_SIGNAL_DATA, - .fd = -1, - .priority = priority, - }; - - r = hashmap_put(e->signal_data, &d->priority, d); - if (r < 0) { - free(d); - return r; - } - - added = true; - } - - ss_copy = d->sigset; - assert_se(sigaddset(&ss_copy, sig) >= 0); - - r = signalfd(d->fd, &ss_copy, SFD_NONBLOCK|SFD_CLOEXEC); - if (r < 0) { - r = -errno; - goto fail; - } - - d->sigset = ss_copy; - - if (d->fd >= 0) { - if (ret) - *ret = d; - return 0; - } - - d->fd = fd_move_above_stdio(r); - - struct epoll_event ev = { - .events = EPOLLIN, - .data.ptr = d, - }; - - if (epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, d->fd, &ev) < 0) { - r = -errno; - goto fail; - } - - if (ret) - *ret = d; - - return 0; - -fail: - if (added) - event_free_signal_data(e, d); - - return r; -} - -static void event_unmask_signal_data(sd_event *e, struct signal_data *d, int sig) { - assert(e); - assert(d); - - /* Turns off the specified signal in the signal data - * object. If the signal mask of the object becomes empty that - * way removes it. */ - - if (sigismember(&d->sigset, sig) == 0) - return; - - assert_se(sigdelset(&d->sigset, sig) >= 0); - - if (sigisemptyset(&d->sigset)) { - /* If all the mask is all-zero we can get rid of the structure */ - event_free_signal_data(e, d); - return; - } - - assert(d->fd >= 0); - - if (signalfd(d->fd, &d->sigset, SFD_NONBLOCK|SFD_CLOEXEC) < 0) - log_debug_errno(errno, "Failed to unset signal bit, ignoring: %m"); -} - -static void event_gc_signal_data(sd_event *e, const int64_t *priority, int sig) { - struct signal_data *d; - static const int64_t zero_priority = 0; - - assert(e); - - /* Rechecks if the specified signal is still something we are interested in. If not, we'll unmask it, - * and possibly drop the signalfd for it. */ - - if (sig == SIGCHLD && - e->n_online_child_sources > 0) - return; - - if (e->signal_sources && - e->signal_sources[sig] && - event_source_is_online(e->signal_sources[sig])) - return; - - /* - * The specified signal might be enabled in three different queues: - * - * 1) the one that belongs to the priority passed (if it is non-NULL) - * 2) the one that belongs to the priority of the event source of the signal (if there is one) - * 3) the 0 priority (to cover the SIGCHLD case) - * - * Hence, let's remove it from all three here. - */ - - if (priority) { - d = hashmap_get(e->signal_data, priority); - if (d) - event_unmask_signal_data(e, d, sig); - } - - if (e->signal_sources && e->signal_sources[sig]) { - d = hashmap_get(e->signal_data, &e->signal_sources[sig]->priority); - if (d) - event_unmask_signal_data(e, d, sig); - } - - d = hashmap_get(e->signal_data, &zero_priority); - if (d) - event_unmask_signal_data(e, d, sig); -} - -static void event_source_pp_prioq_reshuffle(sd_event_source *s) { - assert(s); - - /* Reshuffles the pending + prepare prioqs. Called whenever the dispatch order changes, i.e. when - * they are enabled/disabled or marked pending and such. */ - - if (s->pending) - prioq_reshuffle(s->event->pending, s, &s->pending_index); - - if (s->prepare) - prioq_reshuffle(s->event->prepare, s, &s->prepare_index); -} - -static void event_source_time_prioq_reshuffle(sd_event_source *s) { - struct clock_data *d; - - assert(s); - - /* Called whenever the event source's timer ordering properties changed, i.e. time, accuracy, - * pending, enable state. Makes sure the two prioq's are ordered properly again. */ - - if (s->ratelimited) - d = &s->event->monotonic; - else { - assert(EVENT_SOURCE_IS_TIME(s->type)); - assert_se(d = event_get_clock_data(s->event, s->type)); - } - - prioq_reshuffle(d->earliest, s, &s->earliest_index); - prioq_reshuffle(d->latest, s, &s->latest_index); - d->needs_rearm = true; -} - -static void event_source_time_prioq_remove( - sd_event_source *s, - struct clock_data *d) { - - assert(s); - assert(d); - - prioq_remove(d->earliest, s, &s->earliest_index); - prioq_remove(d->latest, s, &s->latest_index); - s->earliest_index = s->latest_index = PRIOQ_IDX_NULL; - d->needs_rearm = true; -} - -static void source_disconnect(sd_event_source *s) { - sd_event *event; - - assert(s); - - if (!s->event) - return; - - assert(s->event->n_sources > 0); - - switch (s->type) { - - case SOURCE_IO: - if (s->io.fd >= 0) - source_io_unregister(s); - - break; - - case SOURCE_TIME_REALTIME: - case SOURCE_TIME_BOOTTIME: - case SOURCE_TIME_MONOTONIC: - case SOURCE_TIME_REALTIME_ALARM: - case SOURCE_TIME_BOOTTIME_ALARM: - /* Only remove this event source from the time event source here if it is not ratelimited. If - * it is ratelimited, we'll remove it below, separately. Why? Because the clock used might - * differ: ratelimiting always uses CLOCK_MONOTONIC, but timer events might use any clock */ - - if (!s->ratelimited) { - struct clock_data *d; - assert_se(d = event_get_clock_data(s->event, s->type)); - event_source_time_prioq_remove(s, d); - } - - break; - - case SOURCE_SIGNAL: - if (s->signal.sig > 0) { - - if (s->event->signal_sources) - s->event->signal_sources[s->signal.sig] = NULL; - - event_gc_signal_data(s->event, &s->priority, s->signal.sig); - } - - break; - - case SOURCE_CHILD: - if (s->child.pid > 0) { - if (event_source_is_online(s)) { - assert(s->event->n_online_child_sources > 0); - s->event->n_online_child_sources--; - } - - (void) hashmap_remove(s->event->child_sources, PID_TO_PTR(s->child.pid)); - } - - if (EVENT_SOURCE_WATCH_PIDFD(s)) - source_child_pidfd_unregister(s); - else - event_gc_signal_data(s->event, &s->priority, SIGCHLD); - - break; - - case SOURCE_DEFER: - /* nothing */ - break; - - case SOURCE_POST: - set_remove(s->event->post_sources, s); - break; - - case SOURCE_EXIT: - prioq_remove(s->event->exit, s, &s->exit.prioq_index); - break; - - case SOURCE_INOTIFY: { - struct inode_data *inode_data; - - inode_data = s->inotify.inode_data; - if (inode_data) { - struct inotify_data *inotify_data; - assert_se(inotify_data = inode_data->inotify_data); - - /* Detach this event source from the inode object */ - LIST_REMOVE(inotify.by_inode_data, inode_data->event_sources, s); - s->inotify.inode_data = NULL; - - if (s->pending) { - assert(inotify_data->n_pending > 0); - inotify_data->n_pending--; - } - - /* Note that we don't reduce the inotify mask for the watch descriptor here if the inode is - * continued to being watched. That's because inotify doesn't really have an API for that: we - * can only change watch masks with access to the original inode either by fd or by path. But - * paths aren't stable, and keeping an O_PATH fd open all the time would mean wasting an fd - * continuously and keeping the mount busy which we can't really do. We could reconstruct the - * original inode from /proc/self/fdinfo/$INOTIFY_FD (as all watch descriptors are listed - * there), but given the need for open_by_handle_at() which is privileged and not universally - * available this would be quite an incomplete solution. Hence we go the other way, leave the - * mask set, even if it is not minimized now, and ignore all events we aren't interested in - * anymore after reception. Yes, this sucks, but … Linux … */ - - /* Maybe release the inode data (and its inotify) */ - event_gc_inode_data(s->event, inode_data); - } - - break; - } - - default: - assert_not_reached("Wut? I shouldn't exist."); - } - - if (s->pending) - prioq_remove(s->event->pending, s, &s->pending_index); - - if (s->prepare) - prioq_remove(s->event->prepare, s, &s->prepare_index); - - if (s->ratelimited) - event_source_time_prioq_remove(s, &s->event->monotonic); - - event = TAKE_PTR(s->event); - LIST_REMOVE(sources, event->sources, s); - event->n_sources--; - - /* Note that we don't invalidate the type here, since we still need it in order to close the fd or - * pidfd associated with this event source, which we'll do only on source_free(). */ - - if (!s->floating) - sd_event_unref(event); -} - -static void source_free(sd_event_source *s) { - assert(s); - - source_disconnect(s); - - if (s->type == SOURCE_IO && s->io.owned) - s->io.fd = safe_close(s->io.fd); - - if (s->type == SOURCE_CHILD) { - /* Eventually the kernel will do this automatically for us, but for now let's emulate this (unreliably) in userspace. */ - - if (s->child.process_owned) { - - if (!s->child.exited) { - bool sent = false; - - if (s->child.pidfd >= 0) { - if (pidfd_send_signal(s->child.pidfd, SIGKILL, NULL, 0) < 0) { - if (errno == ESRCH) /* Already dead */ - sent = true; - else if (!ERRNO_IS_NOT_SUPPORTED(errno)) - log_debug_errno(errno, "Failed to kill process " PID_FMT " via pidfd_send_signal(), re-trying via kill(): %m", - s->child.pid); - } else - sent = true; - } - - if (!sent) - if (kill(s->child.pid, SIGKILL) < 0) - if (errno != ESRCH) /* Already dead */ - log_debug_errno(errno, "Failed to kill process " PID_FMT " via kill(), ignoring: %m", - s->child.pid); - } - - if (!s->child.waited) { - siginfo_t si = {}; - - /* Reap the child if we can */ - (void) waitid(P_PID, s->child.pid, &si, WEXITED); - } - } - - if (s->child.pidfd_owned) - s->child.pidfd = safe_close(s->child.pidfd); - } - - if (s->destroy_callback) - s->destroy_callback(s->userdata); - - free(s->description); - free(s); -} -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event_source*, source_free); - -static int source_set_pending(sd_event_source *s, bool b) { - int r; - - assert(s); - assert(s->type != SOURCE_EXIT); - - if (s->pending == b) - return 0; - - s->pending = b; - - if (b) { - s->pending_iteration = s->event->iteration; - - r = prioq_put(s->event->pending, s, &s->pending_index); - if (r < 0) { - s->pending = false; - return r; - } - } else - assert_se(prioq_remove(s->event->pending, s, &s->pending_index)); - - if (EVENT_SOURCE_IS_TIME(s->type)) - event_source_time_prioq_reshuffle(s); - - if (s->type == SOURCE_SIGNAL && !b) { - struct signal_data *d; - - d = hashmap_get(s->event->signal_data, &s->priority); - if (d && d->current == s) - d->current = NULL; - } - - if (s->type == SOURCE_INOTIFY) { - - assert(s->inotify.inode_data); - assert(s->inotify.inode_data->inotify_data); - - if (b) - s->inotify.inode_data->inotify_data->n_pending ++; - else { - assert(s->inotify.inode_data->inotify_data->n_pending > 0); - s->inotify.inode_data->inotify_data->n_pending --; - } - } - - return 0; -} - -static sd_event_source *source_new(sd_event *e, bool floating, EventSourceType type) { - sd_event_source *s; - - assert(e); - - s = new(sd_event_source, 1); - if (!s) - return NULL; - - *s = (struct sd_event_source) { - .n_ref = 1, - .event = e, - .floating = floating, - .type = type, - .pending_index = PRIOQ_IDX_NULL, - .prepare_index = PRIOQ_IDX_NULL, - }; - - if (!floating) - sd_event_ref(e); - - LIST_PREPEND(sources, e->sources, s); - e->n_sources++; - - return s; -} - -static int io_exit_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - assert(s); - - return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata)); -} - -_public_ int sd_event_add_io( - sd_event *e, - sd_event_source **ret, - int fd, - uint32_t events, - sd_event_io_handler_t callback, - void *userdata) { - - _cleanup_(source_freep) sd_event_source *s = NULL; - int r; - - assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); - assert_return(fd >= 0, -EBADF); - assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET)), -EINVAL); - assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(e), -ECHILD); - - if (!callback) - callback = io_exit_callback; - - s = source_new(e, !ret, SOURCE_IO); - if (!s) - return -ENOMEM; - - s->wakeup = WAKEUP_EVENT_SOURCE; - s->io.fd = fd; - s->io.events = events; - s->io.callback = callback; - s->userdata = userdata; - s->enabled = SD_EVENT_ON; - - r = source_io_register(s, s->enabled, events); - if (r < 0) - return r; - - if (ret) - *ret = s; - TAKE_PTR(s); - - return 0; -} - -static void initialize_perturb(sd_event *e) { - sd_id128_t bootid = {}; - - /* When we sleep for longer, we try to realign the wakeup to - the same time within each minute/second/250ms, so that - events all across the system can be coalesced into a single - CPU wakeup. However, let's take some system-specific - randomness for this value, so that in a network of systems - with synced clocks timer events are distributed a - bit. Here, we calculate a perturbation usec offset from the - boot ID. */ - - if (_likely_(e->perturb != USEC_INFINITY)) - return; - - if (sd_id128_get_boot(&bootid) >= 0) - e->perturb = (bootid.qwords[0] ^ bootid.qwords[1]) % USEC_PER_MINUTE; -} - -static int event_setup_timer_fd( - sd_event *e, - struct clock_data *d, - clockid_t clock) { - - assert(e); - assert(d); - - if (_likely_(d->fd >= 0)) - return 0; - - _cleanup_close_ int fd = -1; - - fd = timerfd_create(clock, TFD_NONBLOCK|TFD_CLOEXEC); - if (fd < 0) - return -errno; - - fd = fd_move_above_stdio(fd); - - struct epoll_event ev = { - .events = EPOLLIN, - .data.ptr = d, - }; - - if (epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) - return -errno; - - d->fd = TAKE_FD(fd); - return 0; -} - -static int time_exit_callback(sd_event_source *s, uint64_t usec, void *userdata) { - assert(s); - - return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata)); -} - -static int setup_clock_data(sd_event *e, struct clock_data *d, clockid_t clock) { - int r; - - assert(d); - - if (d->fd < 0) { - r = event_setup_timer_fd(e, d, clock); - if (r < 0) - return r; - } - - r = prioq_ensure_allocated(&d->earliest, earliest_time_prioq_compare); - if (r < 0) - return r; - - r = prioq_ensure_allocated(&d->latest, latest_time_prioq_compare); - if (r < 0) - return r; - - return 0; -} - -static int event_source_time_prioq_put( - sd_event_source *s, - struct clock_data *d) { - - int r; - - assert(s); - assert(d); - - r = prioq_put(d->earliest, s, &s->earliest_index); - if (r < 0) - return r; - - r = prioq_put(d->latest, s, &s->latest_index); - if (r < 0) { - assert_se(prioq_remove(d->earliest, s, &s->earliest_index) > 0); - s->earliest_index = PRIOQ_IDX_NULL; - return r; - } - - d->needs_rearm = true; - return 0; -} - -_public_ int sd_event_add_time( - sd_event *e, - sd_event_source **ret, - clockid_t clock, - uint64_t usec, - uint64_t accuracy, - sd_event_time_handler_t callback, - void *userdata) { - - EventSourceType type; - _cleanup_(source_freep) sd_event_source *s = NULL; - struct clock_data *d; - int r; - - assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); - assert_return(accuracy != (uint64_t) -1, -EINVAL); - assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(e), -ECHILD); - - if (!clock_supported(clock)) /* Checks whether the kernel supports the clock */ - return -EOPNOTSUPP; - - type = clock_to_event_source_type(clock); /* checks whether sd-event supports this clock */ - if (type < 0) - return -EOPNOTSUPP; - - if (!callback) - callback = time_exit_callback; - - assert_se(d = event_get_clock_data(e, type)); - - r = setup_clock_data(e, d, clock); - if (r < 0) - return r; - - s = source_new(e, !ret, type); - if (!s) - return -ENOMEM; - - s->time.next = usec; - s->time.accuracy = accuracy == 0 ? DEFAULT_ACCURACY_USEC : accuracy; - s->time.callback = callback; - s->earliest_index = s->latest_index = PRIOQ_IDX_NULL; - s->userdata = userdata; - s->enabled = SD_EVENT_ONESHOT; - - r = event_source_time_prioq_put(s, d); - if (r < 0) - return r; - - if (ret) - *ret = s; - TAKE_PTR(s); - - return 0; -} - -#if 0 /* NM_IGNORED */ -_public_ int sd_event_add_time_relative( - sd_event *e, - sd_event_source **ret, - clockid_t clock, - uint64_t usec, - uint64_t accuracy, - sd_event_time_handler_t callback, - void *userdata) { - - usec_t t; - int r; - - /* Same as sd_event_add_time() but operates relative to the event loop's current point in time, and - * checks for overflow. */ - - r = sd_event_now(e, clock, &t); - if (r < 0) - return r; - - if (usec >= USEC_INFINITY - t) - return -EOVERFLOW; - - return sd_event_add_time(e, ret, clock, t + usec, accuracy, callback, userdata); -} - -static int signal_exit_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { - assert(s); - - return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata)); -} - -_public_ int sd_event_add_signal( - sd_event *e, - sd_event_source **ret, - int sig, - sd_event_signal_handler_t callback, - void *userdata) { - - _cleanup_(source_freep) sd_event_source *s = NULL; - struct signal_data *d; - int r; - - assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); - assert_return(SIGNAL_VALID(sig), -EINVAL); - assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(e), -ECHILD); - - if (!callback) - callback = signal_exit_callback; - - r = signal_is_blocked(sig); - if (r < 0) - return r; - if (r == 0) - return -EBUSY; - - if (!e->signal_sources) { - e->signal_sources = new0(sd_event_source*, _NSIG); - if (!e->signal_sources) - return -ENOMEM; - } else if (e->signal_sources[sig]) - return -EBUSY; - - s = source_new(e, !ret, SOURCE_SIGNAL); - if (!s) - return -ENOMEM; - - s->signal.sig = sig; - s->signal.callback = callback; - s->userdata = userdata; - s->enabled = SD_EVENT_ON; - - e->signal_sources[sig] = s; - - r = event_make_signal_data(e, sig, &d); - if (r < 0) - return r; - - /* Use the signal name as description for the event source by default */ - (void) sd_event_source_set_description(s, signal_to_string(sig)); - - if (ret) - *ret = s; - TAKE_PTR(s); - - return 0; -} - -static int child_exit_callback(sd_event_source *s, const siginfo_t *si, void *userdata) { - assert(s); - - return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata)); -} - -static bool shall_use_pidfd(void) { - /* Mostly relevant for debugging, i.e. this is used in test-event.c to test the event loop once with and once without pidfd */ - return getenv_bool_secure("SYSTEMD_PIDFD") != 0; -} - -_public_ int sd_event_add_child( - sd_event *e, - sd_event_source **ret, - pid_t pid, - int options, - sd_event_child_handler_t callback, - void *userdata) { - - _cleanup_(source_freep) sd_event_source *s = NULL; - int r; - - assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); - assert_return(pid > 1, -EINVAL); - assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED)), -EINVAL); - assert_return(options != 0, -EINVAL); - assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(e), -ECHILD); - - if (!callback) - callback = child_exit_callback; - - if (e->n_online_child_sources == 0) { - /* Caller must block SIGCHLD before using us to watch children, even if pidfd is available, - * for compatibility with pre-pidfd and because we don't want the reap the child processes - * ourselves, i.e. call waitid(), and don't want Linux' default internal logic for that to - * take effect. - * - * (As an optimization we only do this check on the first child event source created.) */ - r = signal_is_blocked(SIGCHLD); - if (r < 0) - return r; - if (r == 0) - return -EBUSY; - } - - r = hashmap_ensure_allocated(&e->child_sources, NULL); - if (r < 0) - return r; - - if (hashmap_contains(e->child_sources, PID_TO_PTR(pid))) - return -EBUSY; - - s = source_new(e, !ret, SOURCE_CHILD); - if (!s) - return -ENOMEM; - - s->wakeup = WAKEUP_EVENT_SOURCE; - s->child.pid = pid; - s->child.options = options; - s->child.callback = callback; - s->userdata = userdata; - s->enabled = SD_EVENT_ONESHOT; - - /* We always take a pidfd here if we can, even if we wait for anything else than WEXITED, so that we - * pin the PID, and make regular waitid() handling race-free. */ - - if (shall_use_pidfd()) { - s->child.pidfd = pidfd_open(s->child.pid, 0); - if (s->child.pidfd < 0) { - /* Propagate errors unless the syscall is not supported or blocked */ - if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno)) - return -errno; - } else - s->child.pidfd_owned = true; /* If we allocate the pidfd we own it by default */ - } else - s->child.pidfd = -1; - - r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s); - if (r < 0) - return r; - - if (EVENT_SOURCE_WATCH_PIDFD(s)) { - /* We have a pidfd and we only want to watch for exit */ - r = source_child_pidfd_register(s, s->enabled); - if (r < 0) - return r; - - } else { - /* We have no pidfd or we shall wait for some other event than WEXITED */ - r = event_make_signal_data(e, SIGCHLD, NULL); - if (r < 0) - return r; - - e->need_process_child = true; - } - - e->n_online_child_sources++; - - if (ret) - *ret = s; - TAKE_PTR(s); - return 0; -} - -_public_ int sd_event_add_child_pidfd( - sd_event *e, - sd_event_source **ret, - int pidfd, - int options, - sd_event_child_handler_t callback, - void *userdata) { - - - _cleanup_(source_freep) sd_event_source *s = NULL; - pid_t pid; - int r; - - assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); - assert_return(pidfd >= 0, -EBADF); - assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED)), -EINVAL); - assert_return(options != 0, -EINVAL); - assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(e), -ECHILD); - - if (!callback) - callback = child_exit_callback; - - if (e->n_online_child_sources == 0) { - r = signal_is_blocked(SIGCHLD); - if (r < 0) - return r; - if (r == 0) - return -EBUSY; - } - - r = hashmap_ensure_allocated(&e->child_sources, NULL); - if (r < 0) - return r; - - r = pidfd_get_pid(pidfd, &pid); - if (r < 0) - return r; - - if (hashmap_contains(e->child_sources, PID_TO_PTR(pid))) - return -EBUSY; - - s = source_new(e, !ret, SOURCE_CHILD); - if (!s) - return -ENOMEM; - - s->wakeup = WAKEUP_EVENT_SOURCE; - s->child.pidfd = pidfd; - s->child.pid = pid; - s->child.options = options; - s->child.callback = callback; - s->child.pidfd_owned = false; /* If we got the pidfd passed in we don't own it by default (similar to the IO fd case) */ - s->userdata = userdata; - s->enabled = SD_EVENT_ONESHOT; - - r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s); - if (r < 0) - return r; - - if (EVENT_SOURCE_WATCH_PIDFD(s)) { - /* We only want to watch for WEXITED */ - r = source_child_pidfd_register(s, s->enabled); - if (r < 0) - return r; - } else { - /* We shall wait for some other event than WEXITED */ - r = event_make_signal_data(e, SIGCHLD, NULL); - if (r < 0) - return r; - - e->need_process_child = true; - } - - e->n_online_child_sources++; - - if (ret) - *ret = s; - TAKE_PTR(s); - return 0; -} -#endif /* NM_IGNORED */ - -static int generic_exit_callback(sd_event_source *s, void *userdata) { - assert(s); - - return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata)); -} - -_public_ int sd_event_add_defer( - sd_event *e, - sd_event_source **ret, - sd_event_handler_t callback, - void *userdata) { - - _cleanup_(source_freep) sd_event_source *s = NULL; - int r; - - assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); - assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(e), -ECHILD); - - if (!callback) - callback = generic_exit_callback; - - s = source_new(e, !ret, SOURCE_DEFER); - if (!s) - return -ENOMEM; - - s->defer.callback = callback; - s->userdata = userdata; - s->enabled = SD_EVENT_ONESHOT; - - r = source_set_pending(s, true); - if (r < 0) - return r; - - if (ret) - *ret = s; - TAKE_PTR(s); - - return 0; -} - -_public_ int sd_event_add_post( - sd_event *e, - sd_event_source **ret, - sd_event_handler_t callback, - void *userdata) { - - _cleanup_(source_freep) sd_event_source *s = NULL; - int r; - - assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); - assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(e), -ECHILD); - - if (!callback) - callback = generic_exit_callback; - - s = source_new(e, !ret, SOURCE_POST); - if (!s) - return -ENOMEM; - - s->post.callback = callback; - s->userdata = userdata; - s->enabled = SD_EVENT_ON; - - r = set_ensure_put(&e->post_sources, NULL, s); - if (r < 0) - return r; - assert(r > 0); - - if (ret) - *ret = s; - TAKE_PTR(s); - - return 0; -} - -_public_ int sd_event_add_exit( - sd_event *e, - sd_event_source **ret, - sd_event_handler_t callback, - void *userdata) { - - _cleanup_(source_freep) sd_event_source *s = NULL; - int r; - - assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); - assert_return(callback, -EINVAL); - assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(e), -ECHILD); - - r = prioq_ensure_allocated(&e->exit, exit_prioq_compare); - if (r < 0) - return r; - - s = source_new(e, !ret, SOURCE_EXIT); - if (!s) - return -ENOMEM; - - s->exit.callback = callback; - s->userdata = userdata; - s->exit.prioq_index = PRIOQ_IDX_NULL; - s->enabled = SD_EVENT_ONESHOT; - - r = prioq_put(s->event->exit, s, &s->exit.prioq_index); - if (r < 0) - return r; - - if (ret) - *ret = s; - TAKE_PTR(s); - - return 0; -} - -static void event_free_inotify_data(sd_event *e, struct inotify_data *d) { - assert(e); - - if (!d) - return; - - assert(hashmap_isempty(d->inodes)); - assert(hashmap_isempty(d->wd)); - - if (d->buffer_filled > 0) - LIST_REMOVE(buffered, e->inotify_data_buffered, d); - - hashmap_free(d->inodes); - hashmap_free(d->wd); - - assert_se(hashmap_remove(e->inotify_data, &d->priority) == d); - - if (d->fd >= 0) { - if (epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, d->fd, NULL) < 0) - log_debug_errno(errno, "Failed to remove inotify fd from epoll, ignoring: %m"); - - safe_close(d->fd); - } - free(d); -} - -static int event_make_inotify_data( - sd_event *e, - int64_t priority, - struct inotify_data **ret) { - - _cleanup_close_ int fd = -1; - struct inotify_data *d; - int r; - - assert(e); - - d = hashmap_get(e->inotify_data, &priority); - if (d) { - if (ret) - *ret = d; - return 0; - } - - fd = inotify_init1(IN_NONBLOCK|O_CLOEXEC); - if (fd < 0) - return -errno; - - fd = fd_move_above_stdio(fd); - - r = hashmap_ensure_allocated(&e->inotify_data, &uint64_hash_ops); - if (r < 0) - return r; - - d = new(struct inotify_data, 1); - if (!d) - return -ENOMEM; - - *d = (struct inotify_data) { - .wakeup = WAKEUP_INOTIFY_DATA, - .fd = TAKE_FD(fd), - .priority = priority, - }; - - r = hashmap_put(e->inotify_data, &d->priority, d); - if (r < 0) { - d->fd = safe_close(d->fd); - free(d); - return r; - } - - struct epoll_event ev = { - .events = EPOLLIN, - .data.ptr = d, - }; - - if (epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, d->fd, &ev) < 0) { - r = -errno; - d->fd = safe_close(d->fd); /* let's close this ourselves, as event_free_inotify_data() would otherwise - * remove the fd from the epoll first, which we don't want as we couldn't - * add it in the first place. */ - event_free_inotify_data(e, d); - return r; - } - - if (ret) - *ret = d; - - return 1; -} - -static int inode_data_compare(const struct inode_data *x, const struct inode_data *y) { - int r; - - assert(x); - assert(y); - - r = CMP(x->dev, y->dev); - if (r != 0) - return r; - - return CMP(x->ino, y->ino); -} - -static void inode_data_hash_func(const struct inode_data *d, struct siphash *state) { - assert(d); - - siphash24_compress(&d->dev, sizeof(d->dev), state); - siphash24_compress(&d->ino, sizeof(d->ino), state); -} - -DEFINE_PRIVATE_HASH_OPS(inode_data_hash_ops, struct inode_data, inode_data_hash_func, inode_data_compare); - -static void event_free_inode_data( - sd_event *e, - struct inode_data *d) { - - assert(e); - - if (!d) - return; - - assert(!d->event_sources); - - if (d->fd >= 0) { - LIST_REMOVE(to_close, e->inode_data_to_close, d); - safe_close(d->fd); - } - - if (d->inotify_data) { - - if (d->wd >= 0) { - if (d->inotify_data->fd >= 0) { - /* So here's a problem. At the time this runs the watch descriptor might already be - * invalidated, because an IN_IGNORED event might be queued right the moment we enter - * the syscall. Hence, whenever we get EINVAL, ignore it entirely, since it's a very - * likely case to happen. */ - - if (inotify_rm_watch(d->inotify_data->fd, d->wd) < 0 && errno != EINVAL) - log_debug_errno(errno, "Failed to remove watch descriptor %i from inotify, ignoring: %m", d->wd); - } - - assert_se(hashmap_remove(d->inotify_data->wd, INT_TO_PTR(d->wd)) == d); - } - - assert_se(hashmap_remove(d->inotify_data->inodes, d) == d); - } - - free(d); -} - -static void event_gc_inode_data( - sd_event *e, - struct inode_data *d) { - - struct inotify_data *inotify_data; - - assert(e); - - if (!d) - return; - - if (d->event_sources) - return; - - inotify_data = d->inotify_data; - event_free_inode_data(e, d); - - if (inotify_data && hashmap_isempty(inotify_data->inodes)) - event_free_inotify_data(e, inotify_data); -} - -static int event_make_inode_data( - sd_event *e, - struct inotify_data *inotify_data, - dev_t dev, - ino_t ino, - struct inode_data **ret) { - - struct inode_data *d, key; - int r; - - assert(e); - assert(inotify_data); - - key = (struct inode_data) { - .ino = ino, - .dev = dev, - }; - - d = hashmap_get(inotify_data->inodes, &key); - if (d) { - if (ret) - *ret = d; - - return 0; - } - - r = hashmap_ensure_allocated(&inotify_data->inodes, &inode_data_hash_ops); - if (r < 0) - return r; - - d = new(struct inode_data, 1); - if (!d) - return -ENOMEM; - - *d = (struct inode_data) { - .dev = dev, - .ino = ino, - .wd = -1, - .fd = -1, - .inotify_data = inotify_data, - }; - - r = hashmap_put(inotify_data->inodes, d, d); - if (r < 0) { - free(d); - return r; - } - - if (ret) - *ret = d; - - return 1; -} - -static uint32_t inode_data_determine_mask(struct inode_data *d) { - bool excl_unlink = true; - uint32_t combined = 0; - sd_event_source *s; - - assert(d); - - /* Combines the watch masks of all event sources watching this inode. We generally just OR them together, but - * the IN_EXCL_UNLINK flag is ANDed instead. - * - * Note that we add all sources to the mask here, regardless whether enabled, disabled or oneshot. That's - * because we cannot change the mask anymore after the event source was created once, since the kernel has no - * API for that. Hence we need to subscribe to the maximum mask we ever might be interested in, and suppress - * events we don't care for client-side. */ - - LIST_FOREACH(inotify.by_inode_data, s, d->event_sources) { - - if ((s->inotify.mask & IN_EXCL_UNLINK) == 0) - excl_unlink = false; - - combined |= s->inotify.mask; - } - - return (combined & ~(IN_ONESHOT|IN_DONT_FOLLOW|IN_ONLYDIR|IN_EXCL_UNLINK)) | (excl_unlink ? IN_EXCL_UNLINK : 0); -} - -static int inode_data_realize_watch(sd_event *e, struct inode_data *d) { - uint32_t combined_mask; - int wd, r; - - assert(d); - assert(d->fd >= 0); - - combined_mask = inode_data_determine_mask(d); - - if (d->wd >= 0 && combined_mask == d->combined_mask) - return 0; - - r = hashmap_ensure_allocated(&d->inotify_data->wd, NULL); - if (r < 0) - return r; - - wd = inotify_add_watch_fd(d->inotify_data->fd, d->fd, combined_mask); - if (wd < 0) - return -errno; - - if (d->wd < 0) { - r = hashmap_put(d->inotify_data->wd, INT_TO_PTR(wd), d); - if (r < 0) { - (void) inotify_rm_watch(d->inotify_data->fd, wd); - return r; - } - - d->wd = wd; - - } else if (d->wd != wd) { - - log_debug("Weird, the watch descriptor we already knew for this inode changed?"); - (void) inotify_rm_watch(d->fd, wd); - return -EINVAL; - } - - d->combined_mask = combined_mask; - return 1; -} - -static int inotify_exit_callback(sd_event_source *s, const struct inotify_event *event, void *userdata) { - assert(s); - - return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata)); -} - -_public_ int sd_event_add_inotify( - sd_event *e, - sd_event_source **ret, - const char *path, - uint32_t mask, - sd_event_inotify_handler_t callback, - void *userdata) { - - struct inotify_data *inotify_data = NULL; - struct inode_data *inode_data = NULL; - _cleanup_close_ int fd = -1; - _cleanup_(source_freep) sd_event_source *s = NULL; - struct stat st; - int r; - - assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); - assert_return(path, -EINVAL); - assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(e), -ECHILD); - - if (!callback) - callback = inotify_exit_callback; - - /* Refuse IN_MASK_ADD since we coalesce watches on the same inode, and hence really don't want to merge - * masks. Or in other words, this whole code exists only to manage IN_MASK_ADD type operations for you, hence - * the user can't use them for us. */ - if (mask & IN_MASK_ADD) - return -EINVAL; - - fd = open(path, O_PATH|O_CLOEXEC| - (mask & IN_ONLYDIR ? O_DIRECTORY : 0)| - (mask & IN_DONT_FOLLOW ? O_NOFOLLOW : 0)); - if (fd < 0) - return -errno; - - if (fstat(fd, &st) < 0) - return -errno; - - s = source_new(e, !ret, SOURCE_INOTIFY); - if (!s) - return -ENOMEM; - - s->enabled = mask & IN_ONESHOT ? SD_EVENT_ONESHOT : SD_EVENT_ON; - s->inotify.mask = mask; - s->inotify.callback = callback; - s->userdata = userdata; - - /* Allocate an inotify object for this priority, and an inode object within it */ - r = event_make_inotify_data(e, SD_EVENT_PRIORITY_NORMAL, &inotify_data); - if (r < 0) - return r; - - r = event_make_inode_data(e, inotify_data, st.st_dev, st.st_ino, &inode_data); - if (r < 0) { - event_free_inotify_data(e, inotify_data); - return r; - } - - /* Keep the O_PATH fd around until the first iteration of the loop, so that we can still change the priority of - * the event source, until then, for which we need the original inode. */ - if (inode_data->fd < 0) { - inode_data->fd = TAKE_FD(fd); - LIST_PREPEND(to_close, e->inode_data_to_close, inode_data); - } - - /* Link our event source to the inode data object */ - LIST_PREPEND(inotify.by_inode_data, inode_data->event_sources, s); - s->inotify.inode_data = inode_data; - - /* Actually realize the watch now */ - r = inode_data_realize_watch(e, inode_data); - if (r < 0) - return r; - - (void) sd_event_source_set_description(s, path); - - if (ret) - *ret = s; - TAKE_PTR(s); - - return 0; -} - -static sd_event_source* event_source_free(sd_event_source *s) { - if (!s) - return NULL; - - /* Here's a special hack: when we are called from a - * dispatch handler we won't free the event source - * immediately, but we will detach the fd from the - * epoll. This way it is safe for the caller to unref - * the event source and immediately close the fd, but - * we still retain a valid event source object after - * the callback. */ - - if (s->dispatching) { - if (s->type == SOURCE_IO) - source_io_unregister(s); - - source_disconnect(s); - } else - source_free(s); - - return NULL; -} - -DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_event_source, sd_event_source, event_source_free); - -_public_ int sd_event_source_set_description(sd_event_source *s, const char *description) { - assert_return(s, -EINVAL); - assert_return(!event_pid_changed(s->event), -ECHILD); - - return free_and_strdup(&s->description, description); -} - -_public_ int sd_event_source_get_description(sd_event_source *s, const char **description) { - assert_return(s, -EINVAL); - assert_return(description, -EINVAL); - assert_return(!event_pid_changed(s->event), -ECHILD); - - if (!s->description) - return -ENXIO; - - *description = s->description; - return 0; -} - -_public_ sd_event *sd_event_source_get_event(sd_event_source *s) { - assert_return(s, NULL); - - return s->event; -} - -_public_ int sd_event_source_get_pending(sd_event_source *s) { - assert_return(s, -EINVAL); - assert_return(s->type != SOURCE_EXIT, -EDOM); - assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(s->event), -ECHILD); - - return s->pending; -} - -_public_ int sd_event_source_get_io_fd(sd_event_source *s) { - assert_return(s, -EINVAL); - assert_return(s->type == SOURCE_IO, -EDOM); - assert_return(!event_pid_changed(s->event), -ECHILD); - - return s->io.fd; -} - -_public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) { - int r; - - assert_return(s, -EINVAL); - assert_return(fd >= 0, -EBADF); - assert_return(s->type == SOURCE_IO, -EDOM); - assert_return(!event_pid_changed(s->event), -ECHILD); - - if (s->io.fd == fd) - return 0; - - if (event_source_is_offline(s)) { - s->io.fd = fd; - s->io.registered = false; - } else { - int saved_fd; - - saved_fd = s->io.fd; - assert(s->io.registered); - - s->io.fd = fd; - s->io.registered = false; - - r = source_io_register(s, s->enabled, s->io.events); - if (r < 0) { - s->io.fd = saved_fd; - s->io.registered = true; - return r; - } - - (void) epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, saved_fd, NULL); - } - - return 0; -} - -_public_ int sd_event_source_get_io_fd_own(sd_event_source *s) { - assert_return(s, -EINVAL); - assert_return(s->type == SOURCE_IO, -EDOM); - - return s->io.owned; -} - -_public_ int sd_event_source_set_io_fd_own(sd_event_source *s, int own) { - assert_return(s, -EINVAL); - assert_return(s->type == SOURCE_IO, -EDOM); - - s->io.owned = own; - return 0; -} - -_public_ int sd_event_source_get_io_events(sd_event_source *s, uint32_t* events) { - assert_return(s, -EINVAL); - assert_return(events, -EINVAL); - assert_return(s->type == SOURCE_IO, -EDOM); - assert_return(!event_pid_changed(s->event), -ECHILD); - - *events = s->io.events; - return 0; -} - -_public_ int sd_event_source_set_io_events(sd_event_source *s, uint32_t events) { - int r; - - assert_return(s, -EINVAL); - assert_return(s->type == SOURCE_IO, -EDOM); - assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET)), -EINVAL); - assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(s->event), -ECHILD); - - /* edge-triggered updates are never skipped, so we can reset edges */ - if (s->io.events == events && !(events & EPOLLET)) - return 0; - - r = source_set_pending(s, false); - if (r < 0) - return r; - - if (event_source_is_online(s)) { - r = source_io_register(s, s->enabled, events); - if (r < 0) - return r; - } - - s->io.events = events; - - return 0; -} - -_public_ int sd_event_source_get_io_revents(sd_event_source *s, uint32_t* revents) { - assert_return(s, -EINVAL); - assert_return(revents, -EINVAL); - assert_return(s->type == SOURCE_IO, -EDOM); - assert_return(s->pending, -ENODATA); - assert_return(!event_pid_changed(s->event), -ECHILD); - - *revents = s->io.revents; - return 0; -} - -_public_ int sd_event_source_get_signal(sd_event_source *s) { - assert_return(s, -EINVAL); - assert_return(s->type == SOURCE_SIGNAL, -EDOM); - assert_return(!event_pid_changed(s->event), -ECHILD); - - return s->signal.sig; -} - -_public_ int sd_event_source_get_priority(sd_event_source *s, int64_t *priority) { - assert_return(s, -EINVAL); - assert_return(!event_pid_changed(s->event), -ECHILD); - - *priority = s->priority; - return 0; -} - -_public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority) { - bool rm_inotify = false, rm_inode = false; - struct inotify_data *new_inotify_data = NULL; - struct inode_data *new_inode_data = NULL; - int r; - - assert_return(s, -EINVAL); - assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(s->event), -ECHILD); - - if (s->priority == priority) - return 0; - - if (s->type == SOURCE_INOTIFY) { - struct inode_data *old_inode_data; - - assert(s->inotify.inode_data); - old_inode_data = s->inotify.inode_data; - - /* We need the original fd to change the priority. If we don't have it we can't change the priority, - * anymore. Note that we close any fds when entering the next event loop iteration, i.e. for inotify - * events we allow priority changes only until the first following iteration. */ - if (old_inode_data->fd < 0) - return -EOPNOTSUPP; - - r = event_make_inotify_data(s->event, priority, &new_inotify_data); - if (r < 0) - return r; - rm_inotify = r > 0; - - r = event_make_inode_data(s->event, new_inotify_data, old_inode_data->dev, old_inode_data->ino, &new_inode_data); - if (r < 0) - goto fail; - rm_inode = r > 0; - - if (new_inode_data->fd < 0) { - /* Duplicate the fd for the new inode object if we don't have any yet */ - new_inode_data->fd = fcntl(old_inode_data->fd, F_DUPFD_CLOEXEC, 3); - if (new_inode_data->fd < 0) { - r = -errno; - goto fail; - } - - LIST_PREPEND(to_close, s->event->inode_data_to_close, new_inode_data); - } - - /* Move the event source to the new inode data structure */ - LIST_REMOVE(inotify.by_inode_data, old_inode_data->event_sources, s); - LIST_PREPEND(inotify.by_inode_data, new_inode_data->event_sources, s); - s->inotify.inode_data = new_inode_data; - - /* Now create the new watch */ - r = inode_data_realize_watch(s->event, new_inode_data); - if (r < 0) { - /* Move it back */ - LIST_REMOVE(inotify.by_inode_data, new_inode_data->event_sources, s); - LIST_PREPEND(inotify.by_inode_data, old_inode_data->event_sources, s); - s->inotify.inode_data = old_inode_data; - goto fail; - } - - s->priority = priority; - - event_gc_inode_data(s->event, old_inode_data); - - } else if (s->type == SOURCE_SIGNAL && event_source_is_online(s)) { - struct signal_data *old, *d; - - /* Move us from the signalfd belonging to the old - * priority to the signalfd of the new priority */ - - assert_se(old = hashmap_get(s->event->signal_data, &s->priority)); - - s->priority = priority; - - r = event_make_signal_data(s->event, s->signal.sig, &d); - if (r < 0) { - s->priority = old->priority; - return r; - } - - event_unmask_signal_data(s->event, old, s->signal.sig); - } else - s->priority = priority; - - event_source_pp_prioq_reshuffle(s); - - if (s->type == SOURCE_EXIT) - prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); - - return 0; - -fail: - if (rm_inode) - event_free_inode_data(s->event, new_inode_data); - - if (rm_inotify) - event_free_inotify_data(s->event, new_inotify_data); - - return r; -} - -_public_ int sd_event_source_get_enabled(sd_event_source *s, int *ret) { - assert_return(s, -EINVAL); - assert_return(!event_pid_changed(s->event), -ECHILD); - - if (ret) - *ret = s->enabled; - - return s->enabled != SD_EVENT_OFF; -} - -static int event_source_offline( - sd_event_source *s, - int enabled, - bool ratelimited) { - - bool was_offline; - int r; - - assert(s); - assert(enabled == SD_EVENT_OFF || ratelimited); - - /* Unset the pending flag when this event source is disabled */ - if (s->enabled != SD_EVENT_OFF && - enabled == SD_EVENT_OFF && - !IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { - r = source_set_pending(s, false); - if (r < 0) - return r; - } - - was_offline = event_source_is_offline(s); - s->enabled = enabled; - s->ratelimited = ratelimited; - - switch (s->type) { - - case SOURCE_IO: - source_io_unregister(s); - break; - - case SOURCE_TIME_REALTIME: - case SOURCE_TIME_BOOTTIME: - case SOURCE_TIME_MONOTONIC: - case SOURCE_TIME_REALTIME_ALARM: - case SOURCE_TIME_BOOTTIME_ALARM: - event_source_time_prioq_reshuffle(s); - break; - - case SOURCE_SIGNAL: - event_gc_signal_data(s->event, &s->priority, s->signal.sig); - break; - - case SOURCE_CHILD: - if (!was_offline) { - assert(s->event->n_online_child_sources > 0); - s->event->n_online_child_sources--; - } - - if (EVENT_SOURCE_WATCH_PIDFD(s)) - source_child_pidfd_unregister(s); - else - event_gc_signal_data(s->event, &s->priority, SIGCHLD); - break; - - case SOURCE_EXIT: - prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); - break; - - case SOURCE_DEFER: - case SOURCE_POST: - case SOURCE_INOTIFY: - break; - - default: - assert_not_reached("Wut? I shouldn't exist."); - } - - return 1; -} - -static int event_source_online( - sd_event_source *s, - int enabled, - bool ratelimited) { - - bool was_online; - int r; - - assert(s); - assert(enabled != SD_EVENT_OFF || !ratelimited); - - /* Unset the pending flag when this event source is enabled */ - if (s->enabled == SD_EVENT_OFF && - enabled != SD_EVENT_OFF && - !IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { - r = source_set_pending(s, false); - if (r < 0) - return r; - } - - /* Are we really ready for onlining? */ - if (enabled == SD_EVENT_OFF || ratelimited) { - /* Nope, we are not ready for onlining, then just update the precise state and exit */ - s->enabled = enabled; - s->ratelimited = ratelimited; - return 0; - } - - was_online = event_source_is_online(s); - - switch (s->type) { - case SOURCE_IO: - r = source_io_register(s, enabled, s->io.events); - if (r < 0) - return r; - break; - - case SOURCE_SIGNAL: - r = event_make_signal_data(s->event, s->signal.sig, NULL); - if (r < 0) { - event_gc_signal_data(s->event, &s->priority, s->signal.sig); - return r; - } - - break; - - case SOURCE_CHILD: - if (EVENT_SOURCE_WATCH_PIDFD(s)) { - /* yes, we have pidfd */ - - r = source_child_pidfd_register(s, enabled); - if (r < 0) - return r; - } else { - /* no pidfd, or something other to watch for than WEXITED */ - - r = event_make_signal_data(s->event, SIGCHLD, NULL); - if (r < 0) { - event_gc_signal_data(s->event, &s->priority, SIGCHLD); - return r; - } - } - - if (!was_online) - s->event->n_online_child_sources++; - break; - - case SOURCE_TIME_REALTIME: - case SOURCE_TIME_BOOTTIME: - case SOURCE_TIME_MONOTONIC: - case SOURCE_TIME_REALTIME_ALARM: - case SOURCE_TIME_BOOTTIME_ALARM: - case SOURCE_EXIT: - case SOURCE_DEFER: - case SOURCE_POST: - case SOURCE_INOTIFY: - break; - - default: - assert_not_reached("Wut? I shouldn't exist."); - } - - s->enabled = enabled; - s->ratelimited = ratelimited; - - /* Non-failing operations below */ - switch (s->type) { - case SOURCE_TIME_REALTIME: - case SOURCE_TIME_BOOTTIME: - case SOURCE_TIME_MONOTONIC: - case SOURCE_TIME_REALTIME_ALARM: - case SOURCE_TIME_BOOTTIME_ALARM: - event_source_time_prioq_reshuffle(s); - break; - - case SOURCE_EXIT: - prioq_reshuffle(s->event->exit, s, &s->exit.prioq_index); - break; - - default: - break; - } - - return 1; -} - -_public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { - int r; - - assert_return(s, -EINVAL); - assert_return(IN_SET(m, SD_EVENT_OFF, SD_EVENT_ON, SD_EVENT_ONESHOT), -EINVAL); - assert_return(!event_pid_changed(s->event), -ECHILD); - - /* If we are dead anyway, we are fine with turning off sources, but everything else needs to fail. */ - if (s->event->state == SD_EVENT_FINISHED) - return m == SD_EVENT_OFF ? 0 : -ESTALE; - - if (s->enabled == m) /* No change? */ - return 0; - - if (m == SD_EVENT_OFF) - r = event_source_offline(s, m, s->ratelimited); - else { - if (s->enabled != SD_EVENT_OFF) { - /* Switching from "on" to "oneshot" or back? If that's the case, we can take a shortcut, the - * event source is already enabled after all. */ - s->enabled = m; - return 0; - } - - r = event_source_online(s, m, s->ratelimited); - } - if (r < 0) - return r; - - event_source_pp_prioq_reshuffle(s); - return 0; -} - -_public_ int sd_event_source_get_time(sd_event_source *s, uint64_t *usec) { - assert_return(s, -EINVAL); - assert_return(usec, -EINVAL); - assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM); - assert_return(!event_pid_changed(s->event), -ECHILD); - - *usec = s->time.next; - return 0; -} - -_public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) { - int r; - - assert_return(s, -EINVAL); - assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM); - assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(s->event), -ECHILD); - - r = source_set_pending(s, false); - if (r < 0) - return r; - - s->time.next = usec; - - event_source_time_prioq_reshuffle(s); - return 0; -} - -_public_ int sd_event_source_set_time_relative(sd_event_source *s, uint64_t usec) { - usec_t t; - int r; - - assert_return(s, -EINVAL); - assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM); - - r = sd_event_now(s->event, event_source_type_to_clock(s->type), &t); - if (r < 0) - return r; - - if (usec >= USEC_INFINITY - t) - return -EOVERFLOW; - - return sd_event_source_set_time(s, t + usec); -} - -_public_ int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *usec) { - assert_return(s, -EINVAL); - assert_return(usec, -EINVAL); - assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM); - assert_return(!event_pid_changed(s->event), -ECHILD); - - *usec = s->time.accuracy; - return 0; -} - -_public_ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec) { - int r; - - assert_return(s, -EINVAL); - assert_return(usec != (uint64_t) -1, -EINVAL); - assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM); - assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(s->event), -ECHILD); - - r = source_set_pending(s, false); - if (r < 0) - return r; - - if (usec == 0) - usec = DEFAULT_ACCURACY_USEC; - - s->time.accuracy = usec; - - event_source_time_prioq_reshuffle(s); - return 0; -} - -_public_ int sd_event_source_get_time_clock(sd_event_source *s, clockid_t *clock) { - assert_return(s, -EINVAL); - assert_return(clock, -EINVAL); - assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM); - assert_return(!event_pid_changed(s->event), -ECHILD); - - *clock = event_source_type_to_clock(s->type); - return 0; -} - -_public_ int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid) { - assert_return(s, -EINVAL); - assert_return(pid, -EINVAL); - assert_return(s->type == SOURCE_CHILD, -EDOM); - assert_return(!event_pid_changed(s->event), -ECHILD); - - *pid = s->child.pid; - return 0; -} - -_public_ int sd_event_source_get_child_pidfd(sd_event_source *s) { - assert_return(s, -EINVAL); - assert_return(s->type == SOURCE_CHILD, -EDOM); - assert_return(!event_pid_changed(s->event), -ECHILD); - - if (s->child.pidfd < 0) - return -EOPNOTSUPP; - - return s->child.pidfd; -} - -_public_ int sd_event_source_send_child_signal(sd_event_source *s, int sig, const siginfo_t *si, unsigned flags) { - assert_return(s, -EINVAL); - assert_return(s->type == SOURCE_CHILD, -EDOM); - assert_return(!event_pid_changed(s->event), -ECHILD); - assert_return(SIGNAL_VALID(sig), -EINVAL); - - /* If we already have seen indication the process exited refuse sending a signal early. This way we - * can be sure we don't accidentally kill the wrong process on PID reuse when pidfds are not - * available. */ - if (s->child.exited) - return -ESRCH; - - if (s->child.pidfd >= 0) { - siginfo_t copy; - - /* pidfd_send_signal() changes the siginfo_t argument. This is weird, let's hence copy the - * structure here */ - if (si) - copy = *si; - - if (pidfd_send_signal(s->child.pidfd, sig, si ? © : NULL, 0) < 0) { - /* Let's propagate the error only if the system call is not implemented or prohibited */ - if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno)) - return -errno; - } else - return 0; - } - - /* Flags are only supported for pidfd_send_signal(), not for rt_sigqueueinfo(), hence let's refuse - * this here. */ - if (flags != 0) - return -EOPNOTSUPP; - - if (si) { - /* We use rt_sigqueueinfo() only if siginfo_t is specified. */ - siginfo_t copy = *si; - - if (rt_sigqueueinfo(s->child.pid, sig, ©) < 0) - return -errno; - } else if (kill(s->child.pid, sig) < 0) - return -errno; - - return 0; -} - -_public_ int sd_event_source_get_child_pidfd_own(sd_event_source *s) { - assert_return(s, -EINVAL); - assert_return(s->type == SOURCE_CHILD, -EDOM); - - if (s->child.pidfd < 0) - return -EOPNOTSUPP; - - return s->child.pidfd_owned; -} - -_public_ int sd_event_source_set_child_pidfd_own(sd_event_source *s, int own) { - assert_return(s, -EINVAL); - assert_return(s->type == SOURCE_CHILD, -EDOM); - - if (s->child.pidfd < 0) - return -EOPNOTSUPP; - - s->child.pidfd_owned = own; - return 0; -} - -_public_ int sd_event_source_get_child_process_own(sd_event_source *s) { - assert_return(s, -EINVAL); - assert_return(s->type == SOURCE_CHILD, -EDOM); - - return s->child.process_owned; -} - -_public_ int sd_event_source_set_child_process_own(sd_event_source *s, int own) { - assert_return(s, -EINVAL); - assert_return(s->type == SOURCE_CHILD, -EDOM); - - s->child.process_owned = own; - return 0; -} - -_public_ int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *mask) { - assert_return(s, -EINVAL); - assert_return(mask, -EINVAL); - assert_return(s->type == SOURCE_INOTIFY, -EDOM); - assert_return(!event_pid_changed(s->event), -ECHILD); - - *mask = s->inotify.mask; - return 0; -} - -_public_ int sd_event_source_set_prepare(sd_event_source *s, sd_event_handler_t callback) { - int r; - - assert_return(s, -EINVAL); - assert_return(s->type != SOURCE_EXIT, -EDOM); - assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(s->event), -ECHILD); - - if (s->prepare == callback) - return 0; - - if (callback && s->prepare) { - s->prepare = callback; - return 0; - } - - r = prioq_ensure_allocated(&s->event->prepare, prepare_prioq_compare); - if (r < 0) - return r; - - s->prepare = callback; - - if (callback) { - r = prioq_put(s->event->prepare, s, &s->prepare_index); - if (r < 0) - return r; - } else - prioq_remove(s->event->prepare, s, &s->prepare_index); - - return 0; -} - -_public_ void* sd_event_source_get_userdata(sd_event_source *s) { - assert_return(s, NULL); - - return s->userdata; -} - -_public_ void *sd_event_source_set_userdata(sd_event_source *s, void *userdata) { - void *ret; - - assert_return(s, NULL); - - ret = s->userdata; - s->userdata = userdata; - - return ret; -} - -static int event_source_enter_ratelimited(sd_event_source *s) { - int r; - - assert(s); - - /* When an event source becomes ratelimited, we place it in the CLOCK_MONOTONIC priority queue, with - * the end of the rate limit time window, much as if it was a timer event source. */ - - if (s->ratelimited) - return 0; /* Already ratelimited, this is a NOP hence */ - - /* Make sure we can install a CLOCK_MONOTONIC event further down. */ - r = setup_clock_data(s->event, &s->event->monotonic, CLOCK_MONOTONIC); - if (r < 0) - return r; - - /* Timer event sources are already using the earliest/latest queues for the timer scheduling. Let's - * first remove them from the prioq appropriate for their own clock, so that we can use the prioq - * fields of the event source then for adding it to the CLOCK_MONOTONIC prioq instead. */ - if (EVENT_SOURCE_IS_TIME(s->type)) - event_source_time_prioq_remove(s, event_get_clock_data(s->event, s->type)); - - /* Now, let's add the event source to the monotonic clock instead */ - r = event_source_time_prioq_put(s, &s->event->monotonic); - if (r < 0) - goto fail; - - /* And let's take the event source officially offline */ - r = event_source_offline(s, s->enabled, /* ratelimited= */ true); - if (r < 0) { - event_source_time_prioq_remove(s, &s->event->monotonic); - goto fail; - } - - event_source_pp_prioq_reshuffle(s); - - log_debug("Event source %p (%s) entered rate limit state.", s, strna(s->description)); - return 0; - -fail: - /* Reinstall time event sources in the priority queue as before. This shouldn't fail, since the queue - * space for it should already be allocated. */ - if (EVENT_SOURCE_IS_TIME(s->type)) - assert_se(event_source_time_prioq_put(s, event_get_clock_data(s->event, s->type)) >= 0); - - return r; -} - -static int event_source_leave_ratelimit(sd_event_source *s) { - int r; - - assert(s); - - if (!s->ratelimited) - return 0; - - /* Let's take the event source out of the monotonic prioq first. */ - event_source_time_prioq_remove(s, &s->event->monotonic); - - /* Let's then add the event source to its native clock prioq again — if this is a timer event source */ - if (EVENT_SOURCE_IS_TIME(s->type)) { - r = event_source_time_prioq_put(s, event_get_clock_data(s->event, s->type)); - if (r < 0) - goto fail; - } - - /* Let's try to take it online again. */ - r = event_source_online(s, s->enabled, /* ratelimited= */ false); - if (r < 0) { - /* Do something roughly sensible when this failed: undo the two prioq ops above */ - if (EVENT_SOURCE_IS_TIME(s->type)) - event_source_time_prioq_remove(s, event_get_clock_data(s->event, s->type)); - - goto fail; - } - - event_source_pp_prioq_reshuffle(s); - ratelimit_reset(&s->rate_limit); - - log_debug("Event source %p (%s) left rate limit state.", s, strna(s->description)); - return 0; - -fail: - /* Do something somewhat reasonable when we cannot move an event sources out of ratelimited mode: - * simply put it back in it, maybe we can then process it more successfully next iteration. */ - assert_se(event_source_time_prioq_put(s, &s->event->monotonic) >= 0); - - return r; -} - -static usec_t sleep_between(sd_event *e, usec_t a, usec_t b) { - usec_t c; - assert(e); - assert(a <= b); - - if (a <= 0) - return 0; - if (a >= USEC_INFINITY) - return USEC_INFINITY; - - if (b <= a + 1) - return a; - - initialize_perturb(e); - - /* - Find a good time to wake up again between times a and b. We - have two goals here: - - a) We want to wake up as seldom as possible, hence prefer - later times over earlier times. - - b) But if we have to wake up, then let's make sure to - dispatch as much as possible on the entire system. - - We implement this by waking up everywhere at the same time - within any given minute if we can, synchronised via the - perturbation value determined from the boot ID. If we can't, - then we try to find the same spot in every 10s, then 1s and - then 250ms step. Otherwise, we pick the last possible time - to wake up. - */ - - c = (b / USEC_PER_MINUTE) * USEC_PER_MINUTE + e->perturb; - if (c >= b) { - if (_unlikely_(c < USEC_PER_MINUTE)) - return b; - - c -= USEC_PER_MINUTE; - } - - if (c >= a) - return c; - - c = (b / (USEC_PER_SEC*10)) * (USEC_PER_SEC*10) + (e->perturb % (USEC_PER_SEC*10)); - if (c >= b) { - if (_unlikely_(c < USEC_PER_SEC*10)) - return b; - - c -= USEC_PER_SEC*10; - } - - if (c >= a) - return c; - - c = (b / USEC_PER_SEC) * USEC_PER_SEC + (e->perturb % USEC_PER_SEC); - if (c >= b) { - if (_unlikely_(c < USEC_PER_SEC)) - return b; - - c -= USEC_PER_SEC; - } - - if (c >= a) - return c; - - c = (b / (USEC_PER_MSEC*250)) * (USEC_PER_MSEC*250) + (e->perturb % (USEC_PER_MSEC*250)); - if (c >= b) { - if (_unlikely_(c < USEC_PER_MSEC*250)) - return b; - - c -= USEC_PER_MSEC*250; - } - - if (c >= a) - return c; - - return b; -} - -static int event_arm_timer( - sd_event *e, - struct clock_data *d) { - - struct itimerspec its = {}; - sd_event_source *a, *b; - usec_t t; - - assert(e); - assert(d); - - if (!d->needs_rearm) - return 0; - else - d->needs_rearm = false; - - a = prioq_peek(d->earliest); - if (!a || a->enabled == SD_EVENT_OFF || time_event_source_next(a) == USEC_INFINITY) { - - if (d->fd < 0) - return 0; - - if (d->next == USEC_INFINITY) - return 0; - - /* disarm */ - if (timerfd_settime(d->fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) - return -errno; - - d->next = USEC_INFINITY; - return 0; - } - - b = prioq_peek(d->latest); - assert_se(b && b->enabled != SD_EVENT_OFF); - - t = sleep_between(e, time_event_source_next(a), time_event_source_latest(b)); - if (d->next == t) - return 0; - - assert_se(d->fd >= 0); - - if (t == 0) { - /* We don' want to disarm here, just mean some time looooong ago. */ - its.it_value.tv_sec = 0; - its.it_value.tv_nsec = 1; - } else - timespec_store(&its.it_value, t); - - if (timerfd_settime(d->fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) - return -errno; - - d->next = t; - return 0; -} - -static int process_io(sd_event *e, sd_event_source *s, uint32_t revents) { - assert(e); - assert(s); - assert(s->type == SOURCE_IO); - - /* If the event source was already pending, we just OR in the - * new revents, otherwise we reset the value. The ORing is - * necessary to handle EPOLLONESHOT events properly where - * readability might happen independently of writability, and - * we need to keep track of both */ - - if (s->pending) - s->io.revents |= revents; - else - s->io.revents = revents; - - return source_set_pending(s, true); -} - -static int flush_timer(sd_event *e, int fd, uint32_t events, usec_t *next) { - uint64_t x; - ssize_t ss; - - assert(e); - assert(fd >= 0); - - assert_return(events == EPOLLIN, -EIO); - - ss = read(fd, &x, sizeof(x)); - if (ss < 0) { - if (IN_SET(errno, EAGAIN, EINTR)) - return 0; - - return -errno; - } - - if (_unlikely_(ss != sizeof(x))) - return -EIO; - - if (next) - *next = USEC_INFINITY; - - return 0; -} - -static int process_timer( - sd_event *e, - usec_t n, - struct clock_data *d) { - - sd_event_source *s; - int r; - - assert(e); - assert(d); - - for (;;) { - s = prioq_peek(d->earliest); - if (!s || time_event_source_next(s) > n) - break; - - if (s->ratelimited) { - /* This is an event sources whose ratelimit window has ended. Let's turn it on - * again. */ - assert(s->ratelimited); - - r = event_source_leave_ratelimit(s); - if (r < 0) - return r; - - continue; - } - - if (s->enabled == SD_EVENT_OFF || s->pending) - break; - - r = source_set_pending(s, true); - if (r < 0) - return r; - - event_source_time_prioq_reshuffle(s); - } - - return 0; -} - -static int process_child(sd_event *e) { - sd_event_source *s; - int r; - - assert(e); - - e->need_process_child = false; - - /* - So, this is ugly. We iteratively invoke waitid() with P_PID - + WNOHANG for each PID we wait for, instead of using - P_ALL. This is because we only want to get child - information of very specific child processes, and not all - of them. We might not have processed the SIGCHLD even of a - previous invocation and we don't want to maintain a - unbounded *per-child* event queue, hence we really don't - want anything flushed out of the kernel's queue that we - don't care about. Since this is O(n) this means that if you - have a lot of processes you probably want to handle SIGCHLD - yourself. - - We do not reap the children here (by using WNOWAIT), this - is only done after the event source is dispatched so that - the callback still sees the process as a zombie. - */ - - HASHMAP_FOREACH(s, e->child_sources) { - assert(s->type == SOURCE_CHILD); - - if (s->pending) - continue; - - if (event_source_is_offline(s)) - continue; - - if (s->child.exited) - continue; - - if (EVENT_SOURCE_WATCH_PIDFD(s)) /* There's a usable pidfd known for this event source? then don't waitid() for it here */ - continue; - - zero(s->child.siginfo); - if (waitid(P_PID, s->child.pid, &s->child.siginfo, - WNOHANG | (s->child.options & WEXITED ? WNOWAIT : 0) | s->child.options) < 0) - return -errno; - - if (s->child.siginfo.si_pid != 0) { - bool zombie = IN_SET(s->child.siginfo.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED); - - if (zombie) - s->child.exited = true; - - if (!zombie && (s->child.options & WEXITED)) { - /* If the child isn't dead then let's - * immediately remove the state change - * from the queue, since there's no - * benefit in leaving it queued */ - - assert(s->child.options & (WSTOPPED|WCONTINUED)); - (void) waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|(s->child.options & (WSTOPPED|WCONTINUED))); - } - - r = source_set_pending(s, true); - if (r < 0) - return r; - } - } - - return 0; -} - -static int process_pidfd(sd_event *e, sd_event_source *s, uint32_t revents) { - assert(e); - assert(s); - assert(s->type == SOURCE_CHILD); - - if (s->pending) - return 0; - - if (event_source_is_offline(s)) - return 0; - - if (!EVENT_SOURCE_WATCH_PIDFD(s)) - return 0; - - zero(s->child.siginfo); - if (waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG | WNOWAIT | s->child.options) < 0) - return -errno; - - if (s->child.siginfo.si_pid == 0) - return 0; - - if (IN_SET(s->child.siginfo.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED)) - s->child.exited = true; - - return source_set_pending(s, true); -} - -static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) { - bool read_one = false; - int r; - - assert(e); - assert(d); - assert_return(events == EPOLLIN, -EIO); - - /* If there's a signal queued on this priority and SIGCHLD is - on this priority too, then make sure to recheck the - children we watch. This is because we only ever dequeue - the first signal per priority, and if we dequeue one, and - SIGCHLD might be enqueued later we wouldn't know, but we - might have higher priority children we care about hence we - need to check that explicitly. */ - - if (sigismember(&d->sigset, SIGCHLD)) - e->need_process_child = true; - - /* If there's already an event source pending for this - * priority we don't read another */ - if (d->current) - return 0; - - for (;;) { - struct signalfd_siginfo si; - ssize_t n; - sd_event_source *s = NULL; - - n = read(d->fd, &si, sizeof(si)); - if (n < 0) { - if (IN_SET(errno, EAGAIN, EINTR)) - return read_one; - - return -errno; - } - - if (_unlikely_(n != sizeof(si))) - return -EIO; - - assert(SIGNAL_VALID(si.ssi_signo)); - - read_one = true; - - if (e->signal_sources) - s = e->signal_sources[si.ssi_signo]; - if (!s) - continue; - if (s->pending) - continue; - - s->signal.siginfo = si; - d->current = s; - - r = source_set_pending(s, true); - if (r < 0) - return r; - - return 1; - } -} - -static int event_inotify_data_read(sd_event *e, struct inotify_data *d, uint32_t revents) { - ssize_t n; - - assert(e); - assert(d); - - assert_return(revents == EPOLLIN, -EIO); - - /* If there's already an event source pending for this priority, don't read another */ - if (d->n_pending > 0) - return 0; - - /* Is the read buffer non-empty? If so, let's not read more */ - if (d->buffer_filled > 0) - return 0; - - n = read(d->fd, &d->buffer, sizeof(d->buffer)); - if (n < 0) { - if (IN_SET(errno, EAGAIN, EINTR)) - return 0; - - return -errno; - } - - assert(n > 0); - d->buffer_filled = (size_t) n; - LIST_PREPEND(buffered, e->inotify_data_buffered, d); - - return 1; -} - -static void event_inotify_data_drop(sd_event *e, struct inotify_data *d, size_t sz) { - assert(e); - assert(d); - assert(sz <= d->buffer_filled); - - if (sz == 0) - return; - - /* Move the rest to the buffer to the front, in order to get things properly aligned again */ - memmove(d->buffer.raw, d->buffer.raw + sz, d->buffer_filled - sz); - d->buffer_filled -= sz; - - if (d->buffer_filled == 0) - LIST_REMOVE(buffered, e->inotify_data_buffered, d); -} - -static int event_inotify_data_process(sd_event *e, struct inotify_data *d) { - int r; - - assert(e); - assert(d); - - /* If there's already an event source pending for this priority, don't read another */ - if (d->n_pending > 0) - return 0; - - while (d->buffer_filled > 0) { - size_t sz; - - /* Let's validate that the event structures are complete */ - if (d->buffer_filled < offsetof(struct inotify_event, name)) - return -EIO; - - sz = offsetof(struct inotify_event, name) + d->buffer.ev.len; - if (d->buffer_filled < sz) - return -EIO; - - if (d->buffer.ev.mask & IN_Q_OVERFLOW) { - struct inode_data *inode_data; - - /* The queue overran, let's pass this event to all event sources connected to this inotify - * object */ - - HASHMAP_FOREACH(inode_data, d->inodes) { - sd_event_source *s; - - LIST_FOREACH(inotify.by_inode_data, s, inode_data->event_sources) { - - if (event_source_is_offline(s)) - continue; - - r = source_set_pending(s, true); - if (r < 0) - return r; - } - } - } else { - struct inode_data *inode_data; - sd_event_source *s; - - /* Find the inode object for this watch descriptor. If IN_IGNORED is set we also remove it from - * our watch descriptor table. */ - if (d->buffer.ev.mask & IN_IGNORED) { - - inode_data = hashmap_remove(d->wd, INT_TO_PTR(d->buffer.ev.wd)); - if (!inode_data) { - event_inotify_data_drop(e, d, sz); - continue; - } - - /* The watch descriptor was removed by the kernel, let's drop it here too */ - inode_data->wd = -1; - } else { - inode_data = hashmap_get(d->wd, INT_TO_PTR(d->buffer.ev.wd)); - if (!inode_data) { - event_inotify_data_drop(e, d, sz); - continue; - } - } - - /* Trigger all event sources that are interested in these events. Also trigger all event - * sources if IN_IGNORED or IN_UNMOUNT is set. */ - LIST_FOREACH(inotify.by_inode_data, s, inode_data->event_sources) { - - if (event_source_is_offline(s)) - continue; - - if ((d->buffer.ev.mask & (IN_IGNORED|IN_UNMOUNT)) == 0 && - (s->inotify.mask & d->buffer.ev.mask & IN_ALL_EVENTS) == 0) - continue; - - r = source_set_pending(s, true); - if (r < 0) - return r; - } - } - - /* Something pending now? If so, let's finish, otherwise let's read more. */ - if (d->n_pending > 0) - return 1; - } - - return 0; -} - -static int process_inotify(sd_event *e) { - struct inotify_data *d; - int r, done = 0; - - assert(e); - - LIST_FOREACH(buffered, d, e->inotify_data_buffered) { - r = event_inotify_data_process(e, d); - if (r < 0) - return r; - if (r > 0) - done ++; - } - - return done; -} - -static int source_dispatch(sd_event_source *s) { - _cleanup_(sd_event_unrefp) sd_event *saved_event = NULL; - EventSourceType saved_type; - int r = 0; - - assert(s); - assert(s->pending || s->type == SOURCE_EXIT); - - /* Save the event source type, here, so that we still know it after the event callback which might - * invalidate the event. */ - saved_type = s->type; - - /* Similar, store a reference to the event loop object, so that we can still access it after the - * callback might have invalidated/disconnected the event source. */ - saved_event = sd_event_ref(s->event); - - /* Check if we hit the ratelimit for this event source, if so, let's disable it. */ - assert(!s->ratelimited); - if (!ratelimit_below(&s->rate_limit)) { - r = event_source_enter_ratelimited(s); - if (r < 0) - return r; - - return 1; - } - - if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { - r = source_set_pending(s, false); - if (r < 0) - return r; - } - - if (s->type != SOURCE_POST) { - sd_event_source *z; - - /* If we execute a non-post source, let's mark all - * post sources as pending */ - - SET_FOREACH(z, s->event->post_sources) { - if (event_source_is_offline(z)) - continue; - - r = source_set_pending(z, true); - if (r < 0) - return r; - } - } - - if (s->enabled == SD_EVENT_ONESHOT) { - r = sd_event_source_set_enabled(s, SD_EVENT_OFF); - if (r < 0) - return r; - } - - s->dispatching = true; - - switch (s->type) { - - case SOURCE_IO: - r = s->io.callback(s, s->io.fd, s->io.revents, s->userdata); - break; - - case SOURCE_TIME_REALTIME: - case SOURCE_TIME_BOOTTIME: - case SOURCE_TIME_MONOTONIC: - case SOURCE_TIME_REALTIME_ALARM: - case SOURCE_TIME_BOOTTIME_ALARM: - r = s->time.callback(s, s->time.next, s->userdata); - break; - - case SOURCE_SIGNAL: - r = s->signal.callback(s, &s->signal.siginfo, s->userdata); - break; - - case SOURCE_CHILD: { - bool zombie; - - zombie = IN_SET(s->child.siginfo.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED); - - r = s->child.callback(s, &s->child.siginfo, s->userdata); - - /* Now, reap the PID for good. */ - if (zombie) { - (void) waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|WEXITED); - s->child.waited = true; - } - - break; - } - - case SOURCE_DEFER: - r = s->defer.callback(s, s->userdata); - break; - - case SOURCE_POST: - r = s->post.callback(s, s->userdata); - break; - - case SOURCE_EXIT: - r = s->exit.callback(s, s->userdata); - break; - - case SOURCE_INOTIFY: { - struct sd_event *e = s->event; - struct inotify_data *d; - size_t sz; - - assert(s->inotify.inode_data); - assert_se(d = s->inotify.inode_data->inotify_data); - - assert(d->buffer_filled >= offsetof(struct inotify_event, name)); - sz = offsetof(struct inotify_event, name) + d->buffer.ev.len; - assert(d->buffer_filled >= sz); - - r = s->inotify.callback(s, &d->buffer.ev, s->userdata); - - /* When no event is pending anymore on this inotify object, then let's drop the event from the - * buffer. */ - if (d->n_pending == 0) - event_inotify_data_drop(e, d, sz); - - break; - } - - case SOURCE_WATCHDOG: - case _SOURCE_EVENT_SOURCE_TYPE_MAX: - case _SOURCE_EVENT_SOURCE_TYPE_INVALID: - assert_not_reached("Wut? I shouldn't exist."); - } - - s->dispatching = false; - - if (r < 0) { - log_debug_errno(r, "Event source %s (type %s) returned error, %s: %m", - strna(s->description), - event_source_type_to_string(saved_type), - s->exit_on_failure ? "exiting" : "disabling"); - - if (s->exit_on_failure) - (void) sd_event_exit(saved_event, r); - } - - if (s->n_ref == 0) - source_free(s); - else if (r < 0) - sd_event_source_set_enabled(s, SD_EVENT_OFF); - - return 1; -} - -static int event_prepare(sd_event *e) { - int r; - - assert(e); - - for (;;) { - sd_event_source *s; - - s = prioq_peek(e->prepare); - if (!s || s->prepare_iteration == e->iteration || event_source_is_offline(s)) - break; - - s->prepare_iteration = e->iteration; - r = prioq_reshuffle(e->prepare, s, &s->prepare_index); - if (r < 0) - return r; - - assert(s->prepare); - - s->dispatching = true; - r = s->prepare(s, s->userdata); - s->dispatching = false; - - if (r < 0) { - log_debug_errno(r, "Prepare callback of event source %s (type %s) returned error, %s: %m", - strna(s->description), - event_source_type_to_string(s->type), - s->exit_on_failure ? "exiting" : "disabling"); - - if (s->exit_on_failure) - (void) sd_event_exit(e, r); - } - - if (s->n_ref == 0) - source_free(s); - else if (r < 0) - sd_event_source_set_enabled(s, SD_EVENT_OFF); - } - - return 0; -} - -static int dispatch_exit(sd_event *e) { - sd_event_source *p; - int r; - - assert(e); - - p = prioq_peek(e->exit); - if (!p || event_source_is_offline(p)) { - e->state = SD_EVENT_FINISHED; - return 0; - } - - _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); - e->iteration++; - e->state = SD_EVENT_EXITING; - r = source_dispatch(p); - e->state = SD_EVENT_INITIAL; - return r; -} - -static sd_event_source* event_next_pending(sd_event *e) { - sd_event_source *p; - - assert(e); - - p = prioq_peek(e->pending); - if (!p) - return NULL; - - if (event_source_is_offline(p)) - return NULL; - - return p; -} - -static int arm_watchdog(sd_event *e) { - struct itimerspec its = {}; - usec_t t; - - assert(e); - assert(e->watchdog_fd >= 0); - - t = sleep_between(e, - e->watchdog_last + (e->watchdog_period / 2), - e->watchdog_last + (e->watchdog_period * 3 / 4)); - - timespec_store(&its.it_value, t); - - /* Make sure we never set the watchdog to 0, which tells the - * kernel to disable it. */ - if (its.it_value.tv_sec == 0 && its.it_value.tv_nsec == 0) - its.it_value.tv_nsec = 1; - - if (timerfd_settime(e->watchdog_fd, TFD_TIMER_ABSTIME, &its, NULL) < 0) - return -errno; - - return 0; -} - -static int process_watchdog(sd_event *e) { - assert(e); - - if (!e->watchdog) - return 0; - - /* Don't notify watchdog too often */ - if (e->watchdog_last + e->watchdog_period / 4 > e->timestamp.monotonic) - return 0; - - sd_notify(false, "WATCHDOG=1"); - e->watchdog_last = e->timestamp.monotonic; - - return arm_watchdog(e); -} - -static void event_close_inode_data_fds(sd_event *e) { - struct inode_data *d; - - assert(e); - - /* Close the fds pointing to the inodes to watch now. We need to close them as they might otherwise pin - * filesystems. But we can't close them right-away as we need them as long as the user still wants to make - * adjustments to the even source, such as changing the priority (which requires us to remove and re-add a watch - * for the inode). Hence, let's close them when entering the first iteration after they were added, as a - * compromise. */ - - while ((d = e->inode_data_to_close)) { - assert(d->fd >= 0); - d->fd = safe_close(d->fd); - - LIST_REMOVE(to_close, e->inode_data_to_close, d); - } -} - -_public_ int sd_event_prepare(sd_event *e) { - int r; - - assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); - assert_return(!event_pid_changed(e), -ECHILD); - assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); - - /* Let's check that if we are a default event loop we are executed in the correct thread. We only do - * this check here once, since gettid() is typically not cached, and thus want to minimize - * syscalls */ - assert_return(!e->default_event_ptr || e->tid == gettid(), -EREMOTEIO); - - /* Make sure that none of the preparation callbacks ends up freeing the event source under our feet */ - _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); - - if (e->exit_requested) - goto pending; - - e->iteration++; - - e->state = SD_EVENT_PREPARING; - r = event_prepare(e); - e->state = SD_EVENT_INITIAL; - if (r < 0) - return r; - - r = event_arm_timer(e, &e->realtime); - if (r < 0) - return r; - - r = event_arm_timer(e, &e->boottime); - if (r < 0) - return r; - - r = event_arm_timer(e, &e->monotonic); - if (r < 0) - return r; - - r = event_arm_timer(e, &e->realtime_alarm); - if (r < 0) - return r; - - r = event_arm_timer(e, &e->boottime_alarm); - if (r < 0) - return r; - - event_close_inode_data_fds(e); - - if (event_next_pending(e) || e->need_process_child) - goto pending; - - e->state = SD_EVENT_ARMED; - - return 0; - -pending: - e->state = SD_EVENT_ARMED; - r = sd_event_wait(e, 0); - if (r == 0) - e->state = SD_EVENT_ARMED; - - return r; -} - -_public_ int sd_event_wait(sd_event *e, uint64_t timeout) { - size_t event_queue_max; - int r, m, i; - - assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); - assert_return(!event_pid_changed(e), -ECHILD); - assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(e->state == SD_EVENT_ARMED, -EBUSY); - - if (e->exit_requested) { - e->state = SD_EVENT_PENDING; - return 1; - } - - event_queue_max = MAX(e->n_sources, 1u); - if (!GREEDY_REALLOC(e->event_queue, e->event_queue_allocated, event_queue_max)) - return -ENOMEM; - - /* If we still have inotify data buffered, then query the other fds, but don't wait on it */ - if (e->inotify_data_buffered) - timeout = 0; - - m = epoll_wait(e->epoll_fd, e->event_queue, event_queue_max, - timeout == (uint64_t) -1 ? -1 : (int) DIV_ROUND_UP(timeout, USEC_PER_MSEC)); - if (m < 0) { - if (errno == EINTR) { - e->state = SD_EVENT_PENDING; - return 1; - } - - r = -errno; - goto finish; - } - - triple_timestamp_get(&e->timestamp); - - for (i = 0; i < m; i++) { - - if (e->event_queue[i].data.ptr == INT_TO_PTR(SOURCE_WATCHDOG)) - r = flush_timer(e, e->watchdog_fd, e->event_queue[i].events, NULL); - else { - WakeupType *t = e->event_queue[i].data.ptr; - - switch (*t) { - - case WAKEUP_EVENT_SOURCE: { - sd_event_source *s = e->event_queue[i].data.ptr; - - assert(s); - - switch (s->type) { - - case SOURCE_IO: - r = process_io(e, s, e->event_queue[i].events); - break; - - case SOURCE_CHILD: - r = process_pidfd(e, s, e->event_queue[i].events); - break; - - default: - assert_not_reached("Unexpected event source type"); - } - - break; - } - - case WAKEUP_CLOCK_DATA: { - struct clock_data *d = e->event_queue[i].data.ptr; - - assert(d); - - r = flush_timer(e, d->fd, e->event_queue[i].events, &d->next); - break; - } - - case WAKEUP_SIGNAL_DATA: - r = process_signal(e, e->event_queue[i].data.ptr, e->event_queue[i].events); - break; - - case WAKEUP_INOTIFY_DATA: - r = event_inotify_data_read(e, e->event_queue[i].data.ptr, e->event_queue[i].events); - break; - - default: - assert_not_reached("Invalid wake-up pointer"); - } - } - if (r < 0) - goto finish; - } - - r = process_watchdog(e); - if (r < 0) - goto finish; - - r = process_timer(e, e->timestamp.realtime, &e->realtime); - if (r < 0) - goto finish; - - r = process_timer(e, e->timestamp.boottime, &e->boottime); - if (r < 0) - goto finish; - - r = process_timer(e, e->timestamp.monotonic, &e->monotonic); - if (r < 0) - goto finish; - - r = process_timer(e, e->timestamp.realtime, &e->realtime_alarm); - if (r < 0) - goto finish; - - r = process_timer(e, e->timestamp.boottime, &e->boottime_alarm); - if (r < 0) - goto finish; - - if (e->need_process_child) { - r = process_child(e); - if (r < 0) - goto finish; - } - - r = process_inotify(e); - if (r < 0) - goto finish; - - if (event_next_pending(e)) { - e->state = SD_EVENT_PENDING; - - return 1; - } - - r = 0; - -finish: - e->state = SD_EVENT_INITIAL; - - return r; -} - -_public_ int sd_event_dispatch(sd_event *e) { - sd_event_source *p; - int r; - - assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); - assert_return(!event_pid_changed(e), -ECHILD); - assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(e->state == SD_EVENT_PENDING, -EBUSY); - - if (e->exit_requested) - return dispatch_exit(e); - - p = event_next_pending(e); - if (p) { - _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); - - e->state = SD_EVENT_RUNNING; - r = source_dispatch(p); - e->state = SD_EVENT_INITIAL; - return r; - } - - e->state = SD_EVENT_INITIAL; - - return 1; -} - -static void event_log_delays(sd_event *e) { - char b[ELEMENTSOF(e->delays) * DECIMAL_STR_MAX(unsigned) + 1], *p; - size_t l, i; - - p = b; - l = sizeof(b); - for (i = 0; i < ELEMENTSOF(e->delays); i++) { - l = strpcpyf(&p, l, "%u ", e->delays[i]); - e->delays[i] = 0; - } - log_debug("Event loop iterations: %s", b); -} - -_public_ int sd_event_run(sd_event *e, uint64_t timeout) { - int r; - - assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); - assert_return(!event_pid_changed(e), -ECHILD); - assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); - - if (e->profile_delays && e->last_run_usec != 0) { - usec_t this_run; - unsigned l; - - this_run = now(CLOCK_MONOTONIC); - - l = u64log2(this_run - e->last_run_usec); - assert(l < ELEMENTSOF(e->delays)); - e->delays[l]++; - - if (this_run - e->last_log_usec >= 5*USEC_PER_SEC) { - event_log_delays(e); - e->last_log_usec = this_run; - } - } - - /* Make sure that none of the preparation callbacks ends up freeing the event source under our feet */ - _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); - - r = sd_event_prepare(e); - if (r == 0) - /* There was nothing? Then wait... */ - r = sd_event_wait(e, timeout); - - if (e->profile_delays) - e->last_run_usec = now(CLOCK_MONOTONIC); - - if (r > 0) { - /* There's something now, then let's dispatch it */ - r = sd_event_dispatch(e); - if (r < 0) - return r; - - return 1; - } - - return r; -} - -_public_ int sd_event_loop(sd_event *e) { - int r; - - assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); - assert_return(!event_pid_changed(e), -ECHILD); - assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); - - _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = NULL; - - while (e->state != SD_EVENT_FINISHED) { - r = sd_event_run(e, (uint64_t) -1); - if (r < 0) - return r; - } - - return e->exit_code; -} - -_public_ int sd_event_get_fd(sd_event *e) { - assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); - assert_return(!event_pid_changed(e), -ECHILD); - - return e->epoll_fd; -} - -_public_ int sd_event_get_state(sd_event *e) { - assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); - assert_return(!event_pid_changed(e), -ECHILD); - - return e->state; -} - -_public_ int sd_event_get_exit_code(sd_event *e, int *code) { - assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); - assert_return(code, -EINVAL); - assert_return(!event_pid_changed(e), -ECHILD); - - if (!e->exit_requested) - return -ENODATA; - - *code = e->exit_code; - return 0; -} - -_public_ int sd_event_exit(sd_event *e, int code) { - assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); - assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(!event_pid_changed(e), -ECHILD); - - e->exit_requested = true; - e->exit_code = code; - - return 0; -} - -_public_ int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec) { - assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); - assert_return(usec, -EINVAL); - assert_return(!event_pid_changed(e), -ECHILD); - - if (!TRIPLE_TIMESTAMP_HAS_CLOCK(clock)) - return -EOPNOTSUPP; - - /* Generate a clean error in case CLOCK_BOOTTIME is not available. Note that don't use clock_supported() here, - * for a reason: there are systems where CLOCK_BOOTTIME is supported, but CLOCK_BOOTTIME_ALARM is not, but for - * the purpose of getting the time this doesn't matter. */ - if (IN_SET(clock, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM) && !clock_boottime_supported()) - return -EOPNOTSUPP; - - if (!triple_timestamp_is_set(&e->timestamp)) { - /* Implicitly fall back to now() if we never ran before and thus have no cached time. */ - *usec = now(clock); - return 1; - } - - *usec = triple_timestamp_by_clock(&e->timestamp, clock); - return 0; -} - -_public_ int sd_event_default(sd_event **ret) { - sd_event *e = NULL; - int r; - - if (!ret) - return !!default_event; - - if (default_event) { - *ret = sd_event_ref(default_event); - return 0; - } - - r = sd_event_new(&e); - if (r < 0) - return r; - - e->default_event_ptr = &default_event; - e->tid = gettid(); - default_event = e; - - *ret = e; - return 1; -} - -#if 0 /* NM_IGNORED */ -_public_ int sd_event_get_tid(sd_event *e, pid_t *tid) { - assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); - assert_return(tid, -EINVAL); - assert_return(!event_pid_changed(e), -ECHILD); - - if (e->tid != 0) { - *tid = e->tid; - return 0; - } - - return -ENXIO; -} - -_public_ int sd_event_set_watchdog(sd_event *e, int b) { - int r; - - assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); - assert_return(!event_pid_changed(e), -ECHILD); - - if (e->watchdog == !!b) - return e->watchdog; - - if (b) { - r = sd_watchdog_enabled(false, &e->watchdog_period); - if (r <= 0) - return r; - - /* Issue first ping immediately */ - sd_notify(false, "WATCHDOG=1"); - e->watchdog_last = now(CLOCK_MONOTONIC); - - e->watchdog_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC); - if (e->watchdog_fd < 0) - return -errno; - - r = arm_watchdog(e); - if (r < 0) - goto fail; - - struct epoll_event ev = { - .events = EPOLLIN, - .data.ptr = INT_TO_PTR(SOURCE_WATCHDOG), - }; - - if (epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, e->watchdog_fd, &ev) < 0) { - r = -errno; - goto fail; - } - - } else { - if (e->watchdog_fd >= 0) { - (void) epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, e->watchdog_fd, NULL); - e->watchdog_fd = safe_close(e->watchdog_fd); - } - } - - e->watchdog = !!b; - return e->watchdog; - -fail: - e->watchdog_fd = safe_close(e->watchdog_fd); - return r; -} - -_public_ int sd_event_get_watchdog(sd_event *e) { - assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); - assert_return(!event_pid_changed(e), -ECHILD); - - return e->watchdog; -} - -_public_ int sd_event_get_iteration(sd_event *e, uint64_t *ret) { - assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); - assert_return(!event_pid_changed(e), -ECHILD); - - *ret = e->iteration; - return 0; -} - -_public_ int sd_event_source_set_destroy_callback(sd_event_source *s, sd_event_destroy_t callback) { - assert_return(s, -EINVAL); - - s->destroy_callback = callback; - return 0; -} - -_public_ int sd_event_source_get_destroy_callback(sd_event_source *s, sd_event_destroy_t *ret) { - assert_return(s, -EINVAL); - - if (ret) - *ret = s->destroy_callback; - - return !!s->destroy_callback; -} - -_public_ int sd_event_source_get_floating(sd_event_source *s) { - assert_return(s, -EINVAL); - - return s->floating; -} - -_public_ int sd_event_source_set_floating(sd_event_source *s, int b) { - assert_return(s, -EINVAL); - - if (s->floating == !!b) - return 0; - - if (!s->event) /* Already disconnected */ - return -ESTALE; - - s->floating = b; - - if (b) { - sd_event_source_ref(s); - sd_event_unref(s->event); - } else { - sd_event_ref(s->event); - sd_event_source_unref(s); - } - - return 1; -} - -_public_ int sd_event_source_get_exit_on_failure(sd_event_source *s) { - assert_return(s, -EINVAL); - assert_return(s->type != SOURCE_EXIT, -EDOM); - - return s->exit_on_failure; -} - -_public_ int sd_event_source_set_exit_on_failure(sd_event_source *s, int b) { - assert_return(s, -EINVAL); - assert_return(s->type != SOURCE_EXIT, -EDOM); - - if (s->exit_on_failure == !!b) - return 0; - - s->exit_on_failure = b; - return 1; -} - -_public_ int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval, unsigned burst) { - int r; - - assert_return(s, -EINVAL); - - /* Turning on ratelimiting on event source types that don't support it, is a loggable offense. Doing - * so is a programming error. */ - assert_return(EVENT_SOURCE_CAN_RATE_LIMIT(s->type), -EDOM); - - /* When ratelimiting is configured we'll always reset the rate limit state first and start fresh, - * non-ratelimited. */ - r = event_source_leave_ratelimit(s); - if (r < 0) - return r; - - s->rate_limit = (RateLimit) { interval, burst }; - return 0; -} - -_public_ int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval, unsigned *ret_burst) { - assert_return(s, -EINVAL); - - /* Querying whether an event source has ratelimiting configured is not a loggable offsense, hence - * don't use assert_return(). Unlike turning on ratelimiting it's not really a programming error */ - if (!EVENT_SOURCE_CAN_RATE_LIMIT(s->type)) - return -EDOM; - - if (!ratelimit_configured(&s->rate_limit)) - return -ENOEXEC; - - if (ret_interval) - *ret_interval = s->rate_limit.interval; - if (ret_burst) - *ret_burst = s->rate_limit.burst; - - return 0; -} - -_public_ int sd_event_source_is_ratelimited(sd_event_source *s) { - assert_return(s, -EINVAL); - - if (!EVENT_SOURCE_CAN_RATE_LIMIT(s->type)) - return false; - - if (!ratelimit_configured(&s->rate_limit)) - return false; - - return s->ratelimited; -} -#endif /* NM_IGNORED */ diff --git a/src/core/systemd/src/libsystemd/sd-id128/id128-util.c b/src/core/systemd/src/libsystemd/sd-id128/id128-util.c deleted file mode 100644 index b61cfdb0..00000000 --- a/src/core/systemd/src/libsystemd/sd-id128/id128-util.c +++ /dev/null @@ -1,218 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include "nm-sd-adapt-core.h" - -#include -#include -#include - -#include "fd-util.h" -#include "fs-util.h" -#include "hexdecoct.h" -#include "id128-util.h" -#include "io-util.h" -#include "stdio-util.h" -#include "string-util.h" - -#if 0 /* NM_IGNORED */ -char *id128_to_uuid_string(sd_id128_t id, char s[static ID128_UUID_STRING_MAX]) { - unsigned n, k = 0; - - assert(s); - - /* Similar to sd_id128_to_string() but formats the result as UUID instead of plain hex chars */ - - for (n = 0; n < 16; n++) { - - if (IN_SET(n, 4, 6, 8, 10)) - s[k++] = '-'; - - s[k++] = hexchar(id.bytes[n] >> 4); - s[k++] = hexchar(id.bytes[n] & 0xF); - } - - assert(k == 36); - - s[k] = 0; - - return s; -} - -bool id128_is_valid(const char *s) { - size_t i, l; - - assert(s); - - l = strlen(s); - if (l == 32) { - - /* Plain 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 (IN_SET(i, 8, 13, 18, 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; -} -#endif /* NM_IGNORED */ - -int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) { - char buffer[36 + 2]; - ssize_t l; - - assert(fd >= 0); - assert(f < _ID128_FORMAT_MAX); - - /* Reads an 128bit ID from a file, which may either be in plain format (32 hex digits), or in UUID format, both - * optionally followed by a newline and nothing else. ID files should really be newline terminated, but if they - * aren't that's OK too, following the rule of "Be conservative in what you send, be liberal in what you - * accept". */ - - l = loop_read(fd, buffer, sizeof(buffer), false); /* we expect a short read of either 32/33 or 36/37 chars */ - if (l < 0) - return (int) l; - if (l == 0) /* empty? */ - return -ENOMEDIUM; - - switch (l) { - - case 13: - case 14: - /* Treat an "uninitialized" id file like an empty one */ - return f == ID128_PLAIN_OR_UNINIT && strneq(buffer, "uninitialized\n", l) ? -ENOMEDIUM : -EINVAL; - - case 33: /* plain UUID with trailing newline */ - if (buffer[32] != '\n') - return -EINVAL; - - _fallthrough_; - case 32: /* plain UUID without trailing newline */ - if (f == ID128_UUID) - return -EINVAL; - - buffer[32] = 0; - break; - - case 37: /* RFC UUID with trailing newline */ - if (buffer[36] != '\n') - return -EINVAL; - - _fallthrough_; - case 36: /* RFC UUID without trailing newline */ - if (IN_SET(f, ID128_PLAIN, ID128_PLAIN_OR_UNINIT)) - return -EINVAL; - - buffer[36] = 0; - break; - - default: - return -EINVAL; - } - - return sd_id128_from_string(buffer, ret); -} - -int id128_read(const char *p, Id128Format f, sd_id128_t *ret) { - _cleanup_close_ int fd = -1; - - fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) - return -errno; - - return id128_read_fd(fd, f, ret); -} - -#if 0 /* NM_IGNORED */ -int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) { - char buffer[36 + 2]; - size_t sz; - int r; - - assert(fd >= 0); - assert(f < _ID128_FORMAT_MAX); - - if (f != ID128_UUID) { - sd_id128_to_string(id, buffer); - buffer[32] = '\n'; - sz = 33; - } else { - id128_to_uuid_string(id, buffer); - buffer[36] = '\n'; - sz = 37; - } - - r = loop_write(fd, buffer, sz, false); - if (r < 0) - return r; - - if (do_sync) { - if (fsync(fd) < 0) - return -errno; - - r = fsync_directory_of_file(fd); - if (r < 0) - return r; - } - - return 0; -} - -int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync) { - _cleanup_close_ int fd = -1; - - fd = open(p, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_TRUNC, 0444); - if (fd < 0) - return -errno; - - return id128_write_fd(fd, f, id, do_sync); -} - -void id128_hash_func(const sd_id128_t *p, struct siphash *state) { - siphash24_compress(p, sizeof(sd_id128_t), state); -} - -int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) { - return memcmp(a, b, 16); -} - -sd_id128_t id128_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; -} - -DEFINE_HASH_OPS(id128_hash_ops, sd_id128_t, id128_hash_func, id128_compare_func); -#endif /* NM_IGNORED */ diff --git a/src/core/systemd/src/libsystemd/sd-id128/id128-util.h b/src/core/systemd/src/libsystemd/sd-id128/id128-util.h deleted file mode 100644 index 6b09bcd9..00000000 --- a/src/core/systemd/src/libsystemd/sd-id128/id128-util.h +++ /dev/null @@ -1,38 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -#include - -#include "sd-id128.h" - -#include "hash-funcs.h" -#include "macro.h" - -#define ID128_UUID_STRING_MAX 37 - -char *id128_to_uuid_string(sd_id128_t id, char s[static ID128_UUID_STRING_MAX]); - -bool id128_is_valid(const char *s) _pure_; - -typedef enum Id128Format { - ID128_ANY, - ID128_PLAIN, /* formatted as 32 hex chars as-is */ - ID128_PLAIN_OR_UNINIT, /* formatted as 32 hex chars as-is; allow special "uninitialized" - * value when reading from file (id128_read() and id128_read_fd()). - * - * This format should be used when reading a machine-id file. */ - ID128_UUID, /* formatted as 36 character uuid string */ - _ID128_FORMAT_MAX, -} Id128Format; - -int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret); -int id128_read(const char *p, Id128Format f, sd_id128_t *ret); - -int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync); -int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync); - -void id128_hash_func(const sd_id128_t *p, struct siphash *state); -int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) _pure_; -extern const struct hash_ops id128_hash_ops; - -sd_id128_t id128_make_v4_uuid(sd_id128_t id); diff --git a/src/core/systemd/src/libsystemd/sd-id128/sd-id128.c b/src/core/systemd/src/libsystemd/sd-id128/sd-id128.c deleted file mode 100644 index 64b8c787..00000000 --- a/src/core/systemd/src/libsystemd/sd-id128/sd-id128.c +++ /dev/null @@ -1,330 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include "nm-sd-adapt-core.h" - -#include -#include -#include - -#include "sd-id128.h" - -#include "alloc-util.h" -#include "fd-util.h" -#include "hexdecoct.h" -#include "id128-util.h" -#include "io-util.h" -#include "khash.h" -#include "macro.h" -#include "missing_syscall.h" -#include "random-util.h" -#include "user-util.h" -#include "util.h" - -#if 0 /* NM_IGNORED */ -_public_ char *sd_id128_to_string(sd_id128_t id, char s[_SD_ARRAY_STATIC 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; -} -#endif /* NM_IGNORED */ - -_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); - - 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 (IN_SET(i, 13, 18, 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; - - if (ret) - *ret = t; - return 0; -} - -_public_ int sd_id128_get_machine(sd_id128_t *ret) { - static thread_local sd_id128_t saved_machine_id = {}; - int r; - - assert_return(ret, -EINVAL); - - if (sd_id128_is_null(saved_machine_id)) { - r = id128_read("/etc/machine-id", ID128_PLAIN, &saved_machine_id); - if (r < 0) - return r; - - if (sd_id128_is_null(saved_machine_id)) - return -ENOMEDIUM; - } - - *ret = saved_machine_id; - return 0; -} - -_public_ int sd_id128_get_boot(sd_id128_t *ret) { - static thread_local sd_id128_t saved_boot_id = {}; - int r; - - assert_return(ret, -EINVAL); - - if (sd_id128_is_null(saved_boot_id)) { - r = id128_read("/proc/sys/kernel/random/boot_id", ID128_UUID, &saved_boot_id); - if (r < 0) - return r; - } - - *ret = saved_boot_id; - return 0; -} - -#if 0 /* NM_IGNORED */ -static int get_invocation_from_keyring(sd_id128_t *ret) { - _cleanup_free_ char *description = NULL; - char *d, *p, *g, *u, *e; - unsigned long perms; - key_serial_t key; - size_t sz = 256; - uid_t uid; - gid_t gid; - int r, c; - -#define MAX_PERMS ((unsigned long) (KEY_POS_VIEW|KEY_POS_READ|KEY_POS_SEARCH| \ - KEY_USR_VIEW|KEY_USR_READ|KEY_USR_SEARCH)) - - assert(ret); - - key = request_key("user", "invocation_id", NULL, 0); - if (key == -1) { - /* Keyring support not available? No invocation key stored? */ - if (IN_SET(errno, ENOSYS, ENOKEY)) - return -ENXIO; - - return -errno; - } - - for (;;) { - description = new(char, sz); - if (!description) - return -ENOMEM; - - c = keyctl(KEYCTL_DESCRIBE, key, (unsigned long) description, sz, 0); - if (c < 0) - return -errno; - - if ((size_t) c <= sz) - break; - - sz = c; - free(description); - } - - /* The kernel returns a final NUL in the string, verify that. */ - assert(description[c-1] == 0); - - /* Chop off the final description string */ - d = strrchr(description, ';'); - if (!d) - return -EIO; - *d = 0; - - /* Look for the permissions */ - p = strrchr(description, ';'); - if (!p) - return -EIO; - - errno = 0; - perms = strtoul(p + 1, &e, 16); - if (errno > 0) - return -errno; - if (e == p + 1) /* Read at least one character */ - return -EIO; - if (e != d) /* Must reached the end */ - return -EIO; - - if ((perms & ~MAX_PERMS) != 0) - return -EPERM; - - *p = 0; - - /* Look for the group ID */ - g = strrchr(description, ';'); - if (!g) - return -EIO; - r = parse_gid(g + 1, &gid); - if (r < 0) - return r; - if (gid != 0) - return -EPERM; - *g = 0; - - /* Look for the user ID */ - u = strrchr(description, ';'); - if (!u) - return -EIO; - r = parse_uid(u + 1, &uid); - if (r < 0) - return r; - if (uid != 0) - return -EPERM; - - c = keyctl(KEYCTL_READ, key, (unsigned long) ret, sizeof(sd_id128_t), 0); - if (c < 0) - return -errno; - if (c != sizeof(sd_id128_t)) - return -EIO; - - return 0; -} - -static int get_invocation_from_environment(sd_id128_t *ret) { - const char *e; - - assert(ret); - - e = secure_getenv("INVOCATION_ID"); - if (!e) - return -ENXIO; - - return sd_id128_from_string(e, ret); -} - -_public_ int sd_id128_get_invocation(sd_id128_t *ret) { - static thread_local sd_id128_t saved_invocation_id = {}; - int r; - - assert_return(ret, -EINVAL); - - if (sd_id128_is_null(saved_invocation_id)) { - /* We first check the environment. The environment variable is primarily relevant for user - * services, and sufficiently safe as long as no privilege boundary is involved. */ - r = get_invocation_from_environment(&saved_invocation_id); - if (r < 0 && r != -ENXIO) - return r; - - /* The kernel keyring is relevant for system services (as for user services we don't store - * the invocation ID in the keyring, as there'd be no trust benefit in that). */ - r = get_invocation_from_keyring(&saved_invocation_id); - if (r < 0) - return r; - } - - *ret = saved_invocation_id; - return 0; -} - -_public_ int sd_id128_randomize(sd_id128_t *ret) { - sd_id128_t t; - int r; - - assert_return(ret, -EINVAL); - - /* We allow usage if x86-64 RDRAND here. It might not be trusted enough for keeping secrets, but it should be - * fine for UUIDS. */ - r = genuine_random_bytes(&t, sizeof t, RANDOM_ALLOW_RDRAND); - 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 = id128_make_v4_uuid(t); - return 0; -} - -static int get_app_specific(sd_id128_t base, sd_id128_t app_id, sd_id128_t *ret) { - _cleanup_(khash_unrefp) khash *h = NULL; - sd_id128_t result; - const void *p; - int r; - - assert(ret); - - r = khash_new_with_key(&h, "hmac(sha256)", &base, sizeof(base)); - if (r < 0) - return r; - - r = khash_put(h, &app_id, sizeof(app_id)); - if (r < 0) - return r; - - r = khash_digest_data(h, &p); - if (r < 0) - return r; - - /* We chop off the trailing 16 bytes */ - memcpy(&result, p, MIN(khash_get_size(h), sizeof(result))); - - *ret = id128_make_v4_uuid(result); - return 0; -} - -_public_ int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *ret) { - sd_id128_t id; - int r; - - assert_return(ret, -EINVAL); - - r = sd_id128_get_machine(&id); - if (r < 0) - return r; - - return get_app_specific(id, app_id, ret); -} - -_public_ int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret) { - sd_id128_t id; - int r; - - assert_return(ret, -EINVAL); - - r = sd_id128_get_boot(&id); - if (r < 0) - return r; - - return get_app_specific(id, app_id, ret); -} -#endif /* NM_IGNORED */ diff --git a/src/core/systemd/src/systemd/_sd-common.h b/src/core/systemd/src/systemd/_sd-common.h deleted file mode 100644 index e3de2ae5..00000000 --- a/src/core/systemd/src/systemd/_sd-common.h +++ /dev/null @@ -1,102 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef foosdcommonhfoo -#define foosdcommonhfoo - -/*** - 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 defined(__INCLUDE_LEVEL__) && __INCLUDE_LEVEL__ <= 1 && !defined(__COVERITY__) -# error "Do not include _sd-common.h directly; it is a private header." -#endif - -typedef void (*_sd_destroy_t)(void *userdata); - -#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 - -/* Note that strictly speaking __deprecated__ has been available before GCC 6. However, starting with GCC 6 - * it also works on enum values, which we are interested in. Since this is a developer-facing feature anyway - * (as opposed to build engineer-facing), let's hence conditionalize this to gcc 6, given that the developers - * are probably going to use something newer anyway. */ -#ifndef _sd_deprecated_ -# if __GNUC__ >= 6 -# define _sd_deprecated_ __attribute__((__deprecated__)) -# else -# define _sd_deprecated_ -# endif -#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 - -#ifndef _SD_ARRAY_STATIC -# if __STDC_VERSION__ >= 199901L -# define _SD_ARRAY_STATIC static -# else -# define _SD_ARRAY_STATIC -# 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/core/systemd/src/systemd/sd-dhcp-client.h b/src/core/systemd/src/systemd/sd-dhcp-client.h deleted file mode 100644 index c35328a9..00000000 --- a/src/core/systemd/src/systemd/sd-dhcp-client.h +++ /dev/null @@ -1,224 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef foosddhcpclienthfoo -#define foosddhcpclienthfoo - -/*** - Copyright © 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 -#include - -#include "sd-dhcp-lease.h" -#include "sd-dhcp-option.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, - SD_DHCP_CLIENT_EVENT_SELECTING = 5, - SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE = 6, /* Sent when we have not received a reply after the first few attempts. - * The client may want to start acquiring link-local addresses. */ -}; - -enum { - SD_DHCP_OPTION_PAD = 0, - SD_DHCP_OPTION_SUBNET_MASK = 1, - SD_DHCP_OPTION_TIME_OFFSET = 2, - SD_DHCP_OPTION_ROUTER = 3, - SD_DHCP_OPTION_DOMAIN_NAME_SERVER = 6, - SD_DHCP_OPTION_LPR_SERVER = 9, - SD_DHCP_OPTION_HOST_NAME = 12, - SD_DHCP_OPTION_BOOT_FILE_SIZE = 13, - SD_DHCP_OPTION_DOMAIN_NAME = 15, - SD_DHCP_OPTION_ROOT_PATH = 17, - SD_DHCP_OPTION_ENABLE_IP_FORWARDING = 19, - SD_DHCP_OPTION_ENABLE_IP_FORWARDING_NL = 20, - SD_DHCP_OPTION_POLICY_FILTER = 21, - SD_DHCP_OPTION_INTERFACE_MDR = 22, - SD_DHCP_OPTION_INTERFACE_TTL = 23, - SD_DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT = 24, - SD_DHCP_OPTION_INTERFACE_MTU = 26, - SD_DHCP_OPTION_BROADCAST = 28, - /* Windows 10 option to send when Anonymize=true */ - SD_DHCP_OPTION_ROUTER_DISCOVER = 31, - SD_DHCP_OPTION_STATIC_ROUTE = 33, - SD_DHCP_OPTION_NTP_SERVER = 42, - SD_DHCP_OPTION_VENDOR_SPECIFIC = 43, - /* Windows 10 option to send when Anonymize=true */ - SD_DHCP_OPTION_NETBIOS_NAMESERVER = 44, - /* Windows 10 option to send when Anonymize=true */ - SD_DHCP_OPTION_NETBIOS_NODETYPE = 46, - /* Windows 10 option to send when Anonymize=true */ - SD_DHCP_OPTION_NETBIOS_SCOPE = 47, - SD_DHCP_OPTION_REQUESTED_IP_ADDRESS = 50, - SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME = 51, - SD_DHCP_OPTION_OVERLOAD = 52, - SD_DHCP_OPTION_MESSAGE_TYPE = 53, - SD_DHCP_OPTION_SERVER_IDENTIFIER = 54, - SD_DHCP_OPTION_PARAMETER_REQUEST_LIST = 55, - SD_DHCP_OPTION_ERROR_MESSAGE = 56, - SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE = 57, - SD_DHCP_OPTION_RENEWAL_T1_TIME = 58, - SD_DHCP_OPTION_REBINDING_T2_TIME = 59, - SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60, - SD_DHCP_OPTION_CLIENT_IDENTIFIER = 61, - SD_DHCP_OPTION_SMTP_SERVER = 69, - SD_DHCP_OPTION_POP3_SERVER = 70, - SD_DHCP_OPTION_USER_CLASS = 77, - SD_DHCP_OPTION_FQDN = 81, - SD_DHCP_OPTION_NEW_POSIX_TIMEZONE = 100, - SD_DHCP_OPTION_NEW_TZDB_TIMEZONE = 101, - SD_DHCP_OPTION_DOMAIN_SEARCH_LIST = 119, - SD_DHCP_OPTION_SIP_SERVER = 120, - SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121, - SD_DHCP_OPTION_MUD_URL = 161, - SD_DHCP_OPTION_PRIVATE_BASE = 224, - /* Windows 10 option to send when Anonymize=true */ - SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE = 249, - /* Windows 10 option to send when Anonymize=true */ - SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY = 252, - SD_DHCP_OPTION_PRIVATE_LAST = 254, - SD_DHCP_OPTION_END = 255, -}; - -typedef struct sd_dhcp_client sd_dhcp_client; - -typedef int (*sd_dhcp_client_callback_t)(sd_dhcp_client *client, int event, void *userdata); -int sd_dhcp_client_set_callback( - sd_dhcp_client *client, - sd_dhcp_client_callback_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_ifindex( - sd_dhcp_client *client, - int interface_index); -int sd_dhcp_client_set_mac( - sd_dhcp_client *client, - const uint8_t *addr, - const uint8_t *bcast_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_set_iaid_duid( - sd_dhcp_client *client, - bool iaid_set, - uint32_t iaid, - uint16_t duid_type, - const void *duid, - size_t duid_len); -int sd_dhcp_client_set_iaid_duid_llt( - sd_dhcp_client *client, - bool iaid_set, - uint32_t iaid, - uint64_t llt_time); -int sd_dhcp_client_set_duid( - sd_dhcp_client *client, - uint16_t duid_type, - const void *duid, - size_t duid_len); -int sd_dhcp_client_set_duid_llt( - sd_dhcp_client *client, - uint64_t llt_time); -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_max_attempts( - sd_dhcp_client *client, - uint64_t attempt); -int sd_dhcp_client_set_client_port( - sd_dhcp_client *client, - uint16_t port); -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_set_mud_url( - sd_dhcp_client *client, - const char *mudurl); -int sd_dhcp_client_set_user_class( - sd_dhcp_client *client, - const char* const *user_class); -int sd_dhcp_client_get_lease( - sd_dhcp_client *client, - sd_dhcp_lease **ret); -int sd_dhcp_client_set_service_type( - sd_dhcp_client *client, - int type); -int sd_dhcp_client_set_fallback_lease_lifetime( - sd_dhcp_client *client, - uint32_t fallback_lease_lifetime); - -int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v); -int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v); - -int sd_dhcp_client_stop(sd_dhcp_client *client); -int sd_dhcp_client_start(sd_dhcp_client *client); -int sd_dhcp_client_send_release(sd_dhcp_client *client); -int sd_dhcp_client_send_decline(sd_dhcp_client *client); -int sd_dhcp_client_send_renew(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); - -/* NOTE: anonymize parameter is used to initialize PRL memory with different - * options when using RFC7844 Anonymity Profiles */ -int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize); - -int sd_dhcp_client_id_to_string(const void *data, size_t len, char **ret); - -int sd_dhcp_client_attach_event( - sd_dhcp_client *client, - sd_event *event, - int64_t 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/core/systemd/src/systemd/sd-dhcp-lease.h b/src/core/systemd/src/systemd/sd-dhcp-lease.h deleted file mode 100644 index c255a1f9..00000000 --- a/src/core/systemd/src/systemd/sd-dhcp-lease.h +++ /dev/null @@ -1,82 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef foosddhcpleasehfoo -#define foosddhcpleasehfoo - -/*** - Copyright © 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 - -#include "_sd-common.h" - -_SD_BEGIN_DECLARATIONS; - -typedef struct sd_dhcp_lease sd_dhcp_lease; -typedef struct sd_dhcp_route 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); - -typedef enum sd_dhcp_lease_server_type { - SD_DHCP_LEASE_DNS, - SD_DHCP_LEASE_NTP, - SD_DHCP_LEASE_SIP, - SD_DHCP_LEASE_POP3, - SD_DHCP_LEASE_SMTP, - SD_DHCP_LEASE_LPR, - _SD_DHCP_LEASE_SERVER_TYPE_MAX, - _SD_DHCP_LEASE_SERVER_TYPE_INVALID = -1, -} sd_dhcp_lease_server_type; - -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, const 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_servers(sd_dhcp_lease *lease, sd_dhcp_lease_server_type what, const 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_sip(sd_dhcp_lease *lease, const struct in_addr **addr); -int sd_dhcp_lease_get_pop3(sd_dhcp_lease *lease, const struct in_addr **addr); -int sd_dhcp_lease_get_smtp(sd_dhcp_lease *lease, const struct in_addr **addr); -int sd_dhcp_lease_get_lpr(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_search_domains(sd_dhcp_lease *lease, char ***domains); -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, 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); - -int sd_dhcp_route_get_destination(sd_dhcp_route *route, struct in_addr *destination); -int sd_dhcp_route_get_destination_prefix_length(sd_dhcp_route *route, uint8_t *length); -int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway); -int sd_dhcp_route_get_option(sd_dhcp_route *route); - -_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_lease, sd_dhcp_lease_unref); - -_SD_END_DECLARATIONS; - -#endif diff --git a/src/core/systemd/src/systemd/sd-dhcp-option.h b/src/core/systemd/src/systemd/sd-dhcp-option.h deleted file mode 100644 index 71aa479b..00000000 --- a/src/core/systemd/src/systemd/sd-dhcp-option.h +++ /dev/null @@ -1,38 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef foosddhcpoptionhfoo -#define foosddhcpoptionhfoo - -/*** - Copyright © 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-common.h" - -_SD_BEGIN_DECLARATIONS; - -typedef struct sd_dhcp_option sd_dhcp_option; - -int sd_dhcp_option_new(uint8_t option, const void *data, size_t length, sd_dhcp_option **ret); -sd_dhcp_option *sd_dhcp_option_ref(sd_dhcp_option *ra); -sd_dhcp_option *sd_dhcp_option_unref(sd_dhcp_option *ra); - -_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_option, sd_dhcp_option_unref); - -_SD_END_DECLARATIONS; - -#endif diff --git a/src/core/systemd/src/systemd/sd-dhcp6-client.h b/src/core/systemd/src/systemd/sd-dhcp6-client.h deleted file mode 100644 index 75ee27d6..00000000 --- a/src/core/systemd/src/systemd/sd-dhcp6-client.h +++ /dev/null @@ -1,180 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef foosddhcp6clienthfoo -#define foosddhcp6clienthfoo - -/*** - Copyright © 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 - -#include "sd-dhcp6-lease.h" -#include "sd-dhcp6-option.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, -}; - -enum { - SD_DHCP6_OPTION_CLIENTID = 1, - SD_DHCP6_OPTION_SERVERID = 2, - SD_DHCP6_OPTION_IA_NA = 3, - SD_DHCP6_OPTION_IA_TA = 4, - SD_DHCP6_OPTION_IAADDR = 5, - SD_DHCP6_OPTION_ORO = 6, - SD_DHCP6_OPTION_PREFERENCE = 7, - SD_DHCP6_OPTION_ELAPSED_TIME = 8, - SD_DHCP6_OPTION_RELAY_MSG = 9, - /* option code 10 is unassigned */ - SD_DHCP6_OPTION_AUTH = 11, - SD_DHCP6_OPTION_UNICAST = 12, - SD_DHCP6_OPTION_STATUS_CODE = 13, - SD_DHCP6_OPTION_RAPID_COMMIT = 14, - SD_DHCP6_OPTION_USER_CLASS = 15, - SD_DHCP6_OPTION_VENDOR_CLASS = 16, - SD_DHCP6_OPTION_VENDOR_OPTS = 17, - SD_DHCP6_OPTION_INTERFACE_ID = 18, - SD_DHCP6_OPTION_RECONF_MSG = 19, - SD_DHCP6_OPTION_RECONF_ACCEPT = 20, - - SD_DHCP6_OPTION_DNS_SERVERS = 23, /* RFC 3646 */ - SD_DHCP6_OPTION_DOMAIN_LIST = 24, /* RFC 3646 */ - SD_DHCP6_OPTION_IA_PD = 25, /* RFC 3633, prefix delegation */ - SD_DHCP6_OPTION_IA_PD_PREFIX = 26, /* RFC 3633, prefix delegation */ - - SD_DHCP6_OPTION_SNTP_SERVERS = 31, /* RFC 4075, deprecated */ - SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME = 32, /* RFC 8415, sec. 21.23 */ - - /* option code 35 is unassigned */ - - SD_DHCP6_OPTION_FQDN = 39, /* RFC 4704 */ - - SD_DHCP6_OPTION_NTP_SERVER = 56, /* RFC 5908 */ - SD_DHCP6_OPTION_MUD_URL = 112, /* RFC 8250 */ - - /* option codes 89-142 are unassigned */ - /* option codes 144-65535 are unassigned */ -}; - -typedef struct sd_dhcp6_client sd_dhcp6_client; - -typedef void (*sd_dhcp6_client_callback_t)(sd_dhcp6_client *client, int event, void *userdata); -int sd_dhcp6_client_set_callback( - sd_dhcp6_client *client, - sd_dhcp6_client_callback_t cb, - void *userdata); - -int sd_dhcp6_client_set_ifindex( - 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 duid_type, - const void *duid, - size_t duid_len); -int sd_dhcp6_client_set_duid_llt( - sd_dhcp6_client *client, - uint64_t llt_time); -int sd_dhcp6_client_set_iaid( - sd_dhcp6_client *client, - uint32_t iaid); -int sd_dhcp6_client_get_iaid( - sd_dhcp6_client *client, - uint32_t *iaid); -int sd_dhcp6_client_duid_as_string( - sd_dhcp6_client *client, - char **duid); -int sd_dhcp6_client_set_fqdn( - sd_dhcp6_client *client, - const char *fqdn); -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_set_request_mud_url( - sd_dhcp6_client *client, - const char *mudurl); -int sd_dhcp6_client_set_request_user_class( - sd_dhcp6_client *client, - char** user_class); -int sd_dhcp6_client_set_request_vendor_class( - sd_dhcp6_client *client, - char** vendor_class); -int sd_dhcp6_client_set_prefix_delegation_hint( - sd_dhcp6_client *client, - uint8_t prefixlen, - const struct in6_addr *pd_address); -int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, - int *delegation); -int sd_dhcp6_client_set_prefix_delegation(sd_dhcp6_client *client, - int delegation); -int sd_dhcp6_client_get_address_request(sd_dhcp6_client *client, - int *request); -int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client, - int request); -int sd_dhcp6_client_set_transaction_id(sd_dhcp6_client *client, - uint32_t transaction_id); -int sd_dhcp6_client_add_vendor_option(sd_dhcp6_client *client, - sd_dhcp6_option *v); - -int sd_dhcp6_client_get_lease( - sd_dhcp6_client *client, - sd_dhcp6_lease **ret); - -int sd_dhcp6_client_add_option(sd_dhcp6_client *client, sd_dhcp6_option *v); - -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, - int64_t 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/core/systemd/src/systemd/sd-dhcp6-lease.h b/src/core/systemd/src/systemd/sd-dhcp6-lease.h deleted file mode 100644 index f77b31ac..00000000 --- a/src/core/systemd/src/systemd/sd-dhcp6-lease.h +++ /dev/null @@ -1,55 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef foosddhcp6leasehfoo -#define foosddhcp6leasehfoo - -/*** - Copyright © 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 -#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); -void sd_dhcp6_lease_reset_pd_prefix_iter(sd_dhcp6_lease *lease); -int sd_dhcp6_lease_get_pd(sd_dhcp6_lease *lease, struct in6_addr *prefix, - uint8_t *prefix_len, - uint32_t *lifetime_preferred, - uint32_t *lifetime_valid); - -int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, const 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, const struct in6_addr **addrs); -int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn); -int sd_dhcp6_lease_get_fqdn(sd_dhcp6_lease *lease, const char **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/core/systemd/src/systemd/sd-dhcp6-option.h b/src/core/systemd/src/systemd/sd-dhcp6-option.h deleted file mode 100644 index ddb2c7ce..00000000 --- a/src/core/systemd/src/systemd/sd-dhcp6-option.h +++ /dev/null @@ -1,37 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef foosddhcp6optionhfoo -#define foosddhcp6optionhfoo - -/*** - 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; - -typedef struct sd_dhcp6_option sd_dhcp6_option; - -int sd_dhcp6_option_new(uint16_t option, const void *data, size_t length, uint32_t enterprise_identifier, sd_dhcp6_option **ret); -sd_dhcp6_option *sd_dhcp6_option_ref(sd_dhcp6_option *ra); -sd_dhcp6_option *sd_dhcp6_option_unref(sd_dhcp6_option *ra); - -_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp6_option, sd_dhcp6_option_unref); - -_SD_END_DECLARATIONS; - -#endif diff --git a/src/core/systemd/src/systemd/sd-event.h b/src/core/systemd/src/systemd/sd-event.h deleted file mode 100644 index 2ae2a0da..00000000 --- a/src/core/systemd/src/systemd/sd-event.h +++ /dev/null @@ -1,176 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef foosdeventhfoo -#define foosdeventhfoo - -/*** - 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 - -#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, child PIDs, inotify events - - Supports systemd-style automatic watchdog event generation -*/ - -_SD_BEGIN_DECLARATIONS; - -#define SD_EVENT_DEFAULT ((sd_event *) 1) - -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); -#if defined _GNU_SOURCE || (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 199309L) -typedef int (*sd_event_child_handler_t)(sd_event_source *s, const siginfo_t *si, void *userdata); -#else -typedef void* sd_event_child_handler_t; -#endif -typedef int (*sd_event_inotify_handler_t)(sd_event_source *s, const struct inotify_event *event, void *userdata); -typedef _sd_destroy_t sd_event_destroy_t; - -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_time_relative(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_child_pidfd(sd_event *e, sd_event_source **s, int pidfd, int options, sd_event_child_handler_t callback, void *userdata); -int sd_event_add_inotify(sd_event *e, sd_event_source **s, const char *path, uint32_t mask, sd_event_inotify_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); -int sd_event_get_iteration(sd_event *e, uint64_t *ret); - -sd_event_source* sd_event_source_ref(sd_event_source *s); -sd_event_source* sd_event_source_unref(sd_event_source *s); -sd_event_source* sd_event_source_disable_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_fd_own(sd_event_source *s); -int sd_event_source_set_io_fd_own(sd_event_source *s, int own); -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_set_time_relative(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); -int sd_event_source_get_child_pidfd(sd_event_source *s); -int sd_event_source_get_child_pidfd_own(sd_event_source *s); -int sd_event_source_set_child_pidfd_own(sd_event_source *s, int own); -int sd_event_source_get_child_process_own(sd_event_source *s); -int sd_event_source_set_child_process_own(sd_event_source *s, int own); -#if defined _GNU_SOURCE || (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 199309L) -int sd_event_source_send_child_signal(sd_event_source *s, int sig, const siginfo_t *si, unsigned flags); -#else -int sd_event_source_send_child_signal(sd_event_source *s, int sig, const void *si, unsigned flags); -#endif -int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *ret); -int sd_event_source_set_destroy_callback(sd_event_source *s, sd_event_destroy_t callback); -int sd_event_source_get_destroy_callback(sd_event_source *s, sd_event_destroy_t *ret); -int sd_event_source_get_floating(sd_event_source *s); -int sd_event_source_set_floating(sd_event_source *s, int b); -int sd_event_source_get_exit_on_failure(sd_event_source *s); -int sd_event_source_set_exit_on_failure(sd_event_source *s, int b); -int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval_usec, unsigned burst); -int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval_usec, unsigned *ret_burst); -int sd_event_source_is_ratelimited(sd_event_source *s); - -/* 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_DEFINE_POINTER_CLEANUP_FUNC(sd_event_source, sd_event_source_disable_unref); - -_SD_END_DECLARATIONS; - -#endif diff --git a/src/core/systemd/src/systemd/sd-id128.h b/src/core/systemd/src/systemd/sd-id128.h deleted file mode 100644 index 02aa318a..00000000 --- a/src/core/systemd/src/systemd/sd-id128.h +++ /dev/null @@ -1,124 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef foosdid128hfoo -#define foosdid128hfoo - -/*** - 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_ARRAY_STATIC 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); -int sd_id128_get_invocation(sd_id128_t *ret); - -int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *ret); -int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret); - -#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 }} - -#define SD_ID128_MAKE(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) \ - ((const sd_id128_t) SD_ID128_ARRAY(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, 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] - -/* Like SD_ID128_FORMAT_STR, but formats as UUID, not in plain format */ -#define SD_ID128_UUID_FORMAT_STR "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" - -#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 }) - -#define SD_ID128_MAKE_STR(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \ - #a #b #c #d #e #f #g #h #i #j #k #l #m #n #o #p - -_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; -} - -_sd_pure_ static __inline__ int sd_id128_is_allf(sd_id128_t a) { - return a.qwords[0] == UINT64_C(0xFFFFFFFFFFFFFFFF) && a.qwords[1] == UINT64_C(0xFFFFFFFFFFFFFFFF); -} - -#define SD_ID128_NULL ((const sd_id128_t) { .qwords = { 0, 0 }}) -#define SD_ID128_ALLF ((const sd_id128_t) { .qwords = { UINT64_C(0xFFFFFFFFFFFFFFFF), UINT64_C(0xFFFFFFFFFFFFFFFF) }}) - -_SD_END_DECLARATIONS; - -#endif diff --git a/src/core/systemd/src/systemd/sd-ipv4acd.h b/src/core/systemd/src/systemd/sd-ipv4acd.h deleted file mode 100644 index 2809d874..00000000 --- a/src/core/systemd/src/systemd/sd-ipv4acd.h +++ /dev/null @@ -1,60 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef foosdipv4acdfoo -#define foosdipv4acdfoo - -/*** - Copyright © 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 -#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_callback_t)(sd_ipv4acd *acd, int event, void *userdata); - -int sd_ipv4acd_detach_event(sd_ipv4acd *acd); -int sd_ipv4acd_attach_event(sd_ipv4acd *acd, sd_event *event, int64_t priority); -int sd_ipv4acd_get_address(sd_ipv4acd *acd, struct in_addr *address); -int sd_ipv4acd_set_callback(sd_ipv4acd *acd, sd_ipv4acd_callback_t cb, void *userdata); -int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr); -int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int interface_index); -int sd_ipv4acd_get_ifindex(sd_ipv4acd *acd); -const char *sd_ipv4acd_get_ifname(sd_ipv4acd *acd); -int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address); -int sd_ipv4acd_is_running(sd_ipv4acd *acd); -int sd_ipv4acd_start(sd_ipv4acd *acd, bool reset_conflicts); -int sd_ipv4acd_stop(sd_ipv4acd *acd); -sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *acd); -sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *acd); -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/core/systemd/src/systemd/sd-ipv4ll.h b/src/core/systemd/src/systemd/sd-ipv4ll.h deleted file mode 100644 index aa4d174e..00000000 --- a/src/core/systemd/src/systemd/sd-ipv4ll.h +++ /dev/null @@ -1,62 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef foosdipv4llfoo -#define foosdipv4llfoo - -/*** - Copyright © 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 -#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_callback_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, int64_t priority); -int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address); -int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata); -int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr); -int sd_ipv4ll_set_ifindex(sd_ipv4ll *ll, int interface_index); -int sd_ipv4ll_get_ifindex(sd_ipv4ll *ll); -const char *sd_ipv4ll_get_ifname(sd_ipv4ll *ll); -int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address); -int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, uint64_t seed); -int sd_ipv4ll_is_running(sd_ipv4ll *ll); -int sd_ipv4ll_restart(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/core/systemd/src/systemd/sd-lldp.h b/src/core/systemd/src/systemd/sd-lldp.h deleted file mode 100644 index f551f6b4..00000000 --- a/src/core/systemd/src/systemd/sd-lldp.h +++ /dev/null @@ -1,194 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef foosdlldphfoo -#define foosdlldphfoo - -/*** - 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 "sd-event.h" - -#include "_sd-common.h" - -_SD_BEGIN_DECLARATIONS; - -/* IEEE 802.1AB-2009 Clause 8: TLV Types */ -enum { - SD_LLDP_TYPE_END = 0, - SD_LLDP_TYPE_CHASSIS_ID = 1, - SD_LLDP_TYPE_PORT_ID = 2, - SD_LLDP_TYPE_TTL = 3, - SD_LLDP_TYPE_PORT_DESCRIPTION = 4, - SD_LLDP_TYPE_SYSTEM_NAME = 5, - SD_LLDP_TYPE_SYSTEM_DESCRIPTION = 6, - SD_LLDP_TYPE_SYSTEM_CAPABILITIES = 7, - SD_LLDP_TYPE_MGMT_ADDRESS = 8, - SD_LLDP_TYPE_PRIVATE = 127, -}; - -/* IEEE 802.1AB-2009 Clause 8.5.2: Chassis subtypes */ -enum { - SD_LLDP_CHASSIS_SUBTYPE_RESERVED = 0, - SD_LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT = 1, - SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS = 2, - SD_LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT = 3, - SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS = 4, - SD_LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS = 5, - SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME = 6, - SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED = 7, -}; - -/* IEEE 802.1AB-2009 Clause 8.5.3: Port subtype */ -enum { - SD_LLDP_PORT_SUBTYPE_RESERVED = 0, - SD_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS = 1, - SD_LLDP_PORT_SUBTYPE_PORT_COMPONENT = 2, - SD_LLDP_PORT_SUBTYPE_MAC_ADDRESS = 3, - SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS = 4, - SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME = 5, - SD_LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID = 6, - SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7, -}; - -/* IEEE 802.1AB-2009 Clause 8.5.8: System capabilities */ -enum { - SD_LLDP_SYSTEM_CAPABILITIES_OTHER = 1 << 0, - SD_LLDP_SYSTEM_CAPABILITIES_REPEATER = 1 << 1, - SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE = 1 << 2, - SD_LLDP_SYSTEM_CAPABILITIES_WLAN_AP = 1 << 3, - SD_LLDP_SYSTEM_CAPABILITIES_ROUTER = 1 << 4, - SD_LLDP_SYSTEM_CAPABILITIES_PHONE = 1 << 5, - SD_LLDP_SYSTEM_CAPABILITIES_DOCSIS = 1 << 6, - SD_LLDP_SYSTEM_CAPABILITIES_STATION = 1 << 7, - SD_LLDP_SYSTEM_CAPABILITIES_CVLAN = 1 << 8, - SD_LLDP_SYSTEM_CAPABILITIES_SVLAN = 1 << 9, - SD_LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10, -}; - -#define SD_LLDP_SYSTEM_CAPABILITIES_ALL ((uint16_t) -1) - -#define SD_LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS \ - ((uint16_t) \ - (SD_LLDP_SYSTEM_CAPABILITIES_REPEATER| \ - SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE| \ - SD_LLDP_SYSTEM_CAPABILITIES_WLAN_AP| \ - SD_LLDP_SYSTEM_CAPABILITIES_ROUTER| \ - SD_LLDP_SYSTEM_CAPABILITIES_DOCSIS| \ - SD_LLDP_SYSTEM_CAPABILITIES_CVLAN| \ - SD_LLDP_SYSTEM_CAPABILITIES_SVLAN| \ - SD_LLDP_SYSTEM_CAPABILITIES_TPMR)) - -#define SD_LLDP_OUI_802_1 (uint8_t[]) { 0x00, 0x80, 0xc2 } -#define SD_LLDP_OUI_802_3 (uint8_t[]) { 0x00, 0x12, 0x0f } - -#define SD_LLDP_OUI_MUD (uint8_t[]) { 0x00, 0x00, 0x5E } -#define SD_LLDP_OUI_SUBTYPE_MUD_USAGE_DESCRIPTION 0x01 - -/* IEEE 802.1AB-2009 Annex E */ -enum { - SD_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID = 1, - SD_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID = 2, - SD_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME = 3, - SD_LLDP_OUI_802_1_SUBTYPE_PROTOCOL_IDENTITY = 4, - SD_LLDP_OUI_802_1_SUBTYPE_VID_USAGE_DIGEST = 5, - SD_LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID = 6, - SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7, -}; - -/* IEEE 802.1AB-2009 Annex F */ -enum { - SD_LLDP_OUI_802_3_SUBTYPE_MAC_PHY_CONFIG_STATUS = 1, - SD_LLDP_OUI_802_3_SUBTYPE_POWER_VIA_MDI = 2, - SD_LLDP_OUI_802_3_SUBTYPE_LINK_AGGREGATION = 3, - SD_LLDP_OUI_802_3_SUBTYPE_MAXIMUM_FRAME_SIZE = 4, -}; - -typedef struct sd_lldp sd_lldp; -typedef struct sd_lldp_neighbor sd_lldp_neighbor; - -typedef enum sd_lldp_event { - SD_LLDP_EVENT_ADDED, - SD_LLDP_EVENT_REMOVED, - SD_LLDP_EVENT_UPDATED, - SD_LLDP_EVENT_REFRESHED, - _SD_LLDP_EVENT_MAX, - _SD_LLDP_EVENT_INVALID = -1, -} sd_lldp_event; - -typedef void (*sd_lldp_callback_t)(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata); - -int sd_lldp_new(sd_lldp **ret); -sd_lldp* sd_lldp_ref(sd_lldp *lldp); -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, int64_t priority); -int sd_lldp_detach_event(sd_lldp *lldp); -sd_event *sd_lldp_get_event(sd_lldp *lldp); - -int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata); -int sd_lldp_set_ifindex(sd_lldp *lldp, int ifindex); - -/* Controls how much and what to store in the neighbors database */ -int sd_lldp_set_neighbors_max(sd_lldp *lldp, uint64_t n); -int sd_lldp_match_capabilities(sd_lldp *lldp, uint16_t mask); -int sd_lldp_set_filter_address(sd_lldp *lldp, const struct ether_addr *address); - -int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***neighbors); - -int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size); -sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n); -sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n); - -/* Access to LLDP frame metadata */ -int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address); -int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address); -int sd_lldp_neighbor_get_timestamp(sd_lldp_neighbor *n, clockid_t clock, uint64_t *ret); -int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size); - -/* High-level, direct, parsed out field access. These fields exist at most once, hence may be queried directly. */ -int sd_lldp_neighbor_get_chassis_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size); -int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret); -int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size); -int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const char **ret); -int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret_sec); -int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret); -int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret); -int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret); -int sd_lldp_neighbor_get_mud_url(sd_lldp_neighbor *n, const char **ret); -int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret); -int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret); - -/* Low-level, iterative TLV access. This is for everything else, it iteratively goes through all available TLVs - * (including the ones covered with the calls above), and allows multiple TLVs for the same fields. */ -int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n); -int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n); -int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type); -int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type); -int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t *subtype); -int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[_SD_ARRAY_STATIC 3], uint8_t subtype); -int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size); - -_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp, sd_lldp_unref); -_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp_neighbor, sd_lldp_neighbor_unref); - -_SD_END_DECLARATIONS; - -#endif diff --git a/src/core/systemd/src/systemd/sd-ndisc.h b/src/core/systemd/src/systemd/sd-ndisc.h deleted file mode 100644 index c0e37899..00000000 --- a/src/core/systemd/src/systemd/sd-ndisc.h +++ /dev/null @@ -1,131 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef foosdndiscfoo -#define foosdndiscfoo - -/*** - Copyright © 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 -#include - -#include "sd-event.h" - -#include "_sd-common.h" - -_SD_BEGIN_DECLARATIONS; - -/* Neighbor Discovery Options, RFC 4861, Section 4.6 and - * https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-5 */ -enum { - SD_NDISC_OPTION_SOURCE_LL_ADDRESS = 1, - SD_NDISC_OPTION_TARGET_LL_ADDRESS = 2, - SD_NDISC_OPTION_PREFIX_INFORMATION = 3, - SD_NDISC_OPTION_MTU = 5, - SD_NDISC_OPTION_ROUTE_INFORMATION = 24, - SD_NDISC_OPTION_RDNSS = 25, - SD_NDISC_OPTION_FLAGS_EXTENSION = 26, - SD_NDISC_OPTION_DNSSL = 31, - SD_NDISC_OPTION_CAPTIVE_PORTAL = 37, -}; - -/* Route preference, RFC 4191, Section 2.1 */ -enum { - SD_NDISC_PREFERENCE_LOW = 3U, - SD_NDISC_PREFERENCE_MEDIUM = 0U, - SD_NDISC_PREFERENCE_HIGH = 1U, -}; - -typedef struct sd_ndisc sd_ndisc; -typedef struct sd_ndisc_router sd_ndisc_router; - -typedef enum sd_ndisc_event { - SD_NDISC_EVENT_TIMEOUT, - SD_NDISC_EVENT_ROUTER, - _SD_NDISC_EVENT_MAX, - _SD_NDISC_EVENT_INVALID = -1, -} sd_ndisc_event; - -typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata); - -int sd_ndisc_new(sd_ndisc **ret); -sd_ndisc *sd_ndisc_ref(sd_ndisc *nd); -sd_ndisc *sd_ndisc_unref(sd_ndisc *nd); - -int sd_ndisc_start(sd_ndisc *nd); -int sd_ndisc_stop(sd_ndisc *nd); - -int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority); -int sd_ndisc_detach_event(sd_ndisc *nd); -sd_event *sd_ndisc_get_event(sd_ndisc *nd); - -int sd_ndisc_set_callback(sd_ndisc *nd, sd_ndisc_callback_t cb, void *userdata); -int sd_ndisc_set_ifindex(sd_ndisc *nd, int interface_index); -int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr); - -int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *ret); -int sd_ndisc_get_hop_limit(sd_ndisc *nd, uint8_t *ret); - -int sd_ndisc_router_from_raw(sd_ndisc_router **ret, const void *raw, size_t raw_size); -sd_ndisc_router *sd_ndisc_router_ref(sd_ndisc_router *rt); -sd_ndisc_router *sd_ndisc_router_unref(sd_ndisc_router *rt); - -int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr); -int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret); -int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size); - -int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret); -int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret_flags); -int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret); -int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint16_t *ret_lifetime); -int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret); - -/* Generic option access */ -int sd_ndisc_router_option_rewind(sd_ndisc_router *rt); -int sd_ndisc_router_option_next(sd_ndisc_router *rt); -int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret); -int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type); -int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size); - -/* Specific option access: SD_NDISC_OPTION_PREFIX_INFORMATION */ -int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router *rt, uint32_t *ret); -int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router *rt, uint32_t *ret); -int sd_ndisc_router_prefix_get_flags(sd_ndisc_router *rt, uint8_t *ret); -int sd_ndisc_router_prefix_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr); -int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router *rt, unsigned *prefixlen); - -/* Specific option access: SD_NDISC_OPTION_ROUTE_INFORMATION */ -int sd_ndisc_router_route_get_lifetime(sd_ndisc_router *rt, uint32_t *ret); -int sd_ndisc_router_route_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr); -int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router *rt, unsigned *prefixlen); -int sd_ndisc_router_route_get_preference(sd_ndisc_router *rt, unsigned *ret); - -/* Specific option access: SD_NDISC_OPTION_RDNSS */ -int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret); -int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint32_t *ret); - -/* Specific option access: SD_NDISC_OPTION_DNSSL */ -int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret); -int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint32_t *ret); - -_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc, sd_ndisc_unref); -_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc_router, sd_ndisc_router_unref); - -_SD_END_DECLARATIONS; - -#endif diff --git a/src/core/tests/config/test-config.c b/src/core/tests/config/test-config.c index 3bb14815..6794fbf6 100644 --- a/src/core/tests/config/test-config.c +++ b/src/core/tests/config/test-config.c @@ -151,6 +151,7 @@ test_config_simple(void) gs_unref_object NMConfig *config = NULL; gs_strfreev char ** plugins = NULL; char * value; + const char * cvalue; gs_unref_object NMDevice *dev50 = nm_test_device_new("00:00:00:00:00:50"); 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"); @@ -206,59 +207,50 @@ test_config_simple(void) g_assert_cmpstr(value, ==, "51"); g_free(value); - value = nm_config_data_get_connection_default(nm_config_get_data_orig(config), - "ipv6.route-metric", - NULL); - g_assert_cmpstr(value, ==, NULL); - g_free(value); - - value = nm_config_data_get_connection_default(nm_config_get_data_orig(config), - "ipv4.route-metric", - NULL); - g_assert_cmpstr(value, ==, "50"); - g_free(value); - - value = nm_config_data_get_connection_default(nm_config_get_data_orig(config), - "ipv4.route-metric", - dev50); - g_assert_cmpstr(value, ==, "50"); - g_free(value); - - value = nm_config_data_get_connection_default(nm_config_get_data_orig(config), - "ipv4.route-metric", - dev51); - g_assert_cmpstr(value, ==, "51"); - g_free(value); - - value = nm_config_data_get_connection_default(nm_config_get_data_orig(config), - "ipv4.route-metric", - dev52); - g_assert_cmpstr(value, ==, "52"); - g_free(value); - - value = nm_config_data_get_connection_default(nm_config_get_data_orig(config), - "ethernet.mtu", - dev51); - g_assert_cmpstr(value, ==, "9000"); - g_free(value); - - value = nm_config_data_get_connection_default(nm_config_get_data_orig(config), - "ethernet.mtu", - dev50); - g_assert_cmpstr(value, ==, "1400"); - g_free(value); - - value = nm_config_data_get_connection_default(nm_config_get_data_orig(config), - "ipv4.dns-priority", - dev51); - g_assert_cmpstr(value, ==, NULL); - g_free(value); - - value = nm_config_data_get_connection_default(nm_config_get_data_orig(config), - "ipv4.dns-priority", - dev50); - g_assert_cmpstr(value, ==, "60"); - g_free(value); + cvalue = nm_config_data_get_connection_default(nm_config_get_data_orig(config), + "ipv6.route-metric", + NULL); + g_assert_cmpstr(cvalue, ==, NULL); + + cvalue = nm_config_data_get_connection_default(nm_config_get_data_orig(config), + "ipv4.route-metric", + NULL); + g_assert_cmpstr(cvalue, ==, "50"); + + cvalue = nm_config_data_get_connection_default(nm_config_get_data_orig(config), + "ipv4.route-metric", + dev50); + g_assert_cmpstr(cvalue, ==, "50"); + + cvalue = nm_config_data_get_connection_default(nm_config_get_data_orig(config), + "ipv4.route-metric", + dev51); + g_assert_cmpstr(cvalue, ==, "51"); + + cvalue = nm_config_data_get_connection_default(nm_config_get_data_orig(config), + "ipv4.route-metric", + dev52); + g_assert_cmpstr(cvalue, ==, "52"); + + cvalue = nm_config_data_get_connection_default(nm_config_get_data_orig(config), + "ethernet.mtu", + dev51); + g_assert_cmpstr(cvalue, ==, "9000"); + + cvalue = nm_config_data_get_connection_default(nm_config_get_data_orig(config), + "ethernet.mtu", + dev50); + g_assert_cmpstr(cvalue, ==, "1400"); + + cvalue = nm_config_data_get_connection_default(nm_config_get_data_orig(config), + "ipv4.dns-priority", + dev51); + g_assert_cmpstr(cvalue, ==, NULL); + + cvalue = nm_config_data_get_connection_default(nm_config_get_data_orig(config), + "ipv4.dns-priority", + dev50); + g_assert_cmpstr(cvalue, ==, "60"); } static void @@ -616,7 +608,7 @@ test_config_confdir(void) #define ASSERT_GET_CONN_DEFAULT(xconfig, xname, xvalue) \ G_STMT_START \ { \ - gs_free char *_value = \ + const char *_value = \ nm_config_data_get_connection_default(nm_config_get_data_orig(xconfig), \ (xname), \ NULL); \ diff --git a/src/core/tests/meson.build b/src/core/tests/meson.build index 994563c4..316f20cc 100644 --- a/src/core/tests/meson.build +++ b/src/core/tests/meson.build @@ -37,11 +37,15 @@ exe = executable( src_inc, ], dependencies: [ - libnm_systemd_core_dep, - libnm_systemd_shared_dep, + libnm_systemd_shared_dep_inc, + libnm_systemd_core_dep_inc, + glib_dep, ], - c_args: [ - '-DG_LOG_DOMAIN="test"', + link_with: [ + libnm_systemd_shared, + libnm_systemd_core, + libnm_log_null, + libc_siphash, ], ) diff --git a/src/core/tests/test-core-with-expect.c b/src/core/tests/test-core-with-expect.c index 022cf8f3..01784863 100644 --- a/src/core/tests/test-core-with-expect.c +++ b/src/core/tests/test-core-with-expect.c @@ -11,6 +11,7 @@ #include #include "NetworkManagerUtils.h" +#include "libnm-platform/nm-platform-utils.h" #include "nm-test-utils-core.h" @@ -586,7 +587,7 @@ test_nm_ethernet_address_is_valid(void) /*****************************************************************************/ static void -test_nm_utils_new_vlan_name(void) +test_nmp_utils_new_vlan_name(void) { guint i, j; const char *parent_names[] = { @@ -614,7 +615,7 @@ test_nm_utils_new_vlan_name(void) vlan_id_s = g_strdup_printf(".%d", vlan_id); - ifname = nm_utils_new_vlan_name(parent_names[i], vlan_id); + ifname = nmp_utils_new_vlan_name(parent_names[i], vlan_id); g_assert(ifname && ifname[0]); g_assert_cmpint(strlen(ifname), ==, @@ -643,7 +644,7 @@ main(int argc, char **argv) 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_utils_new_vlan_name", test_nm_utils_new_vlan_name); + g_test_add_func("/general/nmp_utils_new_vlan_name", test_nmp_utils_new_vlan_name); return g_test_run(); } diff --git a/src/core/tests/test-core.c b/src/core/tests/test-core.c index 8698c406..f28c4178 100644 --- a/src/core/tests/test-core.c +++ b/src/core/tests/test-core.c @@ -11,16 +11,36 @@ /* need math.h for isinf() and INFINITY. No need to link with -lm */ #include +#include "libnm-glib-aux/nm-uuid.h" #include "NetworkManagerUtils.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-core-utils.h" -#include "systemd/nm-sd-utils-core.h" +#include "libnm-systemd-core/nm-sd-utils-core.h" #include "dns/nm-dns-manager.h" #include "nm-connectivity.h" #include "nm-test-utils-core.h" +/*****************************************************************************/ + +static void +test_config_h(void) +{ +#define ABSOLUTE_PATH(path) \ + G_STMT_START \ + { \ + g_assert_cmpstr("" path "", !=, ""); \ + g_assert("" path ""[0] == '/'); \ + } \ + G_STMT_END + + ABSOLUTE_PATH(IPTABLES_PATH); + ABSOLUTE_PATH(NFT_PATH); +} + +/*****************************************************************************/ + /* Reference implementation for nm_utils_ip6_address_clear_host_address. * Taken originally from set_address_masked(), src/ndisc/nm-lndp-ndisc.c **/ @@ -867,7 +887,7 @@ test_connection_no_match_vlan(void) /* 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); + 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); @@ -2231,7 +2251,7 @@ test_utils_file_is_in_path(void) g_assert(!nm_utils_file_is_in_path("//b///a/", "/b//")); g_assert(!nm_utils_file_is_in_path("//b///a/", "/b/a/")); g_assert(!nm_utils_file_is_in_path("//b///a", "/b/a/")); - g_assert(nm_utils_file_is_in_path("//b///a/.", "/b/a/")); + g_assert(!nm_utils_file_is_in_path("//b///a/.", "/b/a/")); g_assert(nm_utils_file_is_in_path("//b///a/..", "/b/a/")); } @@ -2569,6 +2589,8 @@ main(int argc, char **argv) { nmtst_init_with_logging(&argc, &argv, NULL, "ALL"); + g_test_add_func("/general/test_config_h", test_config_h); + g_test_add_func("/general/test_logging_domains", test_logging_domains); g_test_add_func("/general/test_logging_error", test_logging_error); diff --git a/src/core/tests/test-ip4-config.c b/src/core/tests/test-ip4-config.c index 27b1d611..3a095d4a 100644 --- a/src/core/tests/test-ip4-config.c +++ b/src/core/tests/test-ip4-config.c @@ -8,7 +8,7 @@ #include #include "nm-ip4-config.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-test-utils-core.h" diff --git a/src/core/tests/test-ip6-config.c b/src/core/tests/test-ip6-config.c index 3b48fb7f..ddf4c789 100644 --- a/src/core/tests/test-ip6-config.c +++ b/src/core/tests/test-ip6-config.c @@ -10,7 +10,7 @@ #include "nm-ip6-config.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-test-utils-core.h" static NMIP6Config * diff --git a/src/core/tests/test-l3cfg.c b/src/core/tests/test-l3cfg.c index 43132c6d..ba065c09 100644 --- a/src/core/tests/test-l3cfg.c +++ b/src/core/tests/test-l3cfg.c @@ -5,7 +5,7 @@ #include "nm-l3cfg.h" #include "nm-l3-ipv4ll.h" #include "nm-netns.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "platform/tests/test-common.h" @@ -82,8 +82,8 @@ _test_fixture_1_setup(TestFixture1 *f, int test_idx) f->hwaddr0 = l0->l_address; f->hwaddr1 = l1->l_address; - g_assert(nm_platform_link_set_up(f->platform, f->ifindex0, NULL)); - g_assert(nm_platform_link_set_up(f->platform, f->ifindex1, NULL)); + g_assert(nm_platform_link_change_flags(f->platform, f->ifindex0, IFF_UP, TRUE) >= 0); + g_assert(nm_platform_link_change_flags(f->platform, f->ifindex1, IFF_UP, TRUE) >= 0); return f; } @@ -187,6 +187,12 @@ _test_l3cfg_signal_notify(NML3Cfg * l3cfg, nm_assert(NM_IS_L3_CONFIG_DATA(ti->l3cd)); nm_assert(ti->tag); } + } else if (notify_data->notify_type == NM_L3_CONFIG_NOTIFY_TYPE_L3CD_CHANGED) { + g_assert(!notify_data->l3cd_changed.l3cd_old + || NM_IS_L3_CONFIG_DATA(notify_data->l3cd_changed.l3cd_old)); + g_assert(!notify_data->l3cd_changed.l3cd_new + || NM_IS_L3_CONFIG_DATA(notify_data->l3cd_changed.l3cd_new)); + return; } switch (tdata->notify_type) { diff --git a/src/core/tests/test-systemd.c b/src/core/tests/test-systemd.c index 03576c13..12d2b911 100644 --- a/src/core/tests/test-systemd.c +++ b/src/core/tests/test-systemd.c @@ -3,68 +3,12 @@ * Copyright (C) 2016 Red Hat, Inc. */ -#include "src/core/systemd/nm-default-systemd.h" +#include "libnm-systemd-core/nm-default-systemd-core.h" -#include "systemd/nm-sd.h" -#include "systemd/nm-sd-utils-shared.h" +#include "libnm-systemd-core/nm-sd.h" +#include "libnm-systemd-shared/nm-sd-utils-shared.h" -#include "nm-test-utils-core.h" - -/***************************************************************************** - * Stub implementations of libNetworkManagerBase symbols - *****************************************************************************/ - -gboolean -nm_utils_get_testing_initialized(void) -{ - return TRUE; -} - -void -_nm_utils_set_testing(NMUtilsTestFlags flags) -{ - g_assert_not_reached(); -} - -gint32 -nm_utils_get_monotonic_timestamp_sec(void) -{ - return 1; -} - -NMLogDomain _nm_logging_enabled_state[_LOGL_N_REAL]; - -gboolean -_nm_log_enabled_impl(gboolean mt_require_locking, NMLogLevel level, NMLogDomain domain) -{ - return FALSE; -} - -void -_nm_log_impl(const char *file, - guint line, - const char *func, - gboolean mt_require_locking, - NMLogLevel level, - NMLogDomain domain, - int error, - const char *ifname, - const char *con_uuid, - const char *fmt, - ...) -{} - -gboolean -nm_logging_setup(const char *level, const char *domains, char **bad_domains, GError **error) -{ - return TRUE; -} - -const char * -nm_strerror_native(int errsv) -{ - return g_strerror(errsv); -} +#include "libnm-glib-aux/nm-test-utils.h" /*****************************************************************************/ @@ -178,46 +122,34 @@ test_sd_event(void) static void test_path_equal(void) { -#define _path_equal_check1(path, kill_dots, expected) \ - G_STMT_START \ - { \ - const gboolean _kill_dots = (kill_dots); \ - const char * _path0 = (path); \ - const char * _expected = (expected); \ - gs_free char * _path = g_strdup(_path0); \ - const char * _path_result; \ - \ - if (!_kill_dots && !nm_sd_utils_path_equal(_path0, _expected)) \ - g_error("Paths \"%s\" and \"%s\" don't compare equal", _path0, _expected); \ - \ - _path_result = nm_sd_utils_path_simplify(_path, _kill_dots); \ - g_assert(_path_result == _path); \ - g_assert_cmpstr(_path, ==, _expected); \ - } \ - G_STMT_END - -#define _path_equal_check(path, expected_no_kill_dots, expected_kill_dots) \ - G_STMT_START \ - { \ - _path_equal_check1(path, FALSE, expected_no_kill_dots); \ - _path_equal_check1(path, TRUE, expected_kill_dots ?: expected_no_kill_dots); \ - } \ +#define _path_equal_check(path, expected) \ + G_STMT_START \ + { \ + const char * _path0 = (path); \ + const char * _expected = (expected); \ + gs_free char *_path = g_strdup(_path0); \ + const char * _path_result; \ + \ + _path_result = nm_sd_utils_path_simplify(_path); \ + g_assert(_path_result == _path); \ + g_assert_cmpstr(_path, ==, _expected); \ + } \ G_STMT_END - _path_equal_check("", "", NULL); - _path_equal_check(".", ".", NULL); - _path_equal_check("..", "..", NULL); - _path_equal_check("/..", "/..", NULL); - _path_equal_check("//..", "/..", NULL); - _path_equal_check("/.", "/.", "/"); - _path_equal_check("./", ".", "."); - _path_equal_check("./.", "./.", "."); - _path_equal_check(".///.", "./.", "."); - _path_equal_check(".///./", "./.", "."); - _path_equal_check(".////", ".", "."); - _path_equal_check("//..//foo/", "/../foo", NULL); - _path_equal_check("///foo//./bar/.", "/foo/./bar/.", "/foo/bar"); - _path_equal_check(".//./foo//./bar/.", "././foo/./bar/.", "foo/bar"); + _path_equal_check("", ""); + _path_equal_check(".", "."); + _path_equal_check("..", ".."); + _path_equal_check("/..", "/.."); + _path_equal_check("//..", "/.."); + _path_equal_check("/.", "/"); + _path_equal_check("./", "."); + _path_equal_check("./.", "."); + _path_equal_check(".///.", "."); + _path_equal_check(".///./", "."); + _path_equal_check(".////", "."); + _path_equal_check("//..//foo/", "/../foo"); + _path_equal_check("///foo//./bar/.", "/foo/bar"); + _path_equal_check(".//./foo//./bar/.", "foo/bar"); } /*****************************************************************************/ @@ -247,11 +179,11 @@ _test_unbase64mem_mem(const char *base64, const guint8 *expected_arr, gsize expe { gs_free char *expected_base64 = NULL; int r; - gs_free guint8 *exp2_arr = NULL; - gs_free guint8 *exp3_arr = NULL; - gsize exp2_len; - gsize exp3_len; - gsize i; + nm_auto_free guint8 *exp2_arr = NULL; + nm_auto_free guint8 *exp3_arr = NULL; + gsize exp2_len; + gsize exp3_len; + gsize i; expected_base64 = g_base64_encode(expected_arr, expected_len); @@ -327,7 +259,7 @@ NMTST_DEFINE(); int main(int argc, char **argv) { - nmtst_init_assert_logging(&argc, &argv, "INFO", "ALL"); + nmtst_init(&argc, &argv, TRUE); g_test_add_func("/systemd/dhcp/create", test_dhcp_create); g_test_add_func("/systemd/lldp/create", test_lldp_create); diff --git a/src/core/vpn/nm-vpn-connection.c b/src/core/vpn/nm-vpn-connection.c index 02831b08..d06ca46a 100644 --- a/src/core/vpn/nm-vpn-connection.c +++ b/src/core/vpn/nm-vpn-connection.c @@ -14,21 +14,22 @@ #include #include #include +#include #include #include "nm-proxy-config.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" -#include "platform/nm-platform.h" +#include "libnm-platform/nm-platform.h" #include "nm-active-connection.h" #include "NetworkManagerUtils.h" #include "settings/nm-settings-connection.h" #include "nm-dispatcher.h" #include "nm-netns.h" #include "settings/nm-agent-manager.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" #include "nm-pacrunner-manager.h" -#include "nm-firewall-manager.h" +#include "nm-firewalld-manager.h" #include "nm-config.h" #include "nm-vpn-plugin-info.h" #include "nm-vpn-manager.h" @@ -95,7 +96,7 @@ typedef struct { NMVpnPluginInfo * plugin_info; char * bus_name; - NMFirewallManagerCallId *fw_call; + NMFirewalldManagerCallId *fw_call; NMNetns *netns; @@ -341,7 +342,7 @@ fw_call_cleanup(NMVpnConnection *self) NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); if (priv->fw_call) { - nm_firewall_manager_cancel_call(priv->fw_call); + nm_firewalld_manager_cancel_call(priv->fw_call); g_warn_if_fail(!priv->fw_call); priv->fw_call = NULL; } @@ -371,7 +372,7 @@ vpn_cleanup(NMVpnConnection *self, NMDevice *parent_dev) if (priv->ip_ifindex) { NMPlatform *platform = nm_netns_get_platform(priv->netns); - nm_platform_link_set_down(platform, priv->ip_ifindex); + nm_platform_link_change_flags(platform, priv->ip_ifindex, IFF_UP, FALSE); nm_platform_ip_route_flush(platform, AF_UNSPEC, priv->ip_ifindex); nm_platform_ip_address_flush(platform, AF_UNSPEC, priv->ip_ifindex); } @@ -380,11 +381,11 @@ vpn_cleanup(NMVpnConnection *self, NMDevice *parent_dev) /* Remove zone from firewall */ if (priv->ip_iface) { - nm_firewall_manager_remove_from_zone(nm_firewall_manager_get(), - priv->ip_iface, - NULL, - NULL, - NULL); + nm_firewalld_manager_remove_from_zone(nm_firewalld_manager_get(), + priv->ip_iface, + NULL, + NULL, + NULL); } /* Cancel pending firewall call */ fw_call_cleanup(self); @@ -398,11 +399,6 @@ vpn_cleanup(NMVpnConnection *self, NMDevice *parent_dev) 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. - */ - nm_active_connection_clear_secrets(NM_ACTIVE_CONNECTION(self)); } static void @@ -964,11 +960,6 @@ plugin_state_changed(NMVpnConnection *self, NMVpnServiceState 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_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; @@ -1157,7 +1148,10 @@ nm_vpn_connection_apply_config(NMVpnConnection *self) apply_parent_device_config(self); if (priv->ip_ifindex > 0) { - nm_platform_link_set_up(nm_netns_get_platform(priv->netns), priv->ip_ifindex, NULL); + nm_platform_link_change_flags(nm_netns_get_platform(priv->netns), + priv->ip_ifindex, + IFF_UP, + TRUE); if (priv->ip4_config) { nm_assert(priv->ip_ifindex == nm_ip4_config_get_ifindex(priv->ip4_config)); @@ -1211,10 +1205,10 @@ _cleanup_failed_config(NMVpnConnection *self) } static void -fw_change_zone_cb(NMFirewallManager * firewall_manager, - NMFirewallManagerCallId *call_id, - GError * error, - gpointer user_data) +fw_change_zone_cb(NMFirewalldManager * firewalld_manager, + NMFirewalldManagerCallId *call_id, + GError * error, + gpointer user_data) { NMVpnConnection * self = user_data; NMVpnConnectionPrivate *priv; @@ -1270,12 +1264,12 @@ nm_vpn_connection_config_maybe_complete(NMVpnConnection *self, gboolean success) 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, - self); + priv->fw_call = nm_firewalld_manager_add_or_change_zone(nm_firewalld_manager_get(), + priv->ip_iface, + zone, + FALSE, + fw_change_zone_cb, + self); return; } else if (nm_vpn_connection_apply_config(self)) return; @@ -1632,7 +1626,7 @@ nm_vpn_connection_ip4_config_get(NMVpnConnection *self, GVariant *dict) route.metric = route_metric; route.rt_source = NM_IP_CONFIG_SOURCE_VPN; - if (plen > 32 || plen == 0) + if (plen > 32) break; route.plen = plen; route.network = nm_utils_ip4_address_clear_host_address(route.network, plen); @@ -1825,7 +1819,7 @@ nm_vpn_connection_ip6_config_get(NMVpnConnection *self, GVariant *dict) if (!ip6_addr_from_variant(dest, &route.network)) goto next; - if (prefix > 128 || prefix == 0) + if (prefix > 128) goto next; route.plen = prefix; @@ -2912,16 +2906,14 @@ static const GDBusSignalInfo signal_info_vpn_state_changed = NM_DEFINE_GDBUS_SIG static const NMDBusInterfaceInfoExtended interface_info_vpn_connection = { .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( NM_DBUS_INTERFACE_VPN_CONNECTION, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, - &signal_info_vpn_state_changed, ), + .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&signal_info_vpn_state_changed, ), .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("VpnState", - "u", - NM_VPN_CONNECTION_VPN_STATE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Banner", - "s", - NM_VPN_CONNECTION_BANNER), ), ), - .legacy_property_changed = TRUE, + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("VpnState", + "u", + NM_VPN_CONNECTION_VPN_STATE), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Banner", + "s", + NM_VPN_CONNECTION_BANNER), ), ), }; static void diff --git a/src/core/vpn/nm-vpn-connection.h b/src/core/vpn/nm-vpn-connection.h index 66ec7eec..0209ea3d 100644 --- a/src/core/vpn/nm-vpn-connection.h +++ b/src/core/vpn/nm-vpn-connection.h @@ -9,7 +9,7 @@ #include "nm-vpn-dbus-interface.h" #include "devices/nm-device.h" -#include "nm-libnm-core-intern/nm-auth-subject.h" +#include "libnm-core-aux-intern/nm-auth-subject.h" #include "nm-active-connection.h" #include "nm-vpn-plugin-info.h" diff --git a/src/core/vpn/nm-vpn-manager.c b/src/core/vpn/nm-vpn-manager.c index 53fe58dd..f30dba79 100644 --- a/src/core/vpn/nm-vpn-manager.c +++ b/src/core/vpn/nm-vpn-manager.c @@ -12,7 +12,7 @@ #include "nm-vpn-connection.h" #include "nm-setting-vpn.h" #include "nm-vpn-dbus-interface.h" -#include "nm-core-internal.h" +#include "libnm-core-intern/nm-core-internal.h" typedef struct { GSList * plugins; -- cgit 1.3.0-6-gf8a5