From 8b2905fcce86ed2bfa7214676d7a945098a1ba82 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 22 Sep 2020 20:32:14 +0200 Subject: core: use NML3ConfigData (WIP) --- .gitignore | 2 +- Makefile.am | 20 +- WIP.txt | 13 + src/core/README.l3cfg.md | 332 ++ src/core/devices/adsl/nm-device-adsl.c | 52 +- src/core/devices/bluetooth/nm-device-bt.c | 27 +- src/core/devices/nm-acd-manager.c | 496 --- src/core/devices/nm-acd-manager.h | 34 - src/core/devices/nm-device-bond.c | 1 - src/core/devices/nm-device-dummy.c | 1 - src/core/devices/nm-device-ethernet.c | 40 +- src/core/devices/nm-device-infiniband.c | 1 - src/core/devices/nm-device-ip-tunnel.c | 1 - src/core/devices/nm-device-macvlan.c | 1 - src/core/devices/nm-device-ppp.c | 69 +- src/core/devices/nm-device-private.h | 16 +- src/core/devices/nm-device-tun.c | 1 - src/core/devices/nm-device-vlan.c | 2 - src/core/devices/nm-device-vxlan.c | 1 - src/core/devices/nm-device-wireguard.c | 74 +- src/core/devices/nm-device-wpan.c | 1 - src/core/devices/nm-device.c | 5323 +++++++++--------------- src/core/devices/nm-device.h | 23 +- src/core/devices/ovs/nm-device-ovs-bridge.c | 8 +- src/core/devices/ovs/nm-device-ovs-interface.c | 10 +- src/core/devices/ovs/nm-device-ovs-port.c | 8 +- src/core/devices/team/nm-device-team.c | 1 - src/core/devices/tests/meson.build | 1 - src/core/devices/tests/test-acd.c | 259 -- src/core/devices/wifi/nm-device-wifi-p2p.c | 11 +- src/core/devices/wifi/nm-device-wifi.c | 11 +- src/core/devices/wwan/nm-device-modem.c | 105 +- src/core/devices/wwan/nm-modem-broadband.c | 258 +- src/core/devices/wwan/nm-modem-ofono.c | 120 +- src/core/devices/wwan/nm-modem.c | 377 +- src/core/devices/wwan/nm-modem.h | 42 +- src/core/dhcp/nm-dhcp-client.c | 199 +- src/core/dhcp/nm-dhcp-client.h | 17 +- src/core/dhcp/nm-dhcp-dhclient-utils.c | 1 - src/core/dhcp/nm-dhcp-manager.c | 32 +- src/core/dhcp/nm-dhcp-manager.h | 5 - src/core/dhcp/nm-dhcp-nettools.c | 243 +- src/core/dhcp/nm-dhcp-systemd.c | 267 +- src/core/dhcp/nm-dhcp-utils.c | 306 +- src/core/dhcp/nm-dhcp-utils.h | 31 +- src/core/dhcp/tests/test-dhcp-dhclient.c | 1 - src/core/dhcp/tests/test-dhcp-utils.c | 567 ++- src/core/dns/nm-dns-dnsmasq.c | 33 +- src/core/dns/nm-dns-manager.c | 539 +-- src/core/dns/nm-dns-manager.h | 18 +- src/core/dns/nm-dns-systemd-resolved.c | 64 +- src/core/dnsmasq/nm-dnsmasq-manager.c | 51 +- src/core/dnsmasq/nm-dnsmasq-manager.h | 10 +- src/core/meson.build | 4 - src/core/ndisc/nm-ndisc.c | 102 +- src/core/ndisc/nm-ndisc.h | 7 +- src/core/nm-act-request.c | 38 +- src/core/nm-act-request.h | 8 - src/core/nm-connectivity.c | 1 + src/core/nm-dhcp-config.c | 58 +- src/core/nm-dhcp-config.h | 2 +- src/core/nm-dispatcher.c | 178 +- src/core/nm-dispatcher.h | 8 +- src/core/nm-iface-helper.c | 22 +- src/core/nm-ip-config.c | 459 +- src/core/nm-ip-config.h | 45 +- src/core/nm-ip4-config.c | 3297 --------------- src/core/nm-ip4-config.h | 667 --- src/core/nm-ip6-config.c | 2711 ------------ src/core/nm-ip6-config.h | 208 - src/core/nm-manager.c | 2 - src/core/nm-pacrunner-manager.c | 94 +- src/core/nm-pacrunner-manager.h | 7 +- src/core/nm-policy.c | 319 +- src/core/nm-proxy-config.c | 172 - src/core/nm-proxy-config.h | 41 - src/core/nm-types.h | 3 - src/core/ppp/nm-ppp-manager-call.c | 18 - src/core/ppp/nm-ppp-manager-call.h | 6 - src/core/ppp/nm-ppp-manager.c | 171 +- src/core/ppp/nm-ppp-manager.h | 3 +- src/core/ppp/nm-ppp-plugin-api.h | 6 - src/core/tests/test-ip4-config.c | 1 - src/core/tests/test-ip6-config.c | 2 - src/core/vpn/nm-vpn-connection.c | 709 ++-- src/core/vpn/nm-vpn-connection.h | 4 +- src/libnm-systemd-core/meson.build | 2 - src/libnm-systemd-core/nm-sd.h | 1 - tools/run-nm-test.sh | 1 - 89 files changed, 5247 insertions(+), 14256 deletions(-) create mode 100644 WIP.txt create mode 100644 src/core/README.l3cfg.md delete mode 100644 src/core/devices/nm-acd-manager.c delete mode 100644 src/core/devices/nm-acd-manager.h delete mode 100644 src/core/devices/tests/test-acd.c delete mode 100644 src/core/nm-ip4-config.c delete mode 100644 src/core/nm-ip4-config.h delete mode 100644 src/core/nm-ip6-config.c delete mode 100644 src/core/nm-ip6-config.h delete mode 100644 src/core/nm-proxy-config.c delete mode 100644 src/core/nm-proxy-config.h diff --git a/.gitignore b/.gitignore index 22f745efe9..da3032c3d5 100644 --- a/.gitignore +++ b/.gitignore @@ -233,7 +233,6 @@ test-*.trs /src/core/NetworkManager-all-sym /src/core/NetworkManager.ver /src/core/devices/bluetooth/tests/nm-bt-test -/src/core/devices/tests/test-acd /src/core/devices/tests/test-lldp /src/core/devices/wifi/tests/test-devices-wifi /src/core/devices/wwan/tests/test-service-providers @@ -399,6 +398,7 @@ test-*.trs /src/NetworkManager /src/NetworkManager-all-sym /src/NetworkManager.ver +/src/core/devices/tests/test-acd /src/core/initrd/nm-initrd-generator /src/core/initrd/tests/test-cmdline-reader /src/core/initrd/tests/test-dt-reader diff --git a/Makefile.am b/Makefile.am index dbcd9816e7..eeffa46a98 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2309,8 +2309,6 @@ src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \ src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-lease.c \ src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c \ src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c \ - src/libnm-systemd-core/src/libsystemd-network/sd-ipv4acd.c \ - src/libnm-systemd-core/src/libsystemd-network/sd-ipv4ll.c \ src/libnm-systemd-core/src/libsystemd-network/sd-lldp.c \ src/libnm-systemd-core/src/libsystemd/sd-event/event-source.h \ src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c \ @@ -2328,8 +2326,6 @@ src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \ src/libnm-systemd-core/src/systemd/sd-dhcp6-option.h \ src/libnm-systemd-core/src/systemd/sd-event.h \ src/libnm-systemd-core/src/systemd/sd-id128.h \ - src/libnm-systemd-core/src/systemd/sd-ipv4acd.h \ - src/libnm-systemd-core/src/systemd/sd-ipv4ll.h \ src/libnm-systemd-core/src/systemd/sd-lldp.h \ src/libnm-systemd-core/src/systemd/sd-ndisc.h \ $(NULL) @@ -2377,10 +2373,6 @@ src_core_libNetworkManagerBase_la_SOURCES = \ src/core/nm-l3cfg.h \ src/core/nm-ip-config.c \ src/core/nm-ip-config.h \ - src/core/nm-ip4-config.c \ - src/core/nm-ip4-config.h \ - src/core/nm-ip6-config.c \ - src/core/nm-ip6-config.h \ \ src/core/dhcp/nm-dhcp-client.c \ src/core/dhcp/nm-dhcp-client.h \ @@ -2419,8 +2411,6 @@ src_core_libNetworkManager_la_SOURCES = \ src/core/nm-checkpoint-manager.c \ src/core/nm-checkpoint-manager.h \ \ - src/core/devices/nm-acd-manager.c \ - src/core/devices/nm-acd-manager.h \ src/core/devices/nm-lldp-listener.c \ src/core/devices/nm-lldp-listener.h \ src/core/devices/nm-device-utils.c \ @@ -2569,8 +2559,6 @@ src_core_libNetworkManager_la_SOURCES = \ src/core/nm-firewall-utils.h \ src/core/nm-firewalld-manager.c \ src/core/nm-firewalld-manager.h \ - src/core/nm-proxy-config.c \ - src/core/nm-proxy-config.h \ src/core/nm-auth-manager.c \ src/core/nm-auth-manager.h \ src/core/nm-auth-utils.c \ @@ -4254,20 +4242,14 @@ src_core_devices_tests_ldflags = \ check_programs += \ src/core/devices/tests/test-lldp \ - src/core/devices/tests/test-acd + $(NULL) src_core_devices_tests_test_lldp_CPPFLAGS = $(src_core_cppflags_test) src_core_devices_tests_test_lldp_LDFLAGS = $(src_core_devices_tests_ldflags) src_core_devices_tests_test_lldp_LDADD = \ src/core/libNetworkManagerTest.la -src_core_devices_tests_test_acd_CPPFLAGS = $(src_core_cppflags_test) -src_core_devices_tests_test_acd_LDFLAGS = $(src_core_devices_tests_ldflags) -src_core_devices_tests_test_acd_LDADD = \ - src/core/libNetworkManagerTest.la - $(src_core_devices_tests_test_lldp_OBJECTS): $(src_libnm_core_public_mkenums_h) -$(src_core_devices_tests_test_acd_OBJECTS): $(src_libnm_core_public_mkenums_h) EXTRA_DIST += \ src/core/devices/tests/meson.build diff --git a/WIP.txt b/WIP.txt new file mode 100644 index 0000000000..688cb6785f --- /dev/null +++ b/WIP.txt @@ -0,0 +1,13 @@ +The following files have changes since the last rebase, +that need re-review. They probably also don't compile +and are incomplete: + + > src/core/devices/nm-device.c + > src/core/devices/nm-device.h + > src/core/nm-iface-helper.c + > src/core/nm-ip-config.c + > src/core/nm-ip4-config.h + > src/core/nm-ip6-config.h + > src/core/nm-manager.c + > src/core/nm-policy.c + > src/core/vpn/nm-vpn-connection.c diff --git a/src/core/README.l3cfg.md b/src/core/README.l3cfg.md new file mode 100644 index 0000000000..100ce012ea --- /dev/null +++ b/src/core/README.l3cfg.md @@ -0,0 +1,332 @@ +L3Cfg Rework +============ + +NMDevice is complex. Together with NMManager, NMDevice does too much. + +The goal is to rework the IP configuration (Layer 3) to be a more separate +part of the code that is better maintainable, easier to understand and +extend and more correct. + +Current Situation +----------------- + +- [NMManager](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/nm-manager.c): + this is the main object (a singleton) that drives most things. + Among many other things, it creates NMDevice instances and coordinates. + +- [NMDevice](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/devices/nm-device.c): + this represents a device. This is a subclass of NMDBusObject, + it is thus directly exported on D-Bus (as D-Bus objects like + `/org/freedesktop/NetworkManager/Devices/1`). + It also manages all aspects of the device. It has an overall state + (`NM_DEVICE_STATE`) but lots of more specific states (e.g. current state + of DHCP configuration). As always, the hardest part in programming are + stateful objects, and NMDevice has *a lot* of state. The code is huge and + hard to understand and the class has (too) many responsibilities. \ + \ + NMDevice also has subclasses, which are determined based on the "device type". That + means, there are subclasses like NMDeviceEthernet and NMDeviceBridge. As such, the + subclasses also export additional D-Bus interfaces. These subclasses also handle + the Layer 2 specific aspects of the device. For this aspect, delegation probably + would have been a better choice. On the other hand, IP configuration is almost entirely + managed by the parent class. Which is good, because the IP configuration is common to all + device types, but is bad because NMDevice already does so many things. + +- [NMIP4Config](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/nm-ip4-config.c) (and NMIP6Config): + these are also subclasses of NMDBusObject + and exported on D-Bus on paths like `/org/freedesktop/NetworkManager/IP4Config/1`. + The device's `IP4Config` property refers to these objects. They contain + the runtime IP information of that device. I don't think these objects + should exist on the D-Bus API, as NMDevice could directly expose these properties. + But for historic reasons, such is our D-Bus API. + Other than that, NMIP4Config objects are also used internally for tracking + IP configuration. For example, [when](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/dhcp/nm-dhcp-nettools.c#L563) + we receive a DHCP lease, we construct a NMIP4Config object with the addresses, DNS settings, + and so on. These + instances are then [tracked by](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/devices/nm-device.c#L519) + NMDevice, and [merged](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/devices/nm-device.c#L8928) + into an instance that is then exposed on D-Bus. As such, this class has two + mostly independent purposes. + +- [NMDhcpClient](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/dhcp/nm-dhcp-client.c): + our DHCP "library". It's a simple object with a clear API that + abstracts most of the complexity of handling DHCP. But still, NMDevice + needs to drive the DHCP client instance. Meaning, it needs to create (start) and stop + them and hook up signals for changes (new lease) and timeout. This is mostly + fine and unavoidable. The point is that while specific tasks are well abstracted + (like the details of DHCP), there is still some state in NMDevice that is related + to manage these tasks. DHCP is one of many such tasks, like also + link local addresses, SLAAC or LLDP. + This leads to the increased complexity of NMDevice, which manages a large variety + of such tasks. + +### Problems: + +1. first the sheer code size of [nm-device.c](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/devices/nm-device.c#L19030). + It's hard to understand and maintain, and this results in misbehaviours. Also, features that should be easy to implement + are not. Also, there are inefficiencies that are hard to fix. + +2. NMDevice and NMIP4Config are both exported on D-Bus while having other responsibilities. + Being subclasses of NMDBusObject, they are glued to the D-Bus API. For example, NMIP4Config is + also used for other purposes (for tracking IP configuration internally). + +3. NMDevice simply does too much. IP configuration should be a separate, encapsulated + API to make allow NMDevice to be smaller and the IP configuration part better + testable, understandable and smaller too. + +4. in the current model, NMDevice can be related to zero, one or two ifindexes. For example, + for ethernet devices, there is commonly only one actual netdev device (and one ifindex). + For OVS devices, there is no ifindex. For NMDeviceModem or NMDeviceBluetooth there is + a NMDevice instance that has initially no ifindex (it represents the tty serial port + or the bluetooth device) but during activation it gets and ip ifindex. With PPPoE, + the ethernet device can even have two ifindexes (one for the underlying ethernet and + one for the PPP device). That is all utterly confusing, inconsistent and limited. + For example, not all interfaces you see in `ip link` can be found in the D-Bus API. + The D-Bus API also does not give access to the ifindex (which is the real identifier + for a netdev devices). It only exposes the IpInterface name. That should be improved too, + but even such seemingly simple things are not done for years, because it's not trivially + clear what the right ifindex is. + Also a device instance on D-Bus significantly changes its meaning when it activates/deactivates + and it starts/stops being responsible for an ifindex. + In the future there should be devices that represent exactly one netdev device (an ifindex) + and devices that don't have an ifindex. That is follow up work and hinted by + [rhbz#1066703](https://bugzilla.redhat.com/show_bug.cgi?id=1066703). But simplifying + the IP configuration is a requisite before addressing that rework. + With this we will have controller and controlled devices. That means, a controller devices + (that for example represents a bluetooth device) will need to configure IP address on the + controlled IP device. That would be doable by injecting the IP config on that device, + but as the device already does so much, it would be better if this would be a separate + IP configuration manager for that ifindex. + +5. NMIP4Config exports properties on D-Bus like [AddressData](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/introspection/org.freedesktop.NetworkManager.IP4Config.xml#L26). + which are the currently configured IP addresses. These should be directly obtained + from the NMPlatform cache, which contains the correct list of addresses as kernel + exposes them via rtnetlink. Instead, whenever there are changes in platform we + [generate](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/devices/nm-device.c#L14223) + an NMIP4Config instance, then we merge, intersect and subtract this captured information + with the IP configs we want to configure. Finally we merge them together again + and sync the result to platform. This is bad, wrong and inefficient. + We must not mix "what is configured" with "what we want to configure". The current + approach also re-generates these IP config instance whenever something in platform changes. + That does not scale. If we have any hope to handle thousands of routes, this needs to change. + +6. The NMIP4Config objects are mutable, and they are heavily mutated. When we create an NMIP4Config + instance that represent a DHCP lease, we will [subtract](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/devices/nm-device.c#L14236) + addresses that were externally removed. That is wrong, because during a reapply we + will need to know these addresses again. The solution for that is not to mutate this + data, but track whether IP addresses are removed separately. + +7. NMDevice also does ACD, but it can only do it for addresses received via DHCP. + It implicitly also does ACD for IPv4LL, but that is via using the n_ipv4ll library. + It would be good to have an option that we can configure IPv4LL for any address. + Also, if you manually configure an address like 192.168.2.5 (for which we don't do + ACD) and the same address is obtained via DHCP, then doing ACD for the address is wrong. + There needs to be link-wide view of the addresses, and not only looking at individual + addresses when deciding to do ACD. + +8. As IP configuration is done by NMDevice, VPN connections have limited capabilities + in this regard. + When a VPN has IP addresses, then it injects them into NMDevice by + [providing](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/devices/nm-device.c#L13696) + an NMIP4Config. However, that means VPNs cannot do DHCP or IPv4LL, because it can + only inject known configuration. That would be very useful for example with a tap + device with openvpn. The real problem here is that NMVpnConnection are + treated special, when they should be more like devices. That should be reworked in the future, + by reworking VPN plugins. Regardless, having IP configuration handled by NMDevice is limiting. + +9. NetworkManager currently supports `ipv4.method` which can be "manual", "disabled" or + "auto". This scheme does not allow for example to enable IPv4LL together with DHCPv4. + As a special case, you can configure `ipv4.method=auto` together with static + addresses in `ipv4.addresses`, so combining DHCP and static addressing works. But in general, + this scheme is limited. In the future we should have more flexible schemes, where + addressing methods can be independently enabled or disabled. Also, we currently + have `ipv4.may-fail`, but that is limited as well. For example, + `ipv4.may-fail=yes` and `ipv6.may-fail=yes` still means that at least one of the + address families must succeed. That makes sense for certain use cases, but it + means, you cannot have truly best-effort, opportunistic DHCP with this way. + As workaround for that there is `ipv4.dhcp-timeout=infinity`. In + general it is not only useful to enable methods independently, we also configure + independently whether they are required or optional (and possibly, that they are optional + but at least one of several optional methods must succeed). Anyway. The point + is there is a need to make IP configuration more flexible. Currently it is not. + Such a seemingly simple extension would be surprisingly difficult to implement + because [the code](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/devices/nm-device.c#L6616) is + all over the place. The way how NMDevice tracks the overall activation state is + hard to understand. This should be improved and possibly could be improved in a + smaller refactoring effort. But instead of a smaller effort, we will use the big hammer + with L3Cfg rework. + +10. There are two classes NMIP4Config and NMIP6Config. Handling both address families is + commonly similar, so there is lot of similar code in both. They should be unified + so that similar code can handle both address families. + + +Solution and Future +------------------- + +NML3Cfg work is supposed to simplify some part of NMDevice: the part related to +IP configuration. This is a huge rework of a core part of NetworkManager. Arguably, +some parts maybe could be done more evolutionary, but the fundamental problems require +to rip out NMIP4Config and replace it by something better. Doing that is a large rework +that changes NMDevice heavily. That is also the opportunity to get the smaller issues +right. + +There is already a new class [NML3Cfg](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/nm-l3cfg.h#L141) +(currently unused). An NML3Cfg instance is responsible for handling IP configuration +of an ifindex. Consequently, we can ask NMNetns to [get](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/nm-netns.c#L142) +(or create) a NML3Cfg instance for an ifindex. +The idea is that there can be multiple users (NMDevice and NMVpnConnection and future controller devices) +that use the same NML3Cfg instance. Especially with a future rework of NMDevice where +a NMDevice only manages one ifindex (or none), there is a need that multiple +devices manage the IP configuration on the same device. Independent users can cooperate +to configure IP configuration on the same device. Already now with Libreswan VPN, where the VPN "injects" +its NMIP4Config in NMDevice. Or with PPPoE, where the NMDeviceEthernet is both about IP configuration +for the PPPoE device. + +There is also a new class [NML3ConfigData](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/nm-l3-config-data.h). +This replaces some aspect of NMIP4Config/NMIP6Config. A NML3ConfigData object is immutable and has no real logic +(or state). It has some "logic", like comparing two NML3ConfigData instances, logging it, or merging two (immutable) +instances into a new instance. But as the class is immutable, that logic is rather simple. This class is +used to track information. As it's immutable, anybody who is interested can keep a reference +for it's own purpose. For example, NMDhcpClient will generate a NML3ConfigData with the information +of the lease. It may keep the reference, but it will also tell NMDevice about it. The NMDevice +will then itself tell NML3Cfg to accept this configuration. This works by calling +[add()/remove()](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/nm-l3cfg.c#L2654). +One NML3ConfigData can also track both IPv4 and IPv6 information. It's a general set of IP related +configuration, that has some address specific properties. Those are then duplicated for both address +families and implemented in a way to minimize code duplication and encourage to treat them the same. +As this replaces an aspect of NMIP4Config, NMIP4Config can focus on it's other purpose: to expose data on D-Bus. + +What NML3Cfg then does, is to merge all NML3ConfigData, and "commit" it to platform. Thereby it knows +which addresses it configured the last time (if they no longer are to be configured, they must be removed). +This is done [here](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/nm-l3cfg.c#L3442). + +As independent users should be able to cooperate, it is not appropriate that they call "commit". +Instead, they set a commit type ([here](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/nm-l3cfg.c#L3476), +and whenever something changes, NML3Cfg knows the aggregated commit type. That is necessary +because when we activate a device, we may want to preserve the existing IP configuration (e.g. after +a restart of NetworkManager). During that time is the NML3Cfg instance set to a reduced commit +mode (ASSUME). + +NML3Cfg will also handle IPv4 ACD. Any user of NML3Cfg registers/unregisters NML3ConfigData instances +that should be configured. Thereby they also say whether ACD should be done for the IPv4 addresses. +NML3Cfg then keeps state for each IPv4 address, whether ACD should be performed, and whether the +address is ready to be configured. NML3Cfg does not do DHCP or similar. That is still the responsibility +of NMDevice to run a NMDhcpClient. But it does run ACD, because whether to perform ACD on an address +requires a holistic view of all addresses of that interface. For example, if you configure a static +IP address 192.168.2.5 (with ACD disabled) and you also get the same address via DHCP, then ACD should +not performed for that address (even if the user configured ACD with DHCP). Of course, that is a very +unlikely example. More likely is that NetworkManager is restarted and it leaves the addresses (that passed +ACD) configured. After restart, DHCP finds the same addresses and no new ACD should be performed. This shows +that the ACD state depends all the IP addresses on an interface, +and thus it's done by NML3Cfg. The API for this is very simple. Users enable/disable ACD during nm_l3cfg_add_config() +and receive events like [NM_L3_CONFIG_NOTIFY_TYPE_ACD_EVENT](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/nm-l3cfg.c#L303). +Another advantage is that ACD now works for any kinds of addresses. Currently it only works for addresses +from DHCP and link local addresses. + +NML3Cfg does not implement or drive DHCP. However, as it already does ACD it gained it's own IPv4LL +"library": [NML3IPv4LL](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/nm-l3cfg.c#L3624). +This will replace nettools' n-ipv4ll library, because that library also does ACD internally, while we want +to use the holistic view that NML3Cfg has. What this means, is that the user (NMDevice) +can request a NML3IPv4LL handle from the NML3Cfg instance, and it just does it with a simple API. +All the user might do is to enable/disable the handle and to react to signals (if it cares to find +out whether IPv4LL fails). + +The general parts of NML3Cfg are already implemented. It has unit tests and can be tested independently. +You might note that NML3Cfg is not trivial already, but the API that it provides is as simple as possible: +create immutable NML3ConfigData instance, and add/remove them. Optionally, handle the ACD events and +listen to some events. The complexity that NML3Cfg has, will lead in the same amount simplify NMDevice. + +What is missing is NMDevice using this new API. Instead of creating and tracking NMIP4Config instances, +it needs to track NML3ConfigData instances. In principle that sounds simple, in practice that changes +large part of "nm-device.c". + +Thereby also the state machine for NM_DEVICE_STATE will be improved. It's anyway a rewrite. This will lay the +groundwork for more flexible configuration of IP methods, with different failure modes (opportunistic or +mandatory). + +What then also should be easier, to combine IPv4LL with other addressing methods. In Windows AFAIK, if you +don't get a DHCP address it will configure a IPv4LL address. That is also what RFC suggests, but which we +currently don't support. + +In general, change the way how external IP addresses/routes are tracked. This merge, intersect, subtract +approach does not perform well. Currently we react on signals and it's hard to understand what happens +in response to that, or whether it's really the correct thing to do. See yourself starting from +[here](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/devices/nm-device.c#L14214). + +### DHCP + +Currently, when NMDhcpClient receives a lease, it emits a signal with two things: the NMIP4Config +instance (containing addresses, routes, DNS settings and other information for later use), and a string +dictionary with the DHCP lease options (they are mainly used to expose them on D-Bus). The latter is +immutable (meaning, it's not changed afterwards). That does not significantly change with L3Cfg. The +difference is that instead of NMIP4Config a NML3ConfigData instance gets created. That instance then +references the (immutable) strdict. With that, any part of the code that has access to the NML3ConfigData, +also has access to the lease options. So instead of two separate +pieces of information, the result of a lease event will only be a NML3ConfigData instance (which internally +tracks the strdict with the DHCP lease options). + +Later, when NML3Cfg configures an interface, it takes all NML3ConfigData instances that were added to +it, and merges them. [Currently](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/nm-l3-config-data.c#L2693), +the merged data will not contain the lease information, but it's probably not needed anyway. + +If it would be needed, the question is what happens if multiple lease informations are present +during the merge. Duplicate leases would not commonly happen, but in general, the merging algorithm +needs to take into account priorities and conflicting data. +That is done by users who call [add](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/nm-l3cfg.c#L2658) +to provide a priority for the NML3ConfigData instance. +Later, the instances get sorted by priority and merging is smart to take that into account +([here](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/nm-l3cfg.c#L2983)). + +Also, we currently inject the route-metric and table into the generated NMIP4Config. +Those settings come from the connection profiles and not from DHCP. We will avoid that +by allowing the routes in NML3ConfigData to be marked as metric\_any and table\_any. +That way,the NML3ConfigData is independent (and immutable) with respect to those settings. +The same happens for example with PPP, where the modem starts PPP, and currently the +route and metric needs to be passed several layers down. But worst, those settings +can change during reapply. Currently that means we need to hack NMIP4Config with +those changes. Later, we will only tell NML3Cfg to track the NML3ConfigData with +different settings. + +### DNS + +DNS information is currently set in the NMIP4Config instances. That happens for example with the DNS information +from a DHCP lease, but also with the static DNS settings from the connection profile. Later, the same information +will packed in NML3ConfigData. + +One nice difference is again the immutability. Currently, NMDnsManager keeps a reference to all relevant NMIP4Config instances, +but as they are mutable, it needs to [subscribe](https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/6b64fac06d2f6e0d9fa530ebb1ab28d53a1c5d03/src/core/dns/nm-dns-manager.c#L275) +to changes. Later, when a NML3ConfigData instance "changes", it means it was +replaced by a different one and NMDnsManager needs to update its list of tracked NML3ConfigData. I find that +cleaner, because adding and removal to the list of NMIP4Config/NML3ConfigData happens anyway and needs to be handled. + + +Related Bugs +------------ + +* Main bug: + + - [rh#1868254](https://bugzilla.redhat.com/show_bug.cgi?id=1868254): + "refactor NetworkManager's IP configuration done by NMDevice" + +* Follow up but to improve model of devices: + + - [rh#1066703](https://bugzilla.redhat.com/show_bug.cgi?id=1066703): + "\[RFE\] Handle parent/child relationships more cleanly" + +* Flexible IP methods: + + - [rh#1791624](https://bugzilla.redhat.com/show_bug.cgi?id=1791624): + "NetworkManager must not remove used bridge" + +* Improving performance issues, this will lay ground work: + + - [rh#1847125](https://bugzilla.redhat.com/show_bug.cgi?id=1847125): + "\[RFE\] Improve 20% performance on creating 1000 bridge over 1000 VLANs" + + - [rh#1861527](https://bugzilla.redhat.com/show_bug.cgi?id=1861527): + "Excessive memory and CPU usage on a router with IPv6 BGP feed" + + - [rh#1753677](https://bugzilla.redhat.com/show_bug.cgi?id=1753677): + "High cpu usage while non-controlled interface is mangling tc filters" + diff --git a/src/core/devices/adsl/nm-device-adsl.c b/src/core/devices/adsl/nm-device-adsl.c index 4e4c9dcc9c..1909e98339 100644 --- a/src/core/devices/adsl/nm-device-adsl.c +++ b/src/core/devices/adsl/nm-device-adsl.c @@ -15,7 +15,6 @@ #include #include -#include "nm-ip4-config.h" #include "devices/nm-device-private.h" #include "libnm-platform/nm-platform.h" #include "ppp/nm-ppp-manager-call.h" @@ -434,19 +433,30 @@ ppp_ifindex_set(NMPPPManager *ppp_manager, int ifindex, const char *iface, gpoin } static void -ppp_ip4_config(NMPPPManager *ppp_manager, NMIP4Config *config, gpointer user_data) +ppp_new_config(NMPPPManager * ppp_manager, + int addr_family, + const NML3ConfigData * l3cd, + const NMUtilsIPv6IfaceId *iid, + gpointer user_data) { NMDevice *device = NM_DEVICE(user_data); - /* Ignore PPP IP4 events that come in after initial configuration */ - if (nm_device_activate_ip4_state_in_conf(device)) - nm_device_activate_schedule_ip_config_result(device, AF_INET, NM_IP_CONFIG_CAST(config)); + if (addr_family != AF_INET) + return; + + if (!nm_device_activate_ip4_state_in_conf(device)) { + /* Ignore PPP events that come in after initial configuration */ + return; + } + + nm_device_set_dev2_ip_config(device, AF_INET, l3cd); + nm_device_activate_schedule_ip_config_result(device, AF_INET); } static NMActStageReturn -act_stage3_ip4_config_start(NMDevice * device, - NMIP4Config ** out_config, - NMDeviceStateReason *out_failure_reason) +act_stage3_ip4_config_start(NMDevice * device, + const NML3ConfigData **out_l3cd, + NMDeviceStateReason * out_failure_reason) { NMDeviceAdsl * self = NM_DEVICE_ADSL(device); NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE(self); @@ -476,14 +486,6 @@ act_stage3_ip4_config_start(NMDevice * device, priv->ppp_manager = nm_ppp_manager_create(ppp_iface, &err); - if (priv->ppp_manager) { - nm_ppp_manager_set_route_parameters(priv->ppp_manager, - nm_device_get_route_table(device, AF_INET), - nm_device_get_route_metric(device, AF_INET), - nm_device_get_route_table(device, AF_INET6), - nm_device_get_route_metric(device, AF_INET6)); - } - if (!priv->ppp_manager || !nm_ppp_manager_start(priv->ppp_manager, req, @@ -509,23 +511,23 @@ act_stage3_ip4_config_start(NMDevice * device, G_CALLBACK(ppp_ifindex_set), self); g_signal_connect(priv->ppp_manager, - NM_PPP_MANAGER_SIGNAL_IP4_CONFIG, - G_CALLBACK(ppp_ip4_config), + NM_PPP_MANAGER_SIGNAL_NEW_CONFIG, + G_CALLBACK(ppp_new_config), self); return NM_ACT_STAGE_RETURN_POSTPONE; } static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) +act_stage3_ip_config_start(NMDevice * device, + int addr_family, + const NML3ConfigData **out_l3cd, + NMDeviceStateReason * out_failure_reason) { if (addr_family == AF_INET) - return act_stage3_ip4_config_start(device, (NMIP4Config **) out_config, out_failure_reason); + return act_stage3_ip4_config_start(device, out_l3cd, out_failure_reason); return NM_DEVICE_CLASS(nm_device_adsl_parent_class) - ->act_stage3_ip_config_start(device, addr_family, out_config, out_failure_reason); + ->act_stage3_ip_config_start(device, addr_family, out_l3cd, out_failure_reason); } static void @@ -537,7 +539,7 @@ adsl_cleanup(NMDeviceAdsl *self) g_signal_handlers_disconnect_by_func(priv->ppp_manager, G_CALLBACK(ppp_state_changed), self); - g_signal_handlers_disconnect_by_func(priv->ppp_manager, G_CALLBACK(ppp_ip4_config), self); + g_signal_handlers_disconnect_by_func(priv->ppp_manager, G_CALLBACK(ppp_new_config), self); nm_ppp_manager_stop(priv->ppp_manager, NULL, NULL, NULL); g_clear_object(&priv->ppp_manager); } diff --git a/src/core/devices/bluetooth/nm-device-bt.c b/src/core/devices/bluetooth/nm-device-bt.c index 8f4ceba75e..67c1476c2e 100644 --- a/src/core/devices/bluetooth/nm-device-bt.c +++ b/src/core/devices/bluetooth/nm-device-bt.c @@ -25,7 +25,6 @@ #include "settings/nm-settings-connection.h" #include "nm-utils.h" #include "nm-bt-error.h" -#include "nm-ip4-config.h" #include "libnm-platform/nm-platform.h" #include "devices/wwan/nm-modem-manager.h" @@ -550,11 +549,20 @@ device_state_changed(NMDevice * device, } static void -modem_ip4_config_result(NMModem *modem, NMIP4Config *config, GError *error, gpointer user_data) +modem_new_config(NMModem * modem, + int addr_family, + const NML3ConfigData * l3cd, + gboolean do_slaac, + const NMUtilsIPv6IfaceId *iid, + GError * error, + gpointer user_data) { NMDeviceBt *self = NM_DEVICE_BT(user_data); NMDevice * device = NM_DEVICE(self); + if (addr_family != AF_INET) + return; + g_return_if_fail(nm_device_activate_ip4_state_in_conf(device) == TRUE); if (error) { @@ -565,7 +573,8 @@ modem_ip4_config_result(NMModem *modem, NMIP4Config *config, GError *error, gpoi return; } - nm_device_activate_schedule_ip_config_result(device, AF_INET, NM_IP_CONFIG_CAST(config)); + nm_device_set_dev2_ip_config(device, AF_INET, l3cd); + nm_device_activate_schedule_ip_config_result(device, AF_INET); } static void @@ -690,7 +699,7 @@ modem_try_claim(NMDeviceBt *self, NMModem *modem) g_signal_connect(modem, NM_MODEM_PPP_STATS, G_CALLBACK(ppp_stats), self); g_signal_connect(modem, NM_MODEM_PPP_FAILED, G_CALLBACK(ppp_failed), self); g_signal_connect(modem, NM_MODEM_PREPARE_RESULT, G_CALLBACK(modem_prepare_result), self); - g_signal_connect(modem, NM_MODEM_IP4_CONFIG_RESULT, G_CALLBACK(modem_ip4_config_result), self); + g_signal_connect(modem, NM_MODEM_NEW_CONFIG, G_CALLBACK(modem_new_config), self); g_signal_connect(modem, NM_MODEM_AUTH_REQUESTED, G_CALLBACK(modem_auth_requested), self); g_signal_connect(modem, NM_MODEM_AUTH_RESULT, G_CALLBACK(modem_auth_result), self); g_signal_connect(modem, NM_MODEM_STATE_CHANGED, G_CALLBACK(modem_state_cb), self); @@ -1002,10 +1011,10 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) } static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) +act_stage3_ip_config_start(NMDevice * device, + int addr_family, + const NML3ConfigData **out_l3cd, + NMDeviceStateReason * out_failure_reason) { NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE(device); @@ -1023,7 +1032,7 @@ act_stage3_ip_config_start(NMDevice * device, } return NM_DEVICE_CLASS(nm_device_bt_parent_class) - ->act_stage3_ip_config_start(device, addr_family, out_config, out_failure_reason); + ->act_stage3_ip_config_start(device, addr_family, out_l3cd, out_failure_reason); } static void diff --git a/src/core/devices/nm-acd-manager.c b/src/core/devices/nm-acd-manager.c deleted file mode 100644 index 995abacded..0000000000 --- a/src/core/devices/nm-acd-manager.c +++ /dev/null @@ -1,496 +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 "nm-acd-manager.h" - -#include -#include -#include -#include - -#include "libnm-platform/nm-platform.h" -#include "nm-utils.h" -#include "NetworkManagerUtils.h" -#include "n-acd/src/n-acd.h" - -/*****************************************************************************/ - -typedef enum { - STATE_INIT, - STATE_PROBING, - STATE_PROBE_DONE, - STATE_ANNOUNCING, -} State; - -typedef struct { - in_addr_t address; - gboolean duplicate; - NAcdProbe *probe; -} AddressInfo; - -struct _NMAcdManager { - int ifindex; - guint8 hwaddr[ETH_ALEN]; - State state; - GHashTable *addresses; - guint completed; - NAcd * acd; - GSource * event_source; - - NMAcdCallbacks callbacks; - gpointer user_data; -}; - -/*****************************************************************************/ - -#define _NMLOG_DOMAIN LOGD_IP4 -#define _NMLOG_PREFIX_NAME "acd" -#define _NMLOG(level, ...) \ - G_STMT_START \ - { \ - char _sbuf[64]; \ - \ - nm_log((level), \ - _NMLOG_DOMAIN, \ - self && self->ifindex > 0 \ - ? 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, "[%p,%d]", self, self->ifindex) \ - : "" _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - G_STMT_END - -/*****************************************************************************/ - -static const char * -_acd_event_to_string(unsigned int event) -{ - switch (event) { - case N_ACD_EVENT_READY: - return "ready"; - case N_ACD_EVENT_USED: - return "used"; - case N_ACD_EVENT_DEFENDED: - return "defended"; - case N_ACD_EVENT_CONFLICT: - return "conflict"; - case N_ACD_EVENT_DOWN: - return "down"; - } - return NULL; -} - -#define ACD_EVENT_TO_STRING_BUF_SIZE 50 - -static const char * -_acd_event_to_string_buf(unsigned event, char buffer[static ACD_EVENT_TO_STRING_BUF_SIZE]) -{ - const char *s; - - s = _acd_event_to_string(event); - if (s) - return s; - - g_snprintf(buffer, ACD_EVENT_TO_STRING_BUF_SIZE, "(%u)", event); - return buffer; -} - -static const char * -acd_error_to_string(int error) -{ - if (error < 0) - return nm_strerror_native(-error); - - switch (error) { - case _N_ACD_E_SUCCESS: - return "success"; - case N_ACD_E_PREEMPTED: - return "preempted"; - case N_ACD_E_INVALID_ARGUMENT: - return "invalid argument"; - } - - g_return_val_if_reached(NULL); -} - -static int -acd_error_to_nmerr(int error, gboolean always_fail) -{ - if (error < 0) - return -nm_errno_native(error); - - if (always_fail) { - if (NM_IN_SET(error, N_ACD_E_PREEMPTED, N_ACD_E_INVALID_ARGUMENT)) - return -NME_UNSPEC; - g_return_val_if_reached(-NME_UNSPEC); - } - - /* so, @error is either zero (indicating success) or one - * of the special status codes like N_ACD_E_*. In both cases, - * return the positive value here. */ - if (NM_IN_SET(error, _N_ACD_E_SUCCESS, N_ACD_E_PREEMPTED, N_ACD_E_INVALID_ARGUMENT)) - return error; - - g_return_val_if_reached(error); -} - -/*****************************************************************************/ - -/** - * nm_acd_manager_add_address: - * @self: a #NMAcdManager - * @address: an IP address - * - * Add @address to the list of IP addresses to probe. - - * Returns: %TRUE on success, %FALSE if the address was already in the list - */ -gboolean -nm_acd_manager_add_address(NMAcdManager *self, in_addr_t address) -{ - AddressInfo *info; - - g_return_val_if_fail(self, FALSE); - g_return_val_if_fail(self->state == STATE_INIT, FALSE); - - if (g_hash_table_lookup(self->addresses, GUINT_TO_POINTER(address))) - return FALSE; - - info = g_slice_new0(AddressInfo); - info->address = address; - - g_hash_table_insert(self->addresses, GUINT_TO_POINTER(address), info); - - return TRUE; -} - -static gboolean -acd_event(int fd, GIOCondition condition, gpointer data) -{ - NMAcdManager *self = data; - NAcdEvent * event; - AddressInfo * info; - gboolean emit_probe_terminated = FALSE; - char address_str[INET_ADDRSTRLEN]; - int r; - - if (n_acd_dispatch(self->acd)) - return G_SOURCE_CONTINUE; - - while (!n_acd_pop_event(self->acd, &event) && event) { - char to_string_buffer[ACD_EVENT_TO_STRING_BUF_SIZE]; - gs_free char *hwaddr_str = NULL; - gboolean check_probing_done = FALSE; - - switch (event->event) { - case N_ACD_EVENT_READY: - n_acd_probe_get_userdata(event->ready.probe, (void **) &info); - info->duplicate = FALSE; - if (self->state == STATE_ANNOUNCING) { - /* fake probe ended, start announcing */ - r = n_acd_probe_announce(info->probe, N_ACD_DEFEND_ONCE); - if (r) { - _LOGW("couldn't announce address %s on interface '%s': %s", - _nm_utils_inet4_ntop(info->address, address_str), - nm_platform_link_get_name(NM_PLATFORM_GET, self->ifindex), - acd_error_to_string(r)); - } else { - _LOGD("announcing address %s", - _nm_utils_inet4_ntop(info->address, address_str)); - } - } - check_probing_done = TRUE; - break; - case N_ACD_EVENT_USED: - n_acd_probe_get_userdata(event->used.probe, (void **) &info); - info->duplicate = TRUE; - check_probing_done = TRUE; - break; - case N_ACD_EVENT_DEFENDED: - n_acd_probe_get_userdata(event->defended.probe, (void **) &info); - _LOGD("defended address %s from host %s", - _nm_utils_inet4_ntop(info->address, address_str), - (hwaddr_str = - nm_utils_hwaddr_ntoa(event->defended.sender, event->defended.n_sender))); - break; - case N_ACD_EVENT_CONFLICT: - n_acd_probe_get_userdata(event->conflict.probe, (void **) &info); - _LOGW("conflict for address %s detected with host %s on interface '%s'", - _nm_utils_inet4_ntop(info->address, address_str), - (hwaddr_str = - nm_utils_hwaddr_ntoa(event->defended.sender, event->defended.n_sender)), - nm_platform_link_get_name(NM_PLATFORM_GET, self->ifindex)); - break; - default: - _LOGD("unhandled event '%s'", _acd_event_to_string_buf(event->event, to_string_buffer)); - break; - } - - if (check_probing_done && self->state == STATE_PROBING - && ++self->completed == g_hash_table_size(self->addresses)) { - self->state = STATE_PROBE_DONE; - emit_probe_terminated = TRUE; - } - } - - if (emit_probe_terminated) { - if (self->callbacks.probe_terminated_callback) { - self->callbacks.probe_terminated_callback(self, self->user_data); - } - } - - return G_SOURCE_CONTINUE; -} - -static gboolean -acd_probe_add(NMAcdManager *self, AddressInfo *info, guint64 timeout) -{ - NAcdProbeConfig *probe_config; - int r; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - r = n_acd_probe_config_new(&probe_config); - if (r) { - _LOGW("could not create probe config for %s on interface '%s': %s", - _nm_utils_inet4_ntop(info->address, sbuf), - nm_platform_link_get_name(NM_PLATFORM_GET, self->ifindex), - acd_error_to_string(r)); - return FALSE; - } - - n_acd_probe_config_set_ip(probe_config, (struct in_addr){info->address}); - n_acd_probe_config_set_timeout(probe_config, timeout); - - r = n_acd_probe(self->acd, &info->probe, probe_config); - if (r) { - _LOGW("could not start probe for %s on interface '%s': %s", - _nm_utils_inet4_ntop(info->address, sbuf), - nm_platform_link_get_name(NM_PLATFORM_GET, self->ifindex), - acd_error_to_string(r)); - n_acd_probe_config_free(probe_config); - return FALSE; - } - - n_acd_probe_set_userdata(info->probe, info); - n_acd_probe_config_free(probe_config); - - return TRUE; -} - -static int -acd_init(NMAcdManager *self) -{ - NAcdConfig *config; - int r; - - if (self->acd) - return 0; - - r = n_acd_config_new(&config); - if (r) - return r; - - n_acd_config_set_ifindex(config, self->ifindex); - n_acd_config_set_transport(config, N_ACD_TRANSPORT_ETHERNET); - n_acd_config_set_mac(config, self->hwaddr, ETH_ALEN); - - r = n_acd_new(&self->acd, config); - n_acd_config_free(config); - return r; -} - -/** - * nm_acd_manager_start_probe: - * @self: a #NMAcdManager - * @timeout: maximum probe duration in milliseconds - * @error: location to store error, or %NULL - * - * Start probing IP addresses for duplicates; when the probe terminates a - * PROBE_TERMINATED signal is emitted. - * - * Returns: 0 on success or a negative NetworkManager error code (NME_*). - */ -int -nm_acd_manager_start_probe(NMAcdManager *self, guint timeout) -{ - GHashTableIter iter; - AddressInfo * info; - gboolean success = FALSE; - int fd, r; - - g_return_val_if_fail(self, FALSE); - g_return_val_if_fail(self->state == STATE_INIT, FALSE); - - r = acd_init(self); - if (r) { - _LOGW("couldn't init ACD for probing on interface '%s': %s", - nm_platform_link_get_name(NM_PLATFORM_GET, self->ifindex), - acd_error_to_string(r)); - return acd_error_to_nmerr(r, TRUE); - } - - self->completed = 0; - - g_hash_table_iter_init(&iter, self->addresses); - while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &info)) - success |= acd_probe_add(self, info, timeout); - - if (success) - self->state = STATE_PROBING; - - nm_assert(!self->event_source); - n_acd_get_fd(self->acd, &fd); - self->event_source = - nm_g_unix_fd_source_new(fd, G_IO_IN, G_PRIORITY_DEFAULT, acd_event, self, NULL); - g_source_attach(self->event_source, NULL); - - return success ? 0 : -NME_UNSPEC; -} - -/** - * nm_acd_manager_check_address: - * @self: a #NMAcdManager - * @address: an IP address - * - * Check if an IP address is duplicate. @address must have been added with - * nm_acd_manager_add_address(). - * - * Returns: %TRUE if the address is not duplicate, %FALSE otherwise - */ -gboolean -nm_acd_manager_check_address(NMAcdManager *self, in_addr_t address) -{ - AddressInfo *info; - - g_return_val_if_fail(self, FALSE); - g_return_val_if_fail(NM_IN_SET(self->state, STATE_INIT, STATE_PROBE_DONE), FALSE); - - info = g_hash_table_lookup(self->addresses, GUINT_TO_POINTER(address)); - g_return_val_if_fail(info, FALSE); - - return !info->duplicate; -} - -/** - * nm_acd_manager_announce_addresses: - * @self: a #NMAcdManager - * - * Start announcing addresses. - * - * Returns: a negative NetworkManager error number or zero on success. - */ -int -nm_acd_manager_announce_addresses(NMAcdManager *self) -{ - GHashTableIter iter; - AddressInfo * info; - int r; - int fd; - gboolean success = TRUE; - - r = acd_init(self); - if (r) { - _LOGW("couldn't init ACD for announcing addresses on interface '%s': %s", - nm_platform_link_get_name(NM_PLATFORM_GET, self->ifindex), - acd_error_to_string(r)); - return acd_error_to_nmerr(r, TRUE); - } - - if (self->state == STATE_INIT) { - /* n-acd can't announce without probing, therefore let's - * start a fake probe with zero timeout and then perform - * the announcement. */ - g_hash_table_iter_init(&iter, self->addresses); - while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &info)) { - if (!acd_probe_add(self, info, 0)) - success = FALSE; - } - self->state = STATE_ANNOUNCING; - } else if (self->state == STATE_ANNOUNCING) { - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - g_hash_table_iter_init(&iter, self->addresses); - while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &info)) { - if (info->duplicate) - continue; - r = n_acd_probe_announce(info->probe, N_ACD_DEFEND_ONCE); - if (r) { - _LOGW("couldn't announce address %s on interface '%s': %s", - _nm_utils_inet4_ntop(info->address, sbuf), - nm_platform_link_get_name(NM_PLATFORM_GET, self->ifindex), - acd_error_to_string(r)); - success = FALSE; - } else - _LOGD("announcing address %s", _nm_utils_inet4_ntop(info->address, sbuf)); - } - } - - if (!self->event_source) { - n_acd_get_fd(self->acd, &fd); - self->event_source = - nm_g_unix_fd_source_new(fd, G_IO_IN, G_PRIORITY_DEFAULT, acd_event, self, NULL); - g_source_attach(self->event_source, NULL); - } - - return success ? 0 : -NME_UNSPEC; -} - -static void -destroy_address_info(gpointer data) -{ - AddressInfo *info = (AddressInfo *) data; - - n_acd_probe_free(info->probe); - - g_slice_free(AddressInfo, info); -} - -/*****************************************************************************/ - -NMAcdManager * -nm_acd_manager_new(int ifindex, - const guint8 * hwaddr, - guint hwaddr_len, - const NMAcdCallbacks *callbacks, - gpointer user_data) -{ - NMAcdManager *self; - - g_return_val_if_fail(ifindex > 0, NULL); - g_return_val_if_fail(hwaddr, NULL); - g_return_val_if_fail(hwaddr_len == ETH_ALEN, NULL); - - self = g_slice_new0(NMAcdManager); - - if (callbacks) - self->callbacks = *callbacks; - self->user_data = user_data; - - self->addresses = g_hash_table_new_full(nm_direct_hash, NULL, NULL, destroy_address_info); - self->state = STATE_INIT; - self->ifindex = ifindex; - memcpy(self->hwaddr, hwaddr, ETH_ALEN); - return self; -} - -void -nm_acd_manager_free(NMAcdManager *self) -{ - g_return_if_fail(self); - - if (self->callbacks.user_data_destroy) - self->callbacks.user_data_destroy(self->user_data); - - nm_clear_pointer(&self->addresses, g_hash_table_destroy); - nm_clear_g_source_inst(&self->event_source); - nm_clear_pointer(&self->acd, n_acd_unref); - - g_slice_free(NMAcdManager, self); -} diff --git a/src/core/devices/nm-acd-manager.h b/src/core/devices/nm-acd-manager.h deleted file mode 100644 index e8ef6f2b99..0000000000 --- a/src/core/devices/nm-acd-manager.h +++ /dev/null @@ -1,34 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2015 - 2018 Red Hat, Inc. - */ - -#ifndef __NM_ACD_MANAGER__ -#define __NM_ACD_MANAGER__ - -#include - -typedef struct _NMAcdManager NMAcdManager; - -typedef struct { - void (*probe_terminated_callback)(NMAcdManager *self, gpointer user_data); - GDestroyNotify user_data_destroy; -} NMAcdCallbacks; - -NMAcdManager *nm_acd_manager_new(int ifindex, - const guint8 * hwaddr, - guint hwaddr_len, - const NMAcdCallbacks *callbacks, - gpointer user_data); - -void nm_acd_manager_free(NMAcdManager *self); - -gboolean nm_acd_manager_add_address(NMAcdManager *self, in_addr_t address); -int nm_acd_manager_start_probe(NMAcdManager *self, guint timeout); -gboolean nm_acd_manager_check_address(NMAcdManager *self, in_addr_t address); -int nm_acd_manager_announce_addresses(NMAcdManager *self); - -NM_AUTO_DEFINE_FCN0(NMAcdManager *, _nm_auto_free_acdmgr, nm_acd_manager_free); -#define nm_auto_free_acdmgr nm_auto(_nm_auto_free_acdmgr) - -#endif /* __NM_ACD_MANAGER__ */ diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c index 3b3b8fcdd3..73ec0474f9 100644 --- a/src/core/devices/nm-device-bond.c +++ b/src/core/devices/nm-device-bond.c @@ -15,7 +15,6 @@ #include "libnm-platform/nm-platform.h" #include "nm-device-factory.h" #include "libnm-core-intern/nm-core-internal.h" -#include "nm-ip4-config.h" #define _NMLOG_DEVICE_TYPE NMDeviceBond #include "nm-device-logging.h" diff --git a/src/core/devices/nm-device-dummy.c b/src/core/devices/nm-device-dummy.c index 488f0ba003..2f8f311e23 100644 --- a/src/core/devices/nm-device-dummy.c +++ b/src/core/devices/nm-device-dummy.c @@ -12,7 +12,6 @@ #include "nm-act-request.h" #include "nm-device-private.h" -#include "nm-ip4-config.h" #include "libnm-platform/nm-platform.h" #include "nm-device-factory.h" #include "nm-setting-dummy.h" diff --git a/src/core/devices/nm-device-ethernet.c b/src/core/devices/nm-device-ethernet.c index 305552f074..153938ba40 100644 --- a/src/core/devices/nm-device-ethernet.c +++ b/src/core/devices/nm-device-ethernet.c @@ -17,7 +17,6 @@ #include "libnm-glib-aux/nm-uuid.h" #include "nm-device-private.h" #include "nm-act-request.h" -#include "nm-ip4-config.h" #include "NetworkManagerUtils.h" #include "supplicant/nm-supplicant-manager.h" #include "supplicant/nm-supplicant-interface.h" @@ -1136,13 +1135,24 @@ ppp_ifindex_set(NMPPPManager *ppp_manager, int ifindex, const char *iface, gpoin } static void -ppp_ip4_config(NMPPPManager *ppp_manager, NMIP4Config *config, gpointer user_data) +ppp_new_config(NMPPPManager * ppp_manager, + int addr_family, + const NML3ConfigData * l3cd, + const NMUtilsIPv6IfaceId *iid, + gpointer user_data) { NMDevice *device = NM_DEVICE(user_data); - /* Ignore PPP IP4 events that come in after initial configuration */ - if (nm_device_activate_ip4_state_in_conf(device)) - nm_device_activate_schedule_ip_config_result(device, AF_INET, NM_IP_CONFIG_CAST(config)); + if (addr_family != AF_INET) + return; + + if (!nm_device_activate_ip4_state_in_conf(device)) { + /* Ignore PPP IP4 events that come in after initial configuration */ + return; + } + + nm_device_set_dev2_ip_config(device, AF_INET, l3cd); + nm_device_activate_schedule_ip_config_result(device, AF_INET); } static NMActStageReturn @@ -1164,14 +1174,6 @@ pppoe_stage3_ip4_config_start(NMDeviceEthernet *self, NMDeviceStateReason *out_f priv->ppp_manager = nm_ppp_manager_create(nm_device_get_iface(device), &err); - if (priv->ppp_manager) { - nm_ppp_manager_set_route_parameters(priv->ppp_manager, - nm_device_get_route_table(device, AF_INET), - nm_device_get_route_metric(device, AF_INET), - nm_device_get_route_table(device, AF_INET6), - nm_device_get_route_metric(device, AF_INET6)); - } - if (!priv->ppp_manager || !nm_ppp_manager_start(priv->ppp_manager, req, @@ -1197,8 +1199,8 @@ pppoe_stage3_ip4_config_start(NMDeviceEthernet *self, NMDeviceStateReason *out_f G_CALLBACK(ppp_ifindex_set), self); g_signal_connect(priv->ppp_manager, - NM_PPP_MANAGER_SIGNAL_IP4_CONFIG, - G_CALLBACK(ppp_ip4_config), + NM_PPP_MANAGER_SIGNAL_NEW_CONFIG, + G_CALLBACK(ppp_new_config), self); return NM_ACT_STAGE_RETURN_POSTPONE; } @@ -1496,10 +1498,10 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) } static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) +act_stage3_ip_config_start(NMDevice * device, + int addr_family, + const NML3ConfigData **out_config, + NMDeviceStateReason * out_failure_reason) { NMSettingConnection *s_con; const char * connection_type; diff --git a/src/core/devices/nm-device-infiniband.c b/src/core/devices/nm-device-infiniband.c index 37065bc89f..5c3064468e 100644 --- a/src/core/devices/nm-device-infiniband.c +++ b/src/core/devices/nm-device-infiniband.c @@ -13,7 +13,6 @@ #include "NetworkManagerUtils.h" #include "nm-device-private.h" #include "nm-act-request.h" -#include "nm-ip4-config.h" #include "libnm-platform/nm-platform.h" #include "nm-device-factory.h" #include "libnm-core-intern/nm-core-internal.h" diff --git a/src/core/devices/nm-device-ip-tunnel.c b/src/core/devices/nm-device-ip-tunnel.c index c55dd9f6b2..7f3c0b44f6 100644 --- a/src/core/devices/nm-device-ip-tunnel.c +++ b/src/core/devices/nm-device-ip-tunnel.c @@ -21,7 +21,6 @@ #include "libnm-core-intern/nm-core-internal.h" #include "settings/nm-settings.h" #include "nm-act-request.h" -#include "nm-ip4-config.h" #define _NMLOG_DEVICE_TYPE NMDeviceIPTunnel #include "nm-device-logging.h" diff --git a/src/core/devices/nm-device-macvlan.c b/src/core/devices/nm-device-macvlan.c index 7302ecdf2d..87c18ebe3d 100644 --- a/src/core/devices/nm-device-macvlan.c +++ b/src/core/devices/nm-device-macvlan.c @@ -18,7 +18,6 @@ #include "nm-setting-macvlan.h" #include "nm-setting-wired.h" #include "nm-active-connection.h" -#include "nm-ip4-config.h" #include "nm-utils.h" #define _NMLOG_DEVICE_TYPE NMDeviceMacvlan diff --git a/src/core/devices/nm-device-ppp.c b/src/core/devices/nm-device-ppp.c index 8df245bb0f..c593459685 100644 --- a/src/core/devices/nm-device-ppp.c +++ b/src/core/devices/nm-device-ppp.c @@ -7,7 +7,7 @@ #include "nm-device-ppp.h" -#include "nm-ip4-config.h" +#include "nm-l3-config-data.h" #include "nm-act-request.h" #include "nm-device-factory.h" #include "nm-device-private.h" @@ -24,8 +24,8 @@ /*****************************************************************************/ typedef struct _NMDevicePppPrivate { - NMPPPManager *ppp_manager; - NMIP4Config * ip4_config; + NMPPPManager * ppp_manager; + const NML3ConfigData *l3cd_4; } NMDevicePppPrivate; struct _NMDevicePpp { @@ -93,26 +93,31 @@ ppp_ifindex_set(NMPPPManager *ppp_manager, int ifindex, const char *iface, gpoin } static void -ppp_ip4_config(NMPPPManager *ppp_manager, NMIP4Config *config, gpointer user_data) +ppp_new_config(NMPPPManager * ppp_manager, + int addr_family, + const NML3ConfigData * l3cd, + const NMUtilsIPv6IfaceId *iid, + gpointer user_data) { NMDevice * device = NM_DEVICE(user_data); NMDevicePpp * self = NM_DEVICE_PPP(device); NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE(self); + if (addr_family != AF_INET) + return; + _LOGT(LOGD_DEVICE | LOGD_PPP, "received IPv4 config from pppd"); - if (nm_device_get_state(device) == NM_DEVICE_STATE_IP_CONFIG) { - if (nm_device_activate_ip4_state_in_conf(device)) { - nm_device_activate_schedule_ip_config_result(device, - AF_INET, - NM_IP_CONFIG_CAST(config)); - return; - } - } else { - if (priv->ip4_config) - g_object_unref(priv->ip4_config); - priv->ip4_config = g_object_ref(config); + if (nm_device_get_state(device) != NM_DEVICE_STATE_IP_CONFIG) { + nm_l3_config_data_reset(&priv->l3cd_4, l3cd); + return; } + + if (!nm_device_activate_ip4_state_in_conf(device)) + return; + + nm_device_set_dev2_ip_config(device, AF_INET, l3cd); + nm_device_activate_schedule_ip_config_result(device, AF_INET); } static gboolean @@ -150,18 +155,10 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) s_pppoe = nm_device_get_applied_setting(device, NM_TYPE_SETTING_PPPOE); g_return_val_if_fail(s_pppoe, NM_ACT_STAGE_RETURN_FAILURE); - g_clear_object(&priv->ip4_config); + nm_clear_l3cd(&priv->l3cd_4); priv->ppp_manager = nm_ppp_manager_create(nm_setting_pppoe_get_parent(s_pppoe), &error); - if (priv->ppp_manager) { - nm_ppp_manager_set_route_parameters(priv->ppp_manager, - nm_device_get_route_table(device, AF_INET), - nm_device_get_route_metric(device, AF_INET), - nm_device_get_route_table(device, AF_INET6), - nm_device_get_route_metric(device, AF_INET6)); - } - if (!priv->ppp_manager || !nm_ppp_manager_start(priv->ppp_manager, req, @@ -187,27 +184,27 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) G_CALLBACK(ppp_ifindex_set), self); g_signal_connect(priv->ppp_manager, - NM_PPP_MANAGER_SIGNAL_IP4_CONFIG, - G_CALLBACK(ppp_ip4_config), + NM_PPP_MANAGER_SIGNAL_NEW_CONFIG, + G_CALLBACK(ppp_new_config), self); return NM_ACT_STAGE_RETURN_POSTPONE; } static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) +act_stage3_ip_config_start(NMDevice * device, + int addr_family, + const NML3ConfigData **out_l3cd, + NMDeviceStateReason * out_failure_reason) { if (addr_family == AF_INET) { NMDevicePpp * self = NM_DEVICE_PPP(device); NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE(self); - if (priv->ip4_config) { - if (out_config) - *out_config = g_steal_pointer(&priv->ip4_config); + if (priv->l3cd_4) { + if (out_l3cd) + *out_l3cd = g_steal_pointer(&priv->l3cd_4); else - g_clear_object(&priv->ip4_config); + nm_clear_l3cd(&priv->l3cd_4); return NM_ACT_STAGE_RETURN_SUCCESS; } @@ -216,7 +213,7 @@ act_stage3_ip_config_start(NMDevice * device, } return NM_DEVICE_CLASS(nm_device_ppp_parent_class) - ->act_stage3_ip_config_start(device, addr_family, out_config, out_failure_reason); + ->act_stage3_ip_config_start(device, addr_family, out_l3cd, out_failure_reason); } static gboolean @@ -268,7 +265,7 @@ dispose(GObject *object) NMDevicePpp * self = NM_DEVICE_PPP(object); NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE(self); - g_clear_object(&priv->ip4_config); + nm_clear_l3cd(&priv->l3cd_4); G_OBJECT_CLASS(nm_device_ppp_parent_class)->dispose(object); } diff --git a/src/core/devices/nm-device-private.h b/src/core/devices/nm-device-private.h index eb37b14ffb..73d3f7de36 100644 --- a/src/core/devices/nm-device-private.h +++ b/src/core/devices/nm-device-private.h @@ -34,8 +34,6 @@ enum NMActStageReturn { #define NM_DEVICE_CAP_INTERNAL_MASK 0xc0000000 -void nm_device_arp_announce(NMDevice *self); - NMSettings *nm_device_get_settings(NMDevice *self); NMManager *nm_device_get_manager(NMDevice *self); @@ -66,8 +64,7 @@ void nm_device_set_firmware_missing(NMDevice *self, gboolean missing); void nm_device_activate_schedule_stage1_device_prepare(NMDevice *device, gboolean do_sync); void nm_device_activate_schedule_stage2_device_config(NMDevice *device, gboolean do_sync); -void -nm_device_activate_schedule_ip_config_result(NMDevice *device, int addr_family, NMIPConfig *config); +void nm_device_activate_schedule_ip_config_result(NMDevice *device, int addr_family); void nm_device_activate_schedule_ip_config_timeout(NMDevice *device, int addr_family); @@ -109,8 +106,7 @@ nm_device_activate_ip6_state_done(NMDevice *self) return nm_device_activate_get_ip_state(self, AF_INET6) == NM_DEVICE_IP_STATE_DONE; } -gboolean nm_device_dhcp4_renew(NMDevice *device, gboolean release); -gboolean nm_device_dhcp6_renew(NMDevice *device, gboolean release); +gboolean nm_device_dhcp_renew(NMDevice *device, int addr_family, gboolean release); void nm_device_recheck_available_connections(NMDevice *device); @@ -126,7 +122,7 @@ void nm_device_queue_recheck_available(NMDevice * device, NMDeviceStateReason available_reason, NMDeviceStateReason unavailable_reason); -void nm_device_set_dev2_ip_config(NMDevice *device, int addr_family, NMIPConfig *config); +void nm_device_set_dev2_ip_config(NMDevice *device, int addr_family, const NML3ConfigData *l3cd); gboolean nm_device_hw_addr_is_explict(NMDevice *device); @@ -137,11 +133,7 @@ gboolean nm_device_sysctl_ip_conf_set(NMDevice * self, const char *property, const char *value); -NMIP4Config *nm_device_ip4_config_new(NMDevice *self); - -NMIP6Config *nm_device_ip6_config_new(NMDevice *self); - -NMIPConfig *nm_device_ip_config_new(NMDevice *self, int addr_family); +NML3ConfigData *nm_device_create_l3_config_data(NMDevice *self); NML3ConfigData *nm_device_create_l3_config_data(NMDevice *self); diff --git a/src/core/devices/nm-device-tun.c b/src/core/devices/nm-device-tun.c index ebccddfcf8..e622b7a87c 100644 --- a/src/core/devices/nm-device-tun.c +++ b/src/core/devices/nm-device-tun.c @@ -13,7 +13,6 @@ #include "nm-act-request.h" #include "nm-device-private.h" -#include "nm-ip4-config.h" #include "libnm-platform/nm-platform.h" #include "nm-device-factory.h" #include "nm-setting-tun.h" diff --git a/src/core/devices/nm-device-vlan.c b/src/core/devices/nm-device-vlan.c index 548245f80c..c989dbabc5 100644 --- a/src/core/devices/nm-device-vlan.c +++ b/src/core/devices/nm-device-vlan.c @@ -15,7 +15,6 @@ #include "nm-device-private.h" #include "settings/nm-settings.h" #include "nm-act-request.h" -#include "nm-ip4-config.h" #include "libnm-platform/nm-platform.h" #include "nm-device-factory.h" #include "nm-manager.h" @@ -112,7 +111,6 @@ parent_hwaddr_maybe_changed(NMDevice *parent, GParamSpec *pspec, gpointer user_d NM_PRINT_FMT_QUOTE_STRING(new_mac)); if (new_mac) { nm_device_hw_addr_set(device, new_mac, "vlan-parent", TRUE); - nm_device_arp_announce(device); /* When changing the hw address the interface is taken down, * removing the IPv6 configuration; reapply it. */ diff --git a/src/core/devices/nm-device-vxlan.c b/src/core/devices/nm-device-vxlan.c index f9dfad2a82..035acf873b 100644 --- a/src/core/devices/nm-device-vxlan.c +++ b/src/core/devices/nm-device-vxlan.c @@ -16,7 +16,6 @@ #include "nm-setting-wired.h" #include "settings/nm-settings.h" #include "nm-act-request.h" -#include "nm-ip4-config.h" #include "libnm-core-intern/nm-core-internal.h" #define _NMLOG_DEVICE_TYPE NMDeviceVxlan diff --git a/src/core/devices/nm-device-wireguard.c b/src/core/devices/nm-device-wireguard.c index aa9c46eba6..f305a5c67a 100644 --- a/src/core/devices/nm-device-wireguard.c +++ b/src/core/devices/nm-device-wireguard.c @@ -11,6 +11,7 @@ #include #include "nm-setting-wireguard.h" +#include "nm-l3-config-data.h" #include "libnm-core-intern/nm-core-internal.h" #include "libnm-glib-aux/nm-secret-utils.h" #include "nm-device-private.h" @@ -1624,19 +1625,19 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) return ret; } -static NMIPConfig * +static const NML3ConfigData * _get_dev2_ip_config(NMDeviceWireGuard *self, int addr_family) { - NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); - gs_unref_object NMIPConfig *ip_config = NULL; - NMConnection * connection; - NMSettingWireGuard * s_wg; - guint n_peers; - guint i; - int ip_ifindex; - guint32 route_metric; - guint32 route_table_coerced; - gboolean auto_default_route_enabled; + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + NMConnection * connection; + NMSettingWireGuard * s_wg; + guint n_peers; + guint i; + int ip_ifindex; + guint32 route_metric; + guint32 route_table_coerced; + gboolean auto_default_route_enabled; _auto_default_route_init(self); @@ -1714,11 +1715,10 @@ _get_dev2_ip_config(NMDeviceWireGuard *self, int addr_family) continue; } - if (!ip_config) { - ip_config = nm_device_ip_config_new(NM_DEVICE(self), addr_family); - nm_ip_config_set_config_flags(ip_config, - NM_IP_CONFIG_FLAGS_IGNORE_MERGE_NO_DEFAULT_ROUTES, - 0); + if (!l3cd) { + l3cd = nm_device_create_l3_config_data(NM_DEVICE(self)); + nm_l3_config_data_set_flags(l3cd, + NM_L3_CONFIG_DAT_FLAGS_IGNORE_MERGE_NO_DEFAULT_ROUTES); } nm_utils_ipx_address_clear_host_address(addr_family, &addrbin, NULL, prefix); @@ -1753,27 +1753,30 @@ _get_dev2_ip_config(NMDeviceWireGuard *self, int addr_family) }; } - nm_ip_config_add_route(ip_config, &rt.rx, NULL); + nm_l3_config_data_add_route(l3cd, addr_family, NULL, &rt.rx); } } - return g_steal_pointer(&ip_config); + if (!l3cd) + return NULL; + + return nm_l3_config_data_seal(g_steal_pointer(&l3cd)); } static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) +act_stage3_ip_config_start(NMDevice * device, + int addr_family, + const NML3ConfigData **out_l3cd, + NMDeviceStateReason * out_failure_reason) { - gs_unref_object NMIPConfig *ip_config = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; - ip_config = _get_dev2_ip_config(NM_DEVICE_WIREGUARD(device), addr_family); + l3cd = _get_dev2_ip_config(NM_DEVICE_WIREGUARD(device), addr_family); - nm_device_set_dev2_ip_config(device, addr_family, ip_config); + nm_device_set_dev2_ip_config(device, addr_family, l3cd); return NM_DEVICE_CLASS(nm_device_wireguard_parent_class) - ->act_stage3_ip_config_start(device, addr_family, out_config, out_failure_reason); + ->act_stage3_ip_config_start(device, addr_family, out_l3cd, out_failure_reason); } static guint32 @@ -1863,11 +1866,9 @@ can_reapply_change(NMDevice * device, static void reapply_connection(NMDevice *device, NMConnection *con_old, NMConnection *con_new) { - NMDeviceWireGuard * self = NM_DEVICE_WIREGUARD(device); - NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); - gs_unref_object NMIPConfig *ip4_config = NULL; - gs_unref_object NMIPConfig *ip6_config = NULL; - NMDeviceState state = nm_device_get_state(device); + NMDeviceWireGuard * self = NM_DEVICE_WIREGUARD(device); + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); + NMDeviceState state = nm_device_get_state(device); NM_DEVICE_CLASS(nm_device_wireguard_parent_class)->reapply_connection(device, con_old, con_new); @@ -1877,11 +1878,14 @@ reapply_connection(NMDevice *device, NMConnection *con_old, NMConnection *con_ne } if (state >= NM_DEVICE_STATE_IP_CONFIG) { - ip4_config = _get_dev2_ip_config(self, AF_INET); - ip6_config = _get_dev2_ip_config(self, AF_INET6); + nm_auto_unref_l3cd const NML3ConfigData *l3cd_4 = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd_6 = NULL; + + l3cd_4 = _get_dev2_ip_config(self, AF_INET); + l3cd_6 = _get_dev2_ip_config(self, AF_INET6); - nm_device_set_dev2_ip_config(device, AF_INET, ip4_config); - nm_device_set_dev2_ip_config(device, AF_INET6, ip6_config); + nm_device_set_dev2_ip_config(device, AF_INET, l3cd_4); + nm_device_set_dev2_ip_config(device, AF_INET6, l3cd_6); } } diff --git a/src/core/devices/nm-device-wpan.c b/src/core/devices/nm-device-wpan.c index 73d7941001..2486f18c2d 100644 --- a/src/core/devices/nm-device-wpan.c +++ b/src/core/devices/nm-device-wpan.c @@ -14,7 +14,6 @@ #include "nm-act-request.h" #include "nm-device-private.h" -#include "nm-ip4-config.h" #include "libnm-platform/nm-platform.h" #include "nm-device-factory.h" #include "nm-setting-wpan.h" diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index 21863b9533..ba59d4f53c 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -34,6 +34,7 @@ #include "nm-device-private.h" #include "nm-l3cfg.h" #include "nm-l3-config-data.h" +#include "nm-l3-ipv4ll.h" #include "NetworkManagerUtils.h" #include "nm-manager.h" #include "libnm-platform/nm-platform.h" @@ -45,11 +46,9 @@ #include "dhcp/nm-dhcp-manager.h" #include "dhcp/nm-dhcp-utils.h" #include "nm-act-request.h" -#include "nm-proxy-config.h" -#include "nm-ip4-config.h" -#include "nm-ip6-config.h" #include "nm-pacrunner-manager.h" #include "dnsmasq/nm-dnsmasq-manager.h" +#include "nm-ip-config.h" #include "nm-dhcp-config.h" #include "nm-rfkill-manager.h" #include "nm-firewall-utils.h" @@ -66,7 +65,6 @@ #include "nm-config.h" #include "c-list/src/c-list.h" #include "dns/nm-dns-manager.h" -#include "nm-acd-manager.h" #include "libnm-core-intern/nm-core-internal.h" #include "libnm-systemd-core/nm-sd.h" #include "nm-lldp-listener.h" @@ -85,19 +83,8 @@ #define DEFAULT_AUTOCONNECT TRUE -static guint32 -dhcp_grace_period_from_timeout(guint32 timeout) -{ -#define DHCP_GRACE_PERIOD_MULTIPLIER 2U - - nm_assert(timeout > 0); - nm_assert(timeout < G_MAXINT32); - - if (timeout < G_MAXUINT32 / DHCP_GRACE_PERIOD_MULTIPLIER) - return timeout * DHCP_GRACE_PERIOD_MULTIPLIER; - - return G_MAXUINT32; -} +//XXX: drop GRACE_PERIOD_MULTIPLIER or review it at least. +#define GRACE_PERIOD_MULTIPLIER 2U #define CARRIER_WAIT_TIME_MS 6000 #define CARRIER_WAIT_TIME_AFTER_MTU_MS 10000 @@ -116,6 +103,13 @@ typedef enum { CLEANUP_TYPE_DECONFIGURE, } CleanupType; +typedef enum _nm_packed { + ADDR_METHOD_STATE_DISABLED, + ADDR_METHOD_STATE_PENDING, + ADDR_METHOD_STATE_GOOD, + ADDR_METHOD_STATE_FAILED, +} AddrMethodState; + typedef struct { CList lst_slave; NMDevice *slave; @@ -138,28 +132,40 @@ typedef struct { NMOptionBool autoprobe; } SriovOp; -typedef void (*AcdCallback)(NMDevice *, NMIP4Config **, gboolean); - typedef enum { /* The various NML3ConfigData types that we track explicitly. Note that * their relative order matters: higher numbers in this enum means more * important (and during merge overwrites other settings). */ + L3_CONFIG_DATA_TYPE_LL_4, + L3_CONFIG_DATA_TYPE_LL_6, + +#define L3_CONFIG_DATA_TYPE_LL(IS_IPv4) \ + ((IS_IPv4) ? L3_CONFIG_DATA_TYPE_LL_4 : L3_CONFIG_DATA_TYPE_LL_6) + L3_CONFIG_DATA_TYPE_AC_6, + L3_CONFIG_DATA_TYPE_PD_6, + L3_CONFIG_DATA_TYPE_DHCP_4, L3_CONFIG_DATA_TYPE_DHCP_6, + +#define L3_CONFIG_DATA_TYPE_DHCP_X(IS_IPv4) \ + ((IS_IPv4) ? L3_CONFIG_DATA_TYPE_DHCP_4 : L3_CONFIG_DATA_TYPE_DHCP_6) + + L3_CONFIG_DATA_TYPE_SHARED_4, L3_CONFIG_DATA_TYPE_DEV_4, L3_CONFIG_DATA_TYPE_DEV_6, + +#define L3_CONFIG_DATA_TYPE_DEV_X(IS_IPv4) \ + ((IS_IPv4) ? L3_CONFIG_DATA_TYPE_DEV_4 : L3_CONFIG_DATA_TYPE_DEV_6) + L3_CONFIG_DATA_TYPE_SETTING, + _L3_CONFIG_DATA_TYPE_NUM, _L3_CONFIG_DATA_TYPE_NONE, } L3ConfigDataType; -typedef struct { - AcdCallback callback; - NMDevice * device; - NMIP4Config **configs; -} AcdData; +G_STATIC_ASSERT(NM_L3CFG_CONFIG_PRIORITY_IPV4LL == L3_CONFIG_DATA_TYPE_LL_4); typedef enum { HW_ADDR_TYPE_UNSET = 0, @@ -175,19 +181,47 @@ typedef enum { FIREWALL_STATE_WAIT_IP_CONFIG, } FirewallState; -typedef struct { - NMIPConfig *orig; /* the original configuration applied to the device */ - NMIPConfig *current; /* configuration after external changes. NULL means - * that the original configuration didn't change. */ -} AppliedConfig; +typedef enum _nm_packed { + DHCP_STATE_NONE, + + /* NMDhcpClient is in SELECTING state (or retrying). */ + DHCP_STATE_SELECTING, + + /* We have a lease, but are currently performing ACD on the + * address. */ + DHCP_STATE_PROBING, + + /* ACD passed and we accept the lease. */ + DHCP_STATE_BOUND, + + /* ACD failed, lease timeout or timeout obtaining a lease. This is similar to + * DHCP_STATE_SELECTING in that we try to re-get a lease in the background. + * But we also might fail the connection as a whole in this event. + * + * In this case, we also might have the grace timer running. */ + DHCP_STATE_FAILED, +} DhcpState; + +static NM_UTILS_LOOKUP_STR_DEFINE(_dhcp_state_to_string, + DhcpState, + NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT(NULL), + NM_UTILS_LOOKUP_STR_ITEM(DHCP_STATE_NONE, "none"), + NM_UTILS_LOOKUP_STR_ITEM(DHCP_STATE_SELECTING, "selecting"), + NM_UTILS_LOOKUP_STR_ITEM(DHCP_STATE_BOUND, "bound"), + NM_UTILS_LOOKUP_STR_ITEM(DHCP_STATE_PROBING, "probing"), + NM_UTILS_LOOKUP_STR_ITEM(DHCP_STATE_FAILED, "failed"), ); typedef struct { NMDhcpClient *client; NMDhcpConfig *config; - gulong state_sigid; - guint grace_id; - bool grace_pending : 1; - bool was_active : 1; + + /* this is a timer ticking from when we start doing DHCP until + * ipv[46].dhcp-timeout expires. After that, we either fail the + * connection or we keep trying in the background. */ + GSource *grace_source; + + gulong state_sigid; + DhcpState state; } DhcpData; struct _NMDeviceConnectivityHandle { @@ -234,8 +268,7 @@ typedef struct { enum { STATE_CHANGED, AUTOCONNECT_ALLOWED, - IP4_CONFIG_CHANGED, - IP6_CONFIG_CHANGED, + L3CD_CHANGED, IP6_PREFIX_DELEGATED, IP6_SUBNET_NEEDED, REMOVED, @@ -260,6 +293,9 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMDevice, PROP_IP4_ADDRESS, PROP_IP4_CONFIG, PROP_DHCP4_CONFIG, + +#define PROP_DHCPX_CONFIG(IS_IPv4) ((IS_IPv4) ? PROP_DHCP4_CONFIG : PROP_DHCP6_CONFIG) + PROP_IP6_CONFIG, PROP_DHCP6_CONFIG, PROP_STATE, @@ -293,8 +329,6 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMDevice, PROP_INTERFACE_FLAGS, ); typedef struct _NMDevicePrivate { - bool in_state_changed; - guint device_link_changed_id; guint device_ip_link_changed_id; @@ -308,16 +342,7 @@ typedef struct _NMDevicePrivate { NMDeviceStateReason reason; } queued_state; - union { - struct { - guint queued_ip_config_id_6; - guint queued_ip_config_id_4; - }; - guint queued_ip_config_id_x[2]; - }; - GSList *pending_actions; - GSList *dad6_failed_addrs; NMDBusTrackObjPath parent_device; @@ -333,16 +358,31 @@ typedef struct _NMDevicePrivate { char * ip_iface_; }; + union { + NML3Cfg *const l3cfg; + NML3Cfg * l3cfg_; + }; + + NML3CfgCommitTypeHandle *l3cfg_commit_type; + union { const int ifindex; int ifindex_; }; + union { const int ip_ifindex; int ip_ifindex_; }; - NMNetnsSharedIPHandle *shared_ip_handle; + union { + const NML3ConfigData * d; + const NML3ConfigData *const d_; + } l3cds[_L3_CONFIG_DATA_TYPE_NUM]; + + NMNetnsSharedIPHandle *shared4_ip_handle; + + NMFirewallConfig *firewall_config; int parent_ifindex; @@ -365,9 +405,6 @@ typedef struct _NMDevicePrivate { bool real : 1; - bool update_ip_config_completed_v4 : 1; - bool update_ip_config_completed_v6 : 1; - NMDeviceType type; char * type_desc; NMLinkType link_type; @@ -381,6 +418,8 @@ typedef struct _NMDevicePrivate { bool hw_addr_perm_fake : 1; /* whether the permanent HW address could not be read and is a fake */ + guint8 in_state_changed : 4; + NMUtilsStableType current_stable_id_type : 3; bool nm_owned : 1; /* whether the device is a device owned and created by NM */ @@ -446,7 +485,7 @@ typedef struct _NMDevicePrivate { gulong config_changed_id; gulong ifindex_changed_id; guint32 mtu; - guint32 ip6_mtu; + guint32 ip6_mtu; /* FIXME(l3cfg) */ guint32 mtu_initial; guint32 ip6_mtu_initial; NMDeviceMtuSource mtu_source; @@ -462,6 +501,14 @@ typedef struct _NMDevicePrivate { * in the future. This is used to extend the grace period in this particular case. */ gint64 carrier_wait_until_ms; + union { + struct { + NML3ConfigMergeFlags l3config_merge_flags_6; + NML3ConfigMergeFlags l3config_merge_flags_4; + }; + NML3ConfigMergeFlags l3config_merge_flags_x[2]; + }; + union { const NMDeviceSysIfaceState sys_iface_state; NMDeviceSysIfaceState sys_iface_state_; @@ -492,78 +539,33 @@ typedef struct _NMDevicePrivate { bool ipv6ll_handle : 1; /* TRUE if NM handles the device's IPv6LL address */ bool ipv6ll_has : 1; - bool ndisc_started : 1; + bool ac6_ndisc_started : 1; + bool ac6_ndisc_grace_pending : 1; bool device_link_changed_down : 1; bool concheck_rp_filter_checked : 1; + bool ll4_ipv4ll_ready : 1; + bool ll4_ipv4ll_failed : 1; + NMDeviceStageState stage1_sriov_state : 3; + GSource *ac6_ndisc_grace_source; + char *current_stable_id; - /* Proxy Configuration */ - NMProxyConfig * proxy_config; NMPacrunnerConfId *pacrunner_conf_id; - /* IP configuration info. Combined config from VPN, settings, and device */ union { struct { - NMIP6Config *ip_config_6; - NMIP4Config *ip_config_4; + NMIPConfig *ip_config_6; + NMIPConfig *ip_config_4; }; NMIPConfig *ip_config_x[2]; }; - /* Config from DHCP, PPP, LLv4, etc */ - AppliedConfig dev_ip_config_4; - - /* config from the setting */ - union { - struct { - NMIP6Config *con_ip_config_6; - NMIP4Config *con_ip_config_4; - }; - NMIPConfig *con_ip_config_x[2]; - }; - - /* Stuff added outside NM */ - union { - struct { - NMIP6Config *ext_ip_config_6; - NMIP4Config *ext_ip_config_4; - }; - NMIPConfig *ext_ip_config_x[2]; - }; - - /* VPNs which use this device */ - union { - struct { - GSList *vpn_configs_6; - GSList *vpn_configs_4; - }; - GSList *vpn_configs_x[2]; - }; - - /* Extra device configuration, injected by the subclass of NMDevice. - * This is used for example by NMDeviceModem for WWAN configuration. */ - union { - struct { - AppliedConfig dev2_ip_config_6; - AppliedConfig dev2_ip_config_4; - }; - AppliedConfig dev2_ip_config_x[2]; - }; - - /* DHCPv4 tracking */ - struct { - char *pac_url; - } dhcp4; - struct { - /* IP6 config from DHCP */ - AppliedConfig ip6_config; /* Event ID of the current IP6 config from DHCP */ - char * event_id; gulong prefix_sigid; NMNDiscDHCPLevel mode; guint needed_prefixes; @@ -588,24 +590,17 @@ typedef struct _NMDevicePrivate { } gw_ping; /* dnsmasq stuff for shared connections */ - NMDnsMasqManager *dnsmasq_manager; - gulong dnsmasq_state_id; + NMDnsMasqManager *shared4_dnsmasq_manager; + gulong shared4_dnsmasq_state_id; /* Firewall */ FirewallState fw_state : 4; NMFirewalldManager * fw_mgr; NMFirewalldManagerCallId *fw_call; - /* IPv4LL stuff */ - sd_ipv4ll *ipv4ll; - guint ipv4ll_timeout; - guint rt6_temporary_not_available_id; - - /* IPv4 DAD stuff */ - struct { - GSList * dad_list; - NMAcdManager *announcing; - } acd; + NML3IPv4LL * ll4_ipv4ll; + NML3IPv4LLRegistration *ll4_ipv4ll_registation; + guint ll4_timeout_id; union { struct { @@ -618,17 +613,12 @@ typedef struct _NMDevicePrivate { }; }; - AppliedConfig ac_ip6_config; /* config from IPv6 autoconfiguration */ - NMIP6Config * ext_ip6_config_captured; /* Configuration captured from platform. */ - NMIP6Config * dad6_ip6_config; struct in6_addr ipv6ll_addr; - GHashTable *rt6_temporary_not_available; - - NMNDisc * ndisc; - gulong ndisc_changed_id; - gulong ndisc_timeout_id; - NMSettingIP6ConfigPrivacy ndisc_use_tempaddr; + NMNDisc * ac6_ndisc; + gulong ac6_ndisc_changed_id; + gulong ac6_ndisc_timeout_id; + NMSettingIP6ConfigPrivacy ac6_ip6_privacy; guint linklocal6_timeout_id; guint8 linklocal6_dad_counter; @@ -703,59 +693,66 @@ G_DEFINE_ABSTRACT_TYPE(NMDevice, nm_device, NM_TYPE_DBUS_OBJECT) /*****************************************************************************/ +static NMSettingConnectionMdns _prop_get_connection_mdns(NMDevice *self); +static NMSettingConnectionLlmnr _prop_get_connection_llmnr(NMDevice *self); + static const NMDBusInterfaceInfoExtended interface_info_device; static const GDBusSignalInfo signal_info_state_changed; -static void nm_device_set_proxy_config(NMDevice *self, const char *pac_url); +static void _dev_l3_cfg_commit(NMDevice *self, gboolean commit_now); -static gboolean update_ext_ip_config(NMDevice *self, int addr_family, gboolean intersect_configs); - -static gboolean nm_device_set_ip_config(NMDevice * self, - int addr_family, - NMIPConfig *config, - gboolean commit, - GPtrArray * ip4_dev_route_blacklist); - -static gboolean ip_config_merge_and_apply(NMDevice *self, int addr_family, gboolean commit); +static void _dev_l3_cfg_commit_type_reset(NMDevice *self); static gboolean nm_device_master_add_slave(NMDevice *self, NMDevice *slave, gboolean configure); static void nm_device_slave_notify_enslave(NMDevice *self, gboolean success); static void nm_device_slave_notify_release(NMDevice *self, NMDeviceStateReason reason); -static void addrconf6_start_with_link_ready(NMDevice *self); -static gboolean linklocal6_start(NMDevice *self); +static gboolean _dev_ll6_start(NMDevice *self, struct in6_addr *out_ll_addr); static guint32 default_route_metric_penalty_get(NMDevice *self, int addr_family); static guint _prop_get_ipv4_dad_timeout(NMDevice *self); -static NMIP6Config *dad6_get_pending_addresses(NMDevice *self); - static void _carrier_wait_check_queued_act_request(NMDevice *self); static gint64 _get_carrier_wait_ms(NMDevice *self); +static GBytes *_prop_get_ipv6_dhcp_duid(NMDevice * self, + NMConnection *connection, + GBytes * hwaddr, + gboolean * out_enforce); + static const char *_activation_func_to_string(ActivationHandleFunc func); static void _set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason, gboolean quitting); -static void queued_state_clear(NMDevice *device); -static gboolean queued_ip4_config_change(gpointer user_data); -static gboolean queued_ip6_config_change(gpointer user_data); -static void ip_check_ping_watch_cb(GPid pid, int status, gpointer user_data); -static gboolean ip_config_valid(NMDeviceState state); -static NMActStageReturn dhcp4_start(NMDevice *self); -static gboolean dhcp6_start(NMDevice *self, gboolean wait_for_ll); -static void nm_device_start_ip_check(NMDevice *self); -static void realize_start_setup(NMDevice * self, - const NMPlatformLink *plink, - gboolean assume_state_guess_assume, - const char * assume_state_connection_uuid, - gboolean set_nm_owned, - NMUnmanFlagOp unmanaged_user_explicit, - gboolean force_platform_init); -static void _set_mtu(NMDevice *self, guint32 mtu); -static void _commit_mtu(NMDevice *self, const NMIP4Config *config); -static void _cancel_activation(NMDevice *self); +static void queued_state_clear(NMDevice *device); +static void ip_check_ping_watch_cb(GPid pid, int status, gpointer user_data); +static void nm_device_start_ip_check(NMDevice *self); +static void realize_start_setup(NMDevice * self, + const NMPlatformLink *plink, + gboolean assume_state_guess_assume, + const char * assume_state_connection_uuid, + gboolean set_nm_owned, + NMUnmanFlagOp unmanaged_user_explicit, + gboolean force_platform_init); +static void _set_mtu(NMDevice *self, guint32 mtu); +static void _commit_mtu(NMDevice *self); +static void _cancel_activation(NMDevice *self); + +static void _dev_ll4_notify_event(NMDevice *self); + +static void +_dev_dhcpx_cleanup(NMDevice *self, int addr_family, gboolean reset_dhcp_config, gboolean release); + +static gboolean _dev_dhcpx_set_state(NMDevice *self, int addr_family, DhcpState state); + +static void _dev_dhcp4_notify_acd_result(NMDevice *self, gboolean ready); + +static gboolean _dev_ac6_start(NMDevice *self); + +static void _dev_set_unmanaged_external_down(NMDevice *self, gboolean only_if_unmanaged); + +static gboolean _dev_shared4_start(NMDevice *self, GError **error); static void concheck_update_state(NMDevice * self, int addr_family, @@ -765,7 +762,7 @@ static void concheck_update_state(NMDevice * self, static void sriov_op_cb(GError *error, gpointer user_data); static void device_ifindex_changed_cb(NMManager *manager, NMDevice *device_changed, NMDevice *self); -static gboolean device_link_changed(NMDevice *self); +static gboolean device_link_changed(gpointer user_data); /*****************************************************************************/ @@ -1326,8 +1323,8 @@ _prop_get_ipvx_dhcp_timeout(NMDevice *self, int addr_family) { NMDeviceClass *klass; NMConnection * connection; - int timeout_i; guint32 timeout; + int timeout_i; nm_assert(NM_IS_DEVICE(self)); nm_assert_addr_family(addr_family); @@ -2369,27 +2366,6 @@ concheck_get_mgr(NMDevice *self) return priv->concheck_mgr; } -NMIP4Config * -nm_device_ip4_config_new(NMDevice *self) -{ - return nm_ip4_config_new(nm_device_get_multi_index(self), nm_device_get_ip_ifindex(self)); -} - -NMIP6Config * -nm_device_ip6_config_new(NMDevice *self) -{ - return nm_ip6_config_new(nm_device_get_multi_index(self), nm_device_get_ip_ifindex(self)); -} - -NMIPConfig * -nm_device_ip_config_new(NMDevice *self, int addr_family) -{ - nm_assert_addr_family(addr_family); - - return NM_IS_IPv4(addr_family) ? (gpointer) nm_device_ip4_config_new(self) - : (gpointer) nm_device_ip6_config_new(self); -} - NML3ConfigData * nm_device_create_l3_config_data(NMDevice *self) { @@ -2404,98 +2380,33 @@ nm_device_create_l3_config_data(NMDevice *self) return nm_l3_config_data_new(nm_device_get_multi_index(self), ifindex); } -static void -applied_config_clear(AppliedConfig *config) -{ - g_clear_object(&config->current); - g_clear_object(&config->orig); -} - -static void -applied_config_init(AppliedConfig *config, gpointer ip_config) -{ - nm_assert(!ip_config || (!config->orig && !config->current) - || nm_ip_config_get_addr_family(ip_config) - == nm_ip_config_get_addr_family(config->orig ?: config->current)); - nm_assert(!ip_config || NM_IS_IP_CONFIG(ip_config)); - - nm_g_object_ref(ip_config); - applied_config_clear(config); - config->orig = ip_config; -} - -static void -applied_config_init_new(AppliedConfig *config, NMDevice *self, int addr_family) -{ - gs_unref_object NMIPConfig *c = nm_device_ip_config_new(self, addr_family); - - applied_config_init(config, c); -} - -static NMIPConfig * -applied_config_get_current(AppliedConfig *config) -{ - return config->current ?: config->orig; -} - -static void -applied_config_add_address(AppliedConfig *config, const NMPlatformIPAddress *address) -{ - if (config->orig) - nm_ip_config_add_address(config->orig, address); - else - nm_assert(!config->current); - - if (config->current) - nm_ip_config_add_address(config->current, address); -} - -static void -applied_config_add_nameserver(AppliedConfig *config, const NMIPAddr *ns) -{ - if (config->orig) - nm_ip_config_add_nameserver(config->orig, ns); - else - nm_assert(!config->current); - - if (config->current) - nm_ip_config_add_nameserver(config->current, ns); -} - -static void -applied_config_add_search(AppliedConfig *config, const char *new) +static const NML3ConfigData * +_dev_create_l3_config_data_from_connection(NMDevice *self, NMConnection *connection) { - if (config->orig) - nm_ip_config_add_search(config->orig, new); - else - nm_assert(!config->current); - - if (config->current) - nm_ip_config_add_search(config->current, new); -} + NML3ConfigData *l3cd; + int ifindex; -static void -applied_config_reset_searches(AppliedConfig *config) -{ - if (config->orig) - nm_ip_config_reset_searches(config->orig); - else - nm_assert(!config->current); + nm_assert(NM_IS_DEVICE(self)); + nm_assert(!connection || NM_IS_CONNECTION(self)); - if (config->current) - nm_ip_config_reset_searches(config->current); -} + if (!connection) + return NULL; -static void -applied_config_reset_nameservers(AppliedConfig *config) -{ - if (config->orig) - nm_ip_config_reset_nameservers(config->orig); - else - nm_assert(!config->current); + ifindex = nm_device_get_ip_ifindex(self); + if (ifindex <= 0) + g_return_val_if_reached(NULL); - if (config->current) - nm_ip_config_reset_nameservers(config->current); + l3cd = nm_l3_config_data_new_from_connection(nm_device_get_multi_index(self), + ifindex, + connection, + nm_device_get_route_table(self, AF_INET), + nm_device_get_route_table(self, AF_INET6), + nm_device_get_route_metric(self, AF_INET), + nm_device_get_route_metric(self, AF_INET6)); + nm_l3_config_data_set_source(l3cd, NM_IP_CONFIG_SOURCE_USER); + nm_l3_config_data_set_mdns(l3cd, _prop_get_connection_mdns(self)); + nm_l3_config_data_set_llmnr(l3cd, _prop_get_connection_llmnr(self)); + return nm_l3_config_data_seal(l3cd); } /*****************************************************************************/ @@ -2541,6 +2452,7 @@ nm_device_sys_iface_state_set(NMDevice *self, NMDeviceSysIfaceState sys_iface_st 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; + _dev_l3_cfg_commit_type_reset(self); } /* this function only sets a flag, no immediate actions are initiated. @@ -2653,33 +2565,6 @@ nm_device_assume_state_reset(NMDevice *self) /*****************************************************************************/ -static void -init_ip_config_dns_priority(NMDevice *self, NMIPConfig *config) -{ - const char *property; - int priority; - - property = (nm_ip_config_get_addr_family(config) == AF_INET) - ? NM_CON_DEFAULT("ipv4.dns-priority") - : NM_CON_DEFAULT("ipv6.dns-priority"); - - priority = nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, - property, - self, - G_MININT, - G_MAXINT, - 0); - - if (priority == 0) { - priority = - nm_device_is_vpn(self) ? NM_DNS_PRIORITY_DEFAULT_VPN : NM_DNS_PRIORITY_DEFAULT_NORMAL; - } - - nm_ip_config_set_dns_priority(config, priority); -} - -/*****************************************************************************/ - static char * nm_device_sysctl_ip_conf_get(NMDevice *self, int addr_family, const char *property) { @@ -2847,96 +2732,654 @@ _set_ip_state(NMDevice *self, int addr_family, NMDeviceIPState new_state) } } -/*****************************************************************************/ - -const char * -nm_device_get_udi(NMDevice *self) +static void +_set_ip_state_check(NMDevice *self, int addr_family) { - g_return_val_if_fail(self != NULL, NULL); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + int IS_IPv4; - return NM_DEVICE_GET_PRIVATE(self)->udi; + if (addr_family == AF_UNSPEC) { + _set_ip_state_check(self, AF_INET); + _set_ip_state_check(self, AF_INET6); + return; + } + + IS_IPv4 = NM_IS_IPv4(addr_family); + + if (IS_IPv4) { + //XXX + AddrMethodState addr_method_state_dhcp_4 = ADDR_METHOD_STATE_DISABLED; + + if (priv->dhcp_data_4.client) { + /* DHCP is enabled. */ + if (priv->dhcp_data_4.grace_source) { + /* we are still waiting for DHCP to complete/succeed. */ + addr_method_state_dhcp_4 = ADDR_METHOD_STATE_PENDING; + } + //XXX } else if (priv->dhcp_data_4.is_bad || !priv->l3cds[L3_CONFIG_DATA_TYPE_DHCP_4].d) { + //XXX /* the DHCP configuration is failed. */ + //XXX addr_method_state_dhcp_4 = ADDR_METHOD_STATE_FAILED; + //XXX } else + //XXX addr_method_state_dhcp_4 = ADDR_METHOD_STATE_GOOD; + } + + (void) addr_method_state_dhcp_4; + } + + // FIXME(l3cfg): need to check the current state and derive an overall _set_ip_state() value. + + // FIXME(l3cfg): check for IPv6 addresses in DAD with nm_l3cfg_has_commited_ip6_addresses_pending_dad(). } -const char * -nm_device_get_iface(NMDevice *self) +/*****************************************************************************/ + +static gpointer +_dev_l3_config_data_tag_get(NMDevicePrivate *priv, L3ConfigDataType l3cd_type) { - g_return_val_if_fail(NM_IS_DEVICE(self), NULL); + nm_assert(_NM_INT_NOT_NEGATIVE(l3cd_type) && l3cd_type < G_N_ELEMENTS(priv->l3cds)); - return NM_DEVICE_GET_PRIVATE(self)->iface; + return &priv->l3cds[l3cd_type]; } -static gboolean -_set_ifindex(NMDevice *self, int ifindex, gboolean is_ip_ifindex) +static L3ConfigDataType +_dev_l3_config_data_tag_to_type(NMDevice *self, gconstpointer tag) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - int * p_ifindex; - - if (ifindex < 0) - ifindex = 0; + int d; - p_ifindex = is_ip_ifindex ? &priv->ip_ifindex_ : &priv->ifindex_; + /* In C it is undefined behavior to compare unrelated pointers. + * Work around that by using nm_ptr_to_uintptr(), which casts the pointers + * to integers. + * + * I guess, theoretically it's still a problem to assume that if tag pointers + * somewhere inside priv->l3cds, that the uintptr_t case would also yield + * a value in that range. In practice, I couldn't imaging this not not work + * reliably. */ - if (*p_ifindex == ifindex) - return FALSE; + if (nm_ptr_to_uintptr(tag) < nm_ptr_to_uintptr(&priv->l3cds[0]) + || nm_ptr_to_uintptr(tag) >= nm_ptr_to_uintptr(&priv->l3cds[G_N_ELEMENTS(priv->l3cds)])) + return _L3_CONFIG_DATA_TYPE_NONE; - *p_ifindex = ifindex; + d = ((typeof(priv->l3cds[0]) *) tag) - (&priv->l3cds[0]); - _LOGD(LOGD_DEVICE, "ifindex: set %sifindex %d", is_ip_ifindex ? "ip-" : "", ifindex); + nm_assert(d >= 0); + nm_assert(d < _L3_CONFIG_DATA_TYPE_NUM); + nm_assert(tag == &priv->l3cds[d]); + nm_assert(tag == _dev_l3_config_data_tag_get(priv, d)); + return d; +} - if (!is_ip_ifindex) - _notify(self, PROP_IFINDEX); +static L3ConfigDataType +_dev_l3_config_data_acd_addr_info_to_type(NMDevice * self, + const NML3AcdAddrInfo *addr_info, + guint i_track_infos) +{ + nm_assert(NM_IS_DEVICE(self)); + nm_assert(addr_info); + nm_assert(i_track_infos < addr_info->n_track_infos); - if (priv->manager) - nm_manager_emit_device_ifindex_changed(priv->manager, self); - return TRUE; + return _dev_l3_config_data_tag_to_type(self, addr_info->track_infos[i_track_infos].tag); } -/** - * nm_device_take_over_link: - * @self: the #NMDevice - * @ifindex: a ifindex - * @old_name: (transfer full): on return, the name of the old link, if - * the link was renamed - * @error: location to store error, or %NULL - * - * Given an existing link, move it under the control of a device. In - * particular, the link will be renamed to match the device name. If the - * link was renamed, the old name is returned in @old_name. - * - * Returns: %TRUE if the device took control of the link, %FALSE otherwise - */ -gboolean -nm_device_take_over_link(NMDevice *self, int ifindex, char **old_name, GError **error) +static gboolean +_dev_l3_config_data_acd_addr_info_has(NMDevice * self, + const NML3AcdAddrInfo *addr_info, + L3ConfigDataType l3cd_type) { - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - const NMPlatformLink *plink; - NMPlatform * platform; + guint i; - nm_assert(ifindex > 0); - NM_SET_OUT(old_name, NULL); + nm_assert(NM_IS_DEVICE(self)); + nm_assert(addr_info); + nm_assert(_NM_INT_NOT_NEGATIVE(l3cd_type) && l3cd_type < _L3_CONFIG_DATA_TYPE_NUM); - if (priv->ifindex > 0 && priv->ifindex != ifindex) { - nm_utils_error_set(error, - NM_UTILS_ERROR_UNKNOWN, - "the device already has ifindex %d", - priv->ifindex); - return FALSE; + for (i = 0; i < addr_info->n_track_infos; i++) { + if (l3cd_type == _dev_l3_config_data_acd_addr_info_to_type(self, addr_info, i)) + return TRUE; } + return FALSE; +} - platform = nm_device_get_platform(self); - plink = nm_platform_link_get(platform, ifindex); - if (!plink) { - nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "link %d not found", ifindex); - return FALSE; - } +static void +_dev_l3_get_config_settings(NMDevice * self, + L3ConfigDataType type, + NML3ConfigMergeFlags *out_merge_flags, + NML3AcdDefendType * out_acd_defend_type, + guint32 * out_acd_timeout_msec) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NML3ConfigMergeFlags flags; + NMConnection * connection; + NMSettingIPConfig * s_ip; - if (!nm_streq(plink->name, nm_device_get_iface(self))) { - gboolean up; - gboolean success; - gs_free char *name = NULL; + nm_assert(_NM_INT_NOT_NEGATIVE(type) && type < _L3_CONFIG_DATA_TYPE_NUM); - up = NM_FLAGS_HAS(plink->n_ifi_flags, IFF_UP); - name = g_strdup(plink->name); + if (G_UNLIKELY(!priv->l3config_merge_flags_has)) { + int IS_IPv4; + + connection = nm_device_get_applied_connection(self); + + for (IS_IPv4 = 0; IS_IPv4 < 2; IS_IPv4++) { + flags = NM_L3_CONFIG_MERGE_FLAGS_NONE; + + if (connection + && (s_ip = nm_connection_get_setting_ip_config(connection, + IS_IPv4 ? AF_INET : AF_INET6))) { + if (nm_setting_ip_config_get_ignore_auto_routes(s_ip)) + flags |= NM_L3_CONFIG_MERGE_FLAGS_NO_ROUTES; + + if (nm_setting_ip_config_get_ignore_auto_dns(s_ip)) + flags |= NM_L3_CONFIG_MERGE_FLAGS_NO_DNS; + + if (nm_setting_ip_config_get_never_default(s_ip) + || nm_setting_ip_config_get_gateway(s_ip)) { + /* if the connection has an explicit gateway, we also ignore + * the default routes from other sources. */ + flags |= NM_L3_CONFIG_MERGE_FLAGS_NO_DEFAULT_ROUTES; + } + } + + priv->l3config_merge_flags_x[IS_IPv4] = flags; + } + priv->l3config_merge_flags_has = TRUE; + } + + switch (type) { + case L3_CONFIG_DATA_TYPE_SETTING: + case L3_CONFIG_DATA_TYPE_LL_4: + case L3_CONFIG_DATA_TYPE_LL_6: + case L3_CONFIG_DATA_TYPE_PD_6: + case L3_CONFIG_DATA_TYPE_SHARED_4: + case L3_CONFIG_DATA_TYPE_DHCP_4: + case L3_CONFIG_DATA_TYPE_DEV_4: + case L3_CONFIG_DATA_TYPE_AC_6: + case L3_CONFIG_DATA_TYPE_DHCP_6: + case L3_CONFIG_DATA_TYPE_DEV_6: + *out_acd_timeout_msec = _prop_get_ipv4_dad_timeout(self); + break; + + case _L3_CONFIG_DATA_TYPE_NUM: + case _L3_CONFIG_DATA_TYPE_NONE: + *out_acd_timeout_msec = nm_assert_unreachable_val(0); + break; + } + + switch (type) { + case L3_CONFIG_DATA_TYPE_LL_4: + *out_acd_defend_type = NM_L3_ACD_DEFEND_TYPE_ONCE; + break; + + case L3_CONFIG_DATA_TYPE_SETTING: + case L3_CONFIG_DATA_TYPE_LL_6: + case L3_CONFIG_DATA_TYPE_PD_6: + case L3_CONFIG_DATA_TYPE_SHARED_4: + case L3_CONFIG_DATA_TYPE_DHCP_4: + case L3_CONFIG_DATA_TYPE_DEV_4: + case L3_CONFIG_DATA_TYPE_AC_6: + case L3_CONFIG_DATA_TYPE_DHCP_6: + case L3_CONFIG_DATA_TYPE_DEV_6: + *out_acd_defend_type = NM_L3_ACD_DEFEND_TYPE_ALWAYS; + break; + + case _L3_CONFIG_DATA_TYPE_NUM: + case _L3_CONFIG_DATA_TYPE_NONE: + *out_acd_defend_type = nm_assert_unreachable_val(NM_L3_ACD_DEFEND_TYPE_ALWAYS); + break; + } + + switch (type) { + case L3_CONFIG_DATA_TYPE_SETTING: + case L3_CONFIG_DATA_TYPE_LL_4: + case L3_CONFIG_DATA_TYPE_LL_6: + case L3_CONFIG_DATA_TYPE_PD_6: + case L3_CONFIG_DATA_TYPE_SHARED_4: + *out_merge_flags = NM_L3_CONFIG_MERGE_FLAGS_NONE; + break; + + case L3_CONFIG_DATA_TYPE_DHCP_4: + case L3_CONFIG_DATA_TYPE_DEV_4: + *out_merge_flags = priv->l3config_merge_flags_4; + break; + + case L3_CONFIG_DATA_TYPE_AC_6: + case L3_CONFIG_DATA_TYPE_DHCP_6: + case L3_CONFIG_DATA_TYPE_DEV_6: + *out_merge_flags = priv->l3config_merge_flags_6; + break; + + case _L3_CONFIG_DATA_TYPE_NUM: + case _L3_CONFIG_DATA_TYPE_NONE: + *out_merge_flags = nm_assert_unreachable_val(NM_L3_CONFIG_MERGE_FLAGS_NONE); + break; + } +} + +static gboolean +_dev_l3_register_l3cds_add_config(NMDevice *self, L3ConfigDataType l3cd_type) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NML3ConfigMergeFlags merge_flags; + NML3AcdDefendType acd_defend_type; + guint32 acd_timeout_msec; + + _dev_l3_get_config_settings(self, l3cd_type, &merge_flags, &acd_defend_type, &acd_timeout_msec); + return nm_l3cfg_add_config(priv->l3cfg, + _dev_l3_config_data_tag_get(priv, l3cd_type), + FALSE, + priv->l3cds[l3cd_type].d, + l3cd_type, + nm_device_get_route_table(self, AF_INET), + nm_device_get_route_table(self, AF_INET6), + nm_device_get_route_metric(self, AF_INET), + nm_device_get_route_metric(self, AF_INET6), + default_route_metric_penalty_get(self, AF_INET), + default_route_metric_penalty_get(self, AF_INET6), + acd_defend_type, + acd_timeout_msec, + merge_flags); +} + +static gboolean +_dev_l3_register_l3cds_set_one(NMDevice * self, + L3ConfigDataType l3cd_type, + const NML3ConfigData *l3cd, + NMTernary commit_sync) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + nm_auto_unref_l3cd const NML3ConfigData *l3cd_old = NULL; + gboolean changed = FALSE; + + if (priv->l3cds[l3cd_type].d != l3cd) { + l3cd_old = g_steal_pointer(&priv->l3cds[l3cd_type].d); + if (l3cd) + priv->l3cds[l3cd_type].d = nm_l3_config_data_ref_and_seal(l3cd); + } + + if (priv->l3cfg) { + if (priv->l3cds[l3cd_type].d) { + if (_dev_l3_register_l3cds_add_config(self, l3cd_type)) + changed = TRUE; + } + + if (l3cd_old && l3cd_old != priv->l3cds[l3cd_type].d) { + if (nm_l3cfg_remove_config(priv->l3cfg, + _dev_l3_config_data_tag_get(priv, l3cd_type), + l3cd_old)) + changed = TRUE; + } + } + + if (changed && commit_sync != NM_TERNARY_DEFAULT) + _dev_l3_cfg_commit(self, !!commit_sync); + + return changed; +} + +static gboolean +_dev_l3_register_l3cds(NMDevice *self, + NML3Cfg * l3cfg, + gboolean do_add /* else remove */, + NMTernary do_commit) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gboolean is_external; + gboolean changed; + int i; + + if (!l3cfg) + return FALSE; + + is_external = nm_device_sys_iface_state_is_external(self); + + changed = FALSE; + for (i = 0; i < (int) G_N_ELEMENTS(priv->l3cds); i++) { + if (!priv->l3cds[i].d) + continue; + if (!do_add) { + if (nm_l3cfg_remove_config(l3cfg, + _dev_l3_config_data_tag_get(priv, i), + priv->l3cds[i].d)) + changed = TRUE; + continue; + } + if (is_external) + continue; + if (_dev_l3_register_l3cds_add_config(self, i)) + changed = TRUE; + } + + if (do_commit == NM_TERNARY_DEFAULT) + do_commit = changed; + if (do_commit) + _dev_l3_cfg_commit(self, TRUE); + + return changed; +} + +/*****************************************************************************/ + +static void +_dev_l3_notify_change(NMDevice *self, int addr_family) +{ + /* FIXME(l3cfg) */ + nm_device_activate_schedule_ip_config_result(self, addr_family); +} + +static void +_dev_l3_cfg_commit(NMDevice *self, gboolean commit_sync) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + + if (!priv->l3cfg) + return; + + if (!commit_sync) { + nm_l3cfg_commit_on_idle_schedule(priv->l3cfg); + return; + } + nm_l3cfg_commit(priv->l3cfg, NM_L3_CFG_COMMIT_TYPE_AUTO); +} + +static void +_dev_l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + + nm_assert(l3cfg == priv->l3cfg); + + /* FIXME(l3cfg) */ + switch (notify_data->notify_type) { + case NM_L3_CONFIG_NOTIFY_TYPE_L3CD_CHANGED: + if (notify_data->l3cd_changed.commited) { + g_signal_emit(self, + signals[L3CD_CHANGED], + 0, + notify_data->l3cd_changed.l3cd_old, + notify_data->l3cd_changed.l3cd_new); + } + return; + case NM_L3_CONFIG_NOTIFY_TYPE_ACD_EVENT: + { + const NML3AcdAddrInfo *addr_info = ¬ify_data->acd_event.info; + gboolean has_dhcp_4; + + if (addr_info->state <= NM_L3_ACD_ADDR_STATE_PROBING) { + /* still probing... */ + return; + } + + has_dhcp_4 = + _dev_l3_config_data_acd_addr_info_has(self, addr_info, L3_CONFIG_DATA_TYPE_DHCP_4); + if (has_dhcp_4) { + if (addr_info->state <= NM_L3_ACD_ADDR_STATE_USED) + _dev_dhcp4_notify_acd_result(self, FALSE); + else + _dev_dhcp4_notify_acd_result(self, TRUE); + return; + } + + /* other types for ACD results for non-DHCPv4 sources we currently ignore. */ + return; + } + case NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT: + /* FIXME(l3cfg) */ + _dev_l3_notify_change(self, AF_INET); + return; + case NM_L3_CONFIG_NOTIFY_TYPE_IPV4LL_EVENT: + if (priv->ll4_ipv4ll == notify_data->ipv4ll_event.ipv4ll) + _dev_ll4_notify_event(self); + return; + case NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE: + case NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED: + /* FIXME(l3cfg) */ + return; + case NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE: + if (NM_FLAGS_ANY(notify_data->platform_change_on_idle.obj_type_flags, + nmp_object_type_to_flags(NMP_OBJECT_TYPE_IP4_ADDRESS) + | nmp_object_type_to_flags(NMP_OBJECT_TYPE_IP4_ROUTE))) + _dev_l3_notify_change(self, AF_INET); + if (NM_FLAGS_ANY(notify_data->platform_change_on_idle.obj_type_flags, + nmp_object_type_to_flags(NMP_OBJECT_TYPE_IP6_ADDRESS) + | nmp_object_type_to_flags(NMP_OBJECT_TYPE_IP6_ROUTE))) + _dev_l3_notify_change(self, AF_INET6); + + _dev_set_unmanaged_external_down(self, TRUE); + return; + case _NM_L3_CONFIG_NOTIFY_TYPE_NUM: + break; + } + nm_assert_not_reached(); +} + +static void +_dev_l3_cfg_commit_type_reset(NMDevice *self) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NML3CfgCommitType commit_type; + + if (!priv->l3cfg) + return; + + switch (priv->sys_iface_state) { + case NM_DEVICE_SYS_IFACE_STATE_EXTERNAL: + case NM_DEVICE_SYS_IFACE_STATE_REMOVED: + commit_type = NM_L3_CFG_COMMIT_TYPE_NONE; + goto do_set; + case NM_DEVICE_SYS_IFACE_STATE_ASSUME: + commit_type = NM_L3_CFG_COMMIT_TYPE_ASSUME; + goto do_set; + case NM_DEVICE_SYS_IFACE_STATE_MANAGED: + commit_type = NM_L3_CFG_COMMIT_TYPE_UPDATE; + goto do_set; + } + nm_assert_not_reached(); + return; + +do_set: + priv->l3cfg_commit_type = + nm_l3cfg_commit_type_register(priv->l3cfg, commit_type, priv->l3cfg_commit_type); +} + +/*****************************************************************************/ + +//XXX FIXME(l3cfg) +_nm_unused static gboolean +_dev_l3_set_l3cd_setting(NMDevice *self) +{ + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + + l3cd = _dev_create_l3_config_data_from_connection(self, nm_device_get_applied_connection(self)); + return _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_SETTING, l3cd, FALSE); +} + +static gboolean +_dev_l3_set_l3cd_ll_6(NMDevice *self) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + + if (priv->ipv6ll_has) { + const NMPlatformIP6Address ll_a = { + .address = priv->ipv6ll_addr, + .plen = 64, + .addr_source = NM_IP_CONFIG_SOURCE_IP6LL, + }; + const NMPlatformIP6Route ll_r = { + .network.s6_addr16[0] = htons(0xfe80u), + .plen = 64, + .metric = nm_device_get_route_metric(self, AF_INET6), + .rt_source = NM_IP_CONFIG_SOURCE_IP6LL, + }; + + nm_assert(IN6_IS_ADDR_LINKLOCAL(&priv->ipv6ll_addr)); + + l3cd = nm_device_create_l3_config_data(self); + nm_l3_config_data_set_source(l3cd, NM_IP_CONFIG_SOURCE_IP6LL); + nm_l3_config_data_add_address_6(l3cd, &ll_a); + nm_l3_config_data_add_route_6(l3cd, &ll_r); + nm_l3_config_data_seal(l3cd); + } + + return _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_LL_6, l3cd, FALSE); +} + +/*****************************************************************************/ + +const char * +nm_device_get_udi(NMDevice *self) +{ + g_return_val_if_fail(self != NULL, NULL); + + return NM_DEVICE_GET_PRIVATE(self)->udi; +} + +const char * +nm_device_get_iface(NMDevice *self) +{ + g_return_val_if_fail(NM_IS_DEVICE(self), NULL); + + return NM_DEVICE_GET_PRIVATE(self)->iface; +} + +static gboolean +_set_ifindex(NMDevice *self, int ifindex, gboolean is_ip_ifindex) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gs_unref_object NML3Cfg *l3cfg_old = NULL; + NML3CfgCommitTypeHandle *l3cfg_commit_type_old = NULL; + gboolean l3_changed; + int ip_ifindex_new; + int * p_ifindex; + gboolean l3cfg_was_reset = FALSE; + + if (ifindex < 0) { + nm_assert_not_reached(); + ifindex = 0; + } + + p_ifindex = is_ip_ifindex ? &priv->ip_ifindex_ : &priv->ifindex_; + + if (*p_ifindex == ifindex) + return FALSE; + + *p_ifindex = ifindex; + + ip_ifindex_new = nm_device_get_ip_ifindex(self); + + if (priv->l3cfg) { + if (ip_ifindex_new <= 0 || ip_ifindex_new != nm_l3cfg_get_ifindex(priv->l3cfg)) { + g_signal_handlers_disconnect_by_func(priv->l3cfg, + G_CALLBACK(_dev_l3_cfg_notify_cb), + self); + l3cfg_old = g_steal_pointer(&priv->l3cfg_); + l3cfg_commit_type_old = g_steal_pointer(&priv->l3cfg_commit_type); + l3cfg_was_reset = TRUE; + } + } + if (!priv->l3cfg && ip_ifindex_new > 0) { + priv->l3cfg_ = nm_netns_access_l3cfg(priv->netns, ip_ifindex_new); + + g_signal_connect(priv->l3cfg, + NM_L3CFG_SIGNAL_NOTIFY, + G_CALLBACK(_dev_l3_cfg_notify_cb), + self); + + _dev_l3_cfg_commit_type_reset(self); + l3cfg_was_reset = TRUE; + } + + _LOGD(LOGD_DEVICE, + "ifindex: set %sifindex %d%s%s%s%s%s%s", + is_ip_ifindex ? "ip-" : "", + ifindex, + NM_PRINT_FMT_QUOTED(l3cfg_old && l3cfg_old != priv->l3cfg, + " (old-l3cfg: ", + nm_hash_obfuscated_ptr_str_a(l3cfg_old), + ")", + ""), + NM_PRINT_FMT_QUOTED(priv->l3cfg && l3cfg_old != priv->l3cfg, + " (l3cfg: ", + nm_hash_obfuscated_ptr_str_a(priv->l3cfg), + ")", + "")); + + if (priv->manager) + nm_manager_emit_device_ifindex_changed(priv->manager, self); + + if (!is_ip_ifindex) + _notify(self, PROP_IFINDEX); + + if (l3cfg_was_reset) { + nm_ip_config_take_and_unexport_on_idle(g_steal_pointer(&priv->ip_config_4)); + nm_ip_config_take_and_unexport_on_idle(g_steal_pointer(&priv->ip_config_6)); + if (priv->l3cfg) { + priv->ip_config_4 = nm_ip_config_new(AF_INET, priv->l3cfg, FALSE); + priv->ip_config_6 = nm_ip_config_new(AF_INET6, priv->l3cfg, FALSE); + } + _notify(self, PROP_IP4_CONFIG); + _notify(self, PROP_IP6_CONFIG); + } + + l3_changed = FALSE; + if (_dev_l3_register_l3cds(self, priv->l3cfg, TRUE, FALSE)) + l3_changed = TRUE; + if (_dev_l3_register_l3cds(self, l3cfg_old, FALSE, FALSE)) + l3_changed = TRUE; + + if (l3_changed) + _dev_l3_cfg_commit(self, TRUE); + + if (l3cfg_commit_type_old) + nm_l3cfg_commit_type_unregister(l3cfg_old, l3cfg_commit_type_old); + + return TRUE; +} + +/** + * nm_device_take_over_link: + * @self: the #NMDevice + * @ifindex: a ifindex + * @old_name: (transfer full): on return, the name of the old link, if + * the link was renamed + * @error: location to store error, or %NULL + * + * Given an existing link, move it under the control of a device. In + * particular, the link will be renamed to match the device name. If the + * link was renamed, the old name is returned in @old_name. + * + * Returns: %TRUE if the device took control of the link, %FALSE otherwise + */ +gboolean +nm_device_take_over_link(NMDevice *self, int ifindex, char **old_name, GError **error) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + const NMPlatformLink *plink; + NMPlatform * platform; + + nm_assert(ifindex > 0); + NM_SET_OUT(old_name, NULL); + + if (priv->ifindex > 0 && priv->ifindex != ifindex) { + nm_utils_error_set(error, + NM_UTILS_ERROR_UNKNOWN, + "the device already has ifindex %d", + priv->ifindex); + return FALSE; + } + + platform = nm_device_get_platform(self); + plink = nm_platform_link_get(platform, ifindex); + if (!plink) { + nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "link %d not found", ifindex); + return FALSE; + } + + if (!nm_streq(plink->name, nm_device_get_iface(self))) { + gboolean up; + gboolean success; + gs_free char *name = NULL; + + up = NM_FLAGS_HAS(plink->n_ifi_flags, IFF_UP); + name = g_strdup(plink->name); /* Rename the link to the device ifname */ if (up) @@ -3623,7 +4066,8 @@ nm_device_get_route_metric_default(NMDeviceType device_type) return 11000; } -static gboolean +//XXX FIXME(l3cfg) +_nm_unused static gboolean default_route_metric_penalty_detect(NMDevice *self, int addr_family) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); @@ -3707,28 +4151,22 @@ nm_device_get_route_table(NMDevice *self, int addr_family) return route_table ?: (guint32) RT_TABLE_MAIN; } -static NMIPRouteTableSyncMode +//XXX +_nm_unused static NMIPRouteTableSyncMode _get_route_table_sync_mode_stateful(NMDevice *self, int addr_family) { - const int IS_IPv4 = NM_IS_IPv4(addr_family); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMDedupMultiIter ipconf_iter; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); gboolean all_sync_now; gboolean all_sync_eff; all_sync_now = _prop_get_ipvx_route_table(self, addr_family) != 0u; if (!all_sync_now) { - const NMPlatformIPRoute *route; + const NML3ConfigData *l3cd = priv->l3cds[L3_CONFIG_DATA_TYPE_SETTING].d; /* If there's a local route switch to all-sync in order * to properly manage the local table */ - nm_ip_config_iter_ip_route_for_each (&ipconf_iter, priv->con_ip_config_x[IS_IPv4], &route) { - if (nm_platform_route_type_uncoerce(route->type_coerced) == RTN_LOCAL) { - all_sync_now = TRUE; - break; - } - } + all_sync_now = l3cd && nm_l3_config_data_has_routes_with_type_local(l3cd, addr_family); } if (all_sync_now) @@ -3760,18 +4198,10 @@ nm_device_get_best_default_route(NMDevice *self, int addr_family) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - switch (addr_family) { - case AF_INET: - return priv->ip_config_4 ? nm_ip4_config_best_default_route_get(priv->ip_config_4) : NULL; - case AF_INET6: - return priv->ip_config_6 ? nm_ip6_config_best_default_route_get(priv->ip_config_6) : NULL; - case AF_UNSPEC: - return (priv->ip_config_4 ? nm_ip4_config_best_default_route_get(priv->ip_config_4) : NULL) - ?: (priv->ip_config_6 ? nm_ip6_config_best_default_route_get(priv->ip_config_6) - : NULL); - default: - g_return_val_if_reached(NULL); - } + if (!priv->l3cfg) + return NULL; + + return nm_l3cfg_get_best_default_route(priv->l3cfg, addr_family, TRUE); } const char * @@ -4326,14 +4756,8 @@ concheck_update_state(NMDevice * self, _notify(self, IS_IPv4 ? PROP_IP4_CONNECTIVITY : PROP_IP6_CONNECTIVITY); - if (priv->state == NM_DEVICE_STATE_ACTIVATED && !nm_device_sys_iface_state_is_external(self)) { - if (nm_device_get_best_default_route(self, AF_INET) - && !ip_config_merge_and_apply(self, AF_INET, TRUE)) - _LOGW(LOGD_IP4, "Failed to update IPv4 route metric"); - if (nm_device_get_best_default_route(self, AF_INET6) - && !ip_config_merge_and_apply(self, AF_INET6, TRUE)) - _LOGW(LOGD_IP6, "Failed to update IPv6 route metric"); - } + if (priv->state == NM_DEVICE_STATE_ACTIVATED && !nm_device_sys_iface_state_is_external(self)) + _dev_l3_register_l3cds(self, priv->l3cfg, AF_UNSPEC, NM_TERNARY_DEFAULT); } static const char * @@ -4700,10 +5124,6 @@ nm_device_master_enslave_slave(NMDevice *self, NMDevice *slave, NMConnection *co */ nm_device_update_hw_address(self); - /* Send ARP announcements if did not yet and have addresses. */ - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE && !priv->acd.announcing) - nm_device_arp_announce(self); - /* Restart IP configuration if we're waiting for slaves. Do this * after updating the hardware address as IP config may need the * new address. @@ -4719,7 +5139,7 @@ nm_device_master_enslave_slave(NMDevice *self, NMDevice *slave, NMConnection *co /* Since slave devices don't have their own IP configuration, * set the MTU here. */ - _commit_mtu(slave, NM_DEVICE_GET_PRIVATE(slave)->ip_config_4); + _commit_mtu(slave); return success; } @@ -4837,7 +5257,7 @@ is_unmanaged_external_down(NMDevice *self, gboolean consider_can) } static void -set_unmanaged_external_down(NMDevice *self, gboolean only_if_unmanaged) +_dev_set_unmanaged_external_down(NMDevice *self, gboolean only_if_unmanaged) { NMUnmanFlagOp ext_flags; @@ -4877,26 +5297,26 @@ nm_device_update_dynamic_ip_setup(NMDevice *self) g_hash_table_remove_all(priv->ip6_saved_properties); - if (priv->dhcp_data_4.client) { - if (!nm_device_dhcp4_renew(self, FALSE)) { + if (priv->dhcp_data_4.state != DHCP_STATE_NONE) { + if (!nm_device_dhcp_renew(self, AF_INET, FALSE)) { nm_device_state_changed(self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_DHCP_FAILED); return; } } - if (priv->dhcp_data_6.client) { - if (!nm_device_dhcp6_renew(self, FALSE)) { + if (priv->dhcp_data_6.state != DHCP_STATE_NONE) { + if (!nm_device_dhcp_renew(self, AF_INET6, FALSE)) { nm_device_state_changed(self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_DHCP_FAILED); return; } } - if (priv->ndisc) { + if (priv->ac6_ndisc) { /* FIXME: todo */ } - if (priv->dnsmasq_manager) { + if (priv->shared4_dnsmasq_manager) { /* FIXME: todo */ } } @@ -5163,82 +5583,20 @@ device_ifindex_changed_cb(NMManager *manager, NMDevice *device_changed, NMDevice } static void -ndisc_set_router_config(NMNDisc *ndisc, NMDevice *self) +_dev_ac6_ndisc_set_router_config(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - gs_unref_array GArray *addresses = NULL; - gs_unref_array GArray *dns_servers = NULL; - gs_unref_array GArray * dns_domains = NULL; - guint len; - guint i; - const NMDedupMultiHeadEntry *head_entry; - NMDedupMultiIter ipconf_iter; + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + const NML3ConfigData *l3cd; - if (nm_ndisc_get_node_type(ndisc) != NM_NDISC_NODE_TYPE_ROUTER) + if (!priv->ac6_ndisc) return; - head_entry = nm_ip6_config_lookup_addresses(priv->ip_config_6); - addresses = - g_array_sized_new(FALSE, TRUE, sizeof(NMNDiscAddress), head_entry ? head_entry->len : 0); - nm_dedup_multi_iter_for_each (&ipconf_iter, head_entry) { - const NMPlatformIP6Address *addr = NMP_OBJECT_CAST_IP6_ADDRESS(ipconf_iter.current->obj); - NMNDiscAddress * ndisc_addr; - guint32 lifetime; - guint32 preferred; - - if (IN6_IS_ADDR_UNSPECIFIED(&addr->address) || IN6_IS_ADDR_LINKLOCAL(&addr->address)) - continue; - - if (addr->n_ifa_flags & IFA_F_TENTATIVE || addr->n_ifa_flags & IFA_F_DADFAILED) - continue; - - if (addr->plen != 64) - continue; - - lifetime = nmp_utils_lifetime_get(addr->timestamp, - addr->lifetime, - addr->preferred, - NM_NDISC_EXPIRY_BASE_TIMESTAMP / 1000, - &preferred); - if (!lifetime) - continue; - - g_array_set_size(addresses, addresses->len + 1); - ndisc_addr = &g_array_index(addresses, NMNDiscAddress, addresses->len - 1); - ndisc_addr->address = addr->address; - ndisc_addr->expiry_msec = - _nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, lifetime); - ndisc_addr->expiry_preferred_msec = - _nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, preferred); - } - - len = nm_ip6_config_get_num_nameservers(priv->ip_config_6); - dns_servers = g_array_sized_new(FALSE, TRUE, sizeof(NMNDiscDNSServer), len); - g_array_set_size(dns_servers, len); - for (i = 0; i < len; i++) { - const struct in6_addr *nameserver = nm_ip6_config_get_nameserver(priv->ip_config_6, i); - NMNDiscDNSServer * ndisc_nameserver; - - ndisc_nameserver = &g_array_index(dns_servers, NMNDiscDNSServer, i); - ndisc_nameserver->address = *nameserver; - ndisc_nameserver->expiry_msec = - _nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, NM_NDISC_ROUTER_LIFETIME); - } - - len = nm_ip6_config_get_num_searches(priv->ip_config_6); - dns_domains = g_array_sized_new(FALSE, TRUE, sizeof(NMNDiscDNSDomain), len); - g_array_set_size(dns_domains, len); - for (i = 0; i < len; i++) { - const char * search = nm_ip6_config_get_search(priv->ip_config_6, i); - NMNDiscDNSDomain *ndisc_search; - - ndisc_search = &g_array_index(dns_domains, NMNDiscDNSDomain, i); - ndisc_search->domain = (char *) search; - ndisc_search->expiry_msec = - _nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, NM_NDISC_ROUTER_LIFETIME); - } + if (nm_ndisc_get_node_type(priv->ac6_ndisc) != NM_NDISC_NODE_TYPE_ROUTER) + return; - nm_ndisc_set_config(ndisc, addresses, dns_servers, dns_domains); + l3cd = nm_l3cfg_get_combined_l3cd(priv->l3cfg, FALSE); + if (l3cd) + nm_ndisc_set_config(priv->ac6_ndisc, l3cd); } static void @@ -5272,8 +5630,9 @@ device_update_interface_flags(NMDevice *self, const NMPlatformLink *plink) } static gboolean -device_link_changed(NMDevice *self) +device_link_changed(gpointer user_data) { + NMDevice * self = user_data; NMDeviceClass * klass = NM_DEVICE_GET_CLASS(self); NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); gboolean ip_ifname_changed = FALSE; @@ -5358,8 +5717,8 @@ device_link_changed(NMDevice *self) nm_device_emit_recheck_auto_activate(self); } - if (priv->ndisc && pllink->inet6_token.id) { - if (nm_ndisc_set_iid(priv->ndisc, pllink->inet6_token)) + if (priv->ac6_ndisc && pllink->inet6_token.id) { + if (nm_ndisc_set_iid(priv->ac6_ndisc, pllink->inet6_token)) _LOGD(LOGD_DEVICE, "IPv6 tokenized identifier present on device %s", priv->iface); } @@ -5406,23 +5765,15 @@ device_link_changed(NMDevice *self) nm_device_set_unmanaged_by_flags(self, NM_UNMANAGED_PLATFORM_INIT, FALSE, reason); } - set_unmanaged_external_down(self, FALSE); + _dev_set_unmanaged_external_down(self, FALSE); device_recheck_slave_status(self, pllink); if (priv->up && (!was_up || seen_down)) { + priv->linklocal6_dad_counter = 0; /* the link was down and just came up. That happens for example, while changing MTU. * We must restore IP configuration. */ - if (NM_IN_SET(priv->ip_state_4, NM_DEVICE_IP_STATE_CONF, NM_DEVICE_IP_STATE_DONE)) { - if (!ip_config_merge_and_apply(self, AF_INET, TRUE)) - _LOGW(LOGD_IP4, "failed applying IP4 config after link comes up again"); - } - - priv->linklocal6_dad_counter = 0; - if (NM_IN_SET(priv->ip_state_6, NM_DEVICE_IP_STATE_CONF, NM_DEVICE_IP_STATE_DONE)) { - if (!ip_config_merge_and_apply(self, AF_INET6, TRUE)) - _LOGW(LOGD_IP6, "failed applying IP6 config after link comes up again"); - } + _dev_l3_cfg_commit(self, TRUE); } if (update_unmanaged_specs) @@ -5444,8 +5795,9 @@ device_link_changed(NMDevice *self) } static gboolean -device_ip_link_changed(NMDevice *self) +device_ip_link_changed(gpointer user_data) { + NMDevice * self = user_data; NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); const NMPlatformLink *pllink; const char * ip_iface; @@ -5508,13 +5860,12 @@ link_changed_cb(NMPlatform * platform, if (!(info->n_ifi_flags & IFF_UP)) priv->device_link_changed_down = TRUE; if (!priv->device_link_changed_id) { - priv->device_link_changed_id = g_idle_add((GSourceFunc) device_link_changed, self); + priv->device_link_changed_id = g_idle_add(device_link_changed, self); _LOGD(LOGD_DEVICE, "queued link change for ifindex %d", ifindex); } } else if (ifindex == nm_device_get_ip_ifindex(self)) { if (!priv->device_ip_link_changed_id) { - priv->device_ip_link_changed_id = - g_idle_add((GSourceFunc) device_ip_link_changed, self); + priv->device_ip_link_changed_id = g_idle_add(device_ip_link_changed, self); _LOGD(LOGD_DEVICE, "queued link change for ip-ifindex %d", ifindex); } } @@ -5962,8 +6313,6 @@ realize_start_setup(NMDevice * self, g_return_if_fail(nm_device_get_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT)); g_return_if_fail(priv->ip_ifindex <= 0); g_return_if_fail(priv->ip_iface == NULL); - g_return_if_fail(!priv->queued_ip_config_id_4); - g_return_if_fail(!priv->queued_ip_config_id_6); _LOGD(LOGD_DEVICE, "start setup of %s, kernel ifindex %d", @@ -6107,9 +6456,6 @@ nm_device_realize_finish(NMDevice *self, const NMPlatformLink *plink) if (plink) device_recheck_slave_status(self, plink); - priv->update_ip_config_completed_v4 = FALSE; - priv->update_ip_config_completed_v6 = FALSE; - priv->real = TRUE; _notify(self, PROP_REAL); @@ -6205,9 +6551,6 @@ nm_device_unrealize(NMDevice *self, gboolean remove_resources, GError **error) } } - nm_clear_g_source(&priv->queued_ip_config_id_4); - nm_clear_g_source(&priv->queued_ip_config_id_6); - g_object_freeze_notify(G_OBJECT(self)); NM_DEVICE_GET_CLASS(self)->unrealize_notify(self); @@ -6788,6 +7131,9 @@ nm_device_removed(NMDevice *self, gboolean unconfigure_ip_config) g_return_if_fail(NM_IS_DEVICE(self)); + _dev_dhcpx_cleanup(self, AF_INET, TRUE, FALSE); + _dev_dhcpx_cleanup(self, AF_INET6, TRUE, FALSE); + priv = NM_DEVICE_GET_PRIVATE(self); if (priv->master) { /* this is called when something externally messes with the slave or during shut-down. @@ -6799,15 +7145,7 @@ nm_device_removed(NMDevice *self, gboolean unconfigure_ip_config) NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); } - if (unconfigure_ip_config) { - nm_device_set_ip_config(self, AF_INET, NULL, FALSE, NULL); - nm_device_set_ip_config(self, AF_INET6, NULL, FALSE, NULL); - } else { - if (priv->dhcp_data_4.client) - nm_dhcp_client_stop(priv->dhcp_data_4.client, FALSE); - if (priv->dhcp_data_6.client) - nm_dhcp_client_stop(priv->dhcp_data_6.client, FALSE); - } + _dev_l3_register_l3cds(self, priv->l3cfg, FALSE, TRUE); } static gboolean @@ -7065,22 +7403,36 @@ nm_device_can_auto_connect(NMDevice *self, NMSettingsConnection *sett_conn, char static gboolean device_has_config(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + const NMDedupMultiHeadEntry *head_entry; + const NMPlatformLink * pllink; + NMPLookup lookup; + + pllink = nm_l3cfg_get_pllink(priv->l3cfg, TRUE); + if (!pllink) + return FALSE; - /* Check for IP configuration. */ - if (priv->ip_config_4 && nm_ip4_config_get_num_addresses(priv->ip_config_4)) + if (pllink->master > 0) { + /* Master-slave relationship is also a configuration */ return TRUE; - if (priv->ip_config_6 && nm_ip6_config_get_num_addresses(priv->ip_config_6)) + } + + head_entry = nm_platform_lookup( + nm_device_get_platform(self), + nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP4_ADDRESS, pllink->ifindex)); + if (head_entry) return TRUE; - /* The existence of a software device is good enough. */ - if (nm_device_is_software(self) && nm_device_is_real(self)) + head_entry = nm_platform_lookup( + nm_device_get_platform(self), + nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP6_ADDRESS, pllink->ifindex)); + if (head_entry) return TRUE; - /* Master-slave relationship is also a configuration */ - if (!c_list_is_empty(&priv->slaves) - || nm_platform_link_get_master(nm_device_get_platform(self), priv->ifindex) > 0) + if (nm_device_is_software(self) && nm_device_is_real(self)) { + /* The existence of a software device is good enough. */ return TRUE; + } return FALSE; } @@ -7134,7 +7486,8 @@ nm_device_master_update_slave_connection(NMDevice * self, return FALSE; } -static gboolean +//XXX +_nm_unused static gboolean _get_maybe_ipv6_disabled(NMDevice *self) { NMPlatform *platform; @@ -7228,11 +7581,13 @@ nm_device_generate_connection(NMDevice *self, } } else { /* Only regular and master devices get IP configuration; slaves do not */ - s_ip4 = nm_ip4_config_create_setting(priv->ip_config_4); - nm_connection_add_setting(connection, s_ip4); + //XXX s_ip4 = nm_ip4_config_create_setting (priv->ip_config_4); + //XXX nm_connection_add_setting (connection, s_ip4); + (void) s_ip4; - s_ip6 = nm_ip6_config_create_setting(priv->ip_config_6, _get_maybe_ipv6_disabled(self)); - nm_connection_add_setting(connection, s_ip6); + //XXX s_ip6 = nm_ip6_config_create_setting (priv->ip_config_6, _get_maybe_ipv6_disabled (self)); + //XXX nm_connection_add_setting (connection, s_ip6); + s_ip6 = NULL; nm_connection_add_setting(connection, nm_setting_proxy_new()); @@ -7685,20 +8040,6 @@ nm_device_emit_recheck_auto_activate(NMDevice *self) g_signal_emit(self, signals[RECHECK_AUTO_ACTIVATE], 0); } -static void -dnsmasq_state_changed_cb(NMDnsMasqManager *manager, guint32 status, gpointer user_data) -{ - NMDevice *self = NM_DEVICE(user_data); - - switch (status) { - case NM_DNSMASQ_STATUS_DEAD: - nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_SHARED_START_FAILED); - break; - default: - break; - } -} - void nm_device_auth_request(NMDevice * self, GDBusMethodInvocation * context, @@ -8035,6 +8376,7 @@ activate_stage1_device_prepare(NMDevice *self) priv->v4_route_table_initialized = FALSE; priv->v6_route_table_initialized = FALSE; + priv->l3config_merge_flags_has = FALSE; _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_NONE); _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_NONE); @@ -8478,7 +8820,7 @@ activate_stage2_device_config(NMDevice *self) lldp_setup(self, NM_TERNARY_DEFAULT); - _commit_mtu(self, NULL); + _commit_mtu(self); nm_device_activate_schedule_stage3_ip_config_start(self); } @@ -8513,936 +8855,411 @@ nm_device_ip_method_failed(NMDevice *self, int addr_family, NMDeviceStateReason /*****************************************************************************/ static void -acd_data_destroy(gpointer ptr) +_dev_ll4_cleanup(NMDevice *self) { - AcdData *data = ptr; - int i; - - for (i = 0; data->configs && data->configs[i]; i++) - g_object_unref(data->configs[i]); - g_free(data->configs); - g_slice_free(AcdData, data); -} + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); -static void -ipv4_manual_method_apply(NMDevice *self, NMIP4Config **configs, gboolean success) -{ - NMConnection *connection; - const char * method; + priv->ll4_ipv4ll_failed = FALSE; + priv->ll4_ipv4ll_ready = FALSE; - connection = nm_device_get_applied_connection(self); - nm_assert(connection); - method = nm_utils_get_ip_config_method(connection, AF_INET); - nm_assert(NM_IN_STRSET(method, - NM_SETTING_IP4_CONFIG_METHOD_MANUAL, - NM_SETTING_IP4_CONFIG_METHOD_AUTO)); + if (nm_clear_pointer(&priv->ll4_ipv4ll, nm_l3_ipv4ll_unref)) + nm_clear_pointer(&priv->ll4_ipv4ll_registation, nm_l3_ipv4ll_register_remove); + else + nm_assert(!priv->ll4_ipv4ll_registation); - if (!success) { - nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE); - return; - } + nm_clear_g_source(&priv->ll4_timeout_id); - if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) - nm_device_activate_schedule_ip_config_result(self, AF_INET, NULL); - else { - if (NM_DEVICE_GET_PRIVATE(self)->ip_state_4 != NM_DEVICE_IP_STATE_DONE) - ip_config_merge_and_apply(self, AF_INET, TRUE); - } + _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_LL_4, NULL, FALSE); } static void -acd_manager_probe_terminated(NMAcdManager *acd_manager, gpointer user_data) +_dev_ll4_notify_event(NMDevice *self) { - AcdData * data = user_data; - NMDevice * self; - NMDevicePrivate * priv; - NMDedupMultiIter ipconf_iter; - const NMPlatformIP4Address *address; - gboolean result, success = TRUE; - int i; - - g_assert(data); - self = data->device; - priv = NM_DEVICE_GET_PRIVATE(self); + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NML3IPv4LLState ipv4ll_state = NM_L3_IPV4LL_STATE_UNKNOWN; + const NML3ConfigData *l3cd; - for (i = 0; data->configs && data->configs[i]; i++) { - nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, data->configs[i], &address) { - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - result = nm_acd_manager_check_address(acd_manager, address->address); - success &= result; + ipv4ll_state = + priv->ll4_ipv4ll ? nm_l3_ipv4ll_get_state(priv->ll4_ipv4ll) : NM_L3_IPV4LL_STATE_UNKNOWN; - _NMLOG(result ? LOGL_DEBUG : LOGL_WARN, - LOGD_DEVICE, - "IPv4 DAD result: address %s is %s", - _nm_utils_inet4_ntop(address->address, sbuf), - result ? "unique" : "duplicate"); - } + if (nm_l3_ipv4ll_state_is_good(ipv4ll_state)) { + priv->ll4_ipv4ll_failed = FALSE; + priv->ll4_ipv4ll_ready = TRUE; + l3cd = nm_l3_ipv4ll_get_l3cd(priv->ll4_ipv4ll); + nm_assert(NM_IS_L3_CONFIG_DATA(l3cd)); + nm_assert(!nm_l3_ipv4ll_is_timed_out(priv->ll4_ipv4ll)); + } else { + priv->ll4_ipv4ll_failed = (priv->ll4_ipv4ll && nm_l3_ipv4ll_is_timed_out(priv->ll4_ipv4ll)); + l3cd = NULL; } - data->callback(self, data->configs, success); + _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_LL_4, l3cd, FALSE); - priv->acd.dad_list = g_slist_remove(priv->acd.dad_list, acd_manager); - nm_acd_manager_free(acd_manager); + _set_ip_state_check(self, AF_INET); } -/** - * ipv4_dad_start: - * @self: device instance - * @configs: NULL-terminated array of IPv4 configurations - * @cb: callback function - * - * Start IPv4 DAD on device @self, check addresses in @configs and call @cb - * when the procedure ends. @cb will be called in any case, even if DAD can't - * be started. @configs will be unreferenced after @cb has been called. - */ -static void -ipv4_dad_start(NMDevice *self, NMIP4Config **configs, AcdCallback cb) +static NMActStageReturn +_dev_ll4_start(NMDevice *self) { - static const NMAcdCallbacks acd_callbacks = { - .probe_terminated_callback = acd_manager_probe_terminated, - .user_data_destroy = acd_data_destroy, - }; - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMAcdManager * acd_manager; - const NMPlatformIP4Address *address; - NMDedupMultiIter ipconf_iter; - AcdData * data; - guint timeout; - gboolean addr_found; - int r; - const guint8 * hwaddr_arr; - size_t length; - guint i; - - g_return_if_fail(NM_IS_DEVICE(self)); - g_return_if_fail(configs); - g_return_if_fail(cb); - - for (i = 0, addr_found = FALSE; configs[i]; i++) { - if (nm_ip4_config_get_num_addresses(configs[i]) > 0) { - addr_found = TRUE; - break; - } - } + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + guint timeout_msec; - timeout = _prop_get_ipv4_dad_timeout(self); - hwaddr_arr = nm_platform_link_get_address(nm_device_get_platform(self), - nm_device_get_ip_ifindex(self), - &length); + _dev_ll4_cleanup(self); - if (!timeout || !hwaddr_arr || !addr_found || length != ETH_ALEN - || nm_device_sys_iface_state_is_external_or_assume(self)) { - /* DAD not needed, signal success */ - cb(self, configs, TRUE); + timeout_msec = _prop_get_ipv4_dad_timeout(self); + if (timeout_msec == 0) + timeout_msec = NM_ACD_TIMEOUT_RFC5227_MSEC; - for (i = 0; configs[i]; i++) - g_object_unref(configs[i]); - g_free(configs); + _LOGI(LOGD_DEVICE | LOGD_AUTOIP4, "ipv4ll: enabling"); - return; - } + priv->ll4_ipv4ll = nm_l3cfg_access_ipv4ll(priv->l3cfg); + priv->ll4_ipv4ll_registation = nm_l3_ipv4ll_register_new(priv->ll4_ipv4ll, timeout_msec); + return NM_ACT_STAGE_RETURN_POSTPONE; +} - data = g_slice_new0(AcdData); - data->configs = configs; - data->callback = cb; - data->device = self; +/*****************************************************************************/ - acd_manager = nm_acd_manager_new(nm_device_get_ip_ifindex(self), - hwaddr_arr, - length, - &acd_callbacks, - data); - priv->acd.dad_list = g_slist_append(priv->acd.dad_list, acd_manager); +static const char * +_device_get_dhcp_anycast_address(NMDevice *self) +{ + NMDeviceClass *klass; - for (i = 0; configs[i]; i++) { - nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, configs[i], &address) - nm_acd_manager_add_address(acd_manager, address->address); - } + nm_assert(NM_IS_DEVICE(self)); - r = nm_acd_manager_start_probe(acd_manager, timeout); - if (r < 0) { - _LOGW(LOGD_DEVICE, "acd probe failed"); + klass = NM_DEVICE_GET_CLASS(self); - /* DAD could not be started, signal success */ - cb(self, configs, TRUE); + if (klass->get_dhcp_anycast_address) + return klass->get_dhcp_anycast_address(self); - priv->acd.dad_list = g_slist_remove(priv->acd.dad_list, acd_manager); - nm_acd_manager_free(acd_manager); - } + return NULL; } /*****************************************************************************/ -/* IPv4LL stuff */ static void -ipv4ll_cleanup(NMDevice *self) +_dev_dhcp4_notify_acd_result(NMDevice *self, gboolean ready) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (priv->ipv4ll) { - sd_ipv4ll_set_callback(priv->ipv4ll, NULL, NULL); - sd_ipv4ll_stop(priv->ipv4ll); - priv->ipv4ll = sd_ipv4ll_unref(priv->ipv4ll); + if (!ready) { + nm_dhcp_client_decline(priv->dhcp_data_4.client, "acd failed", NULL); + _dev_dhcpx_set_state(self, AF_INET, DHCP_STATE_FAILED); + nm_clear_g_source_inst(&priv->dhcp_data_4.grace_source); + _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_DHCP_4, NULL, FALSE); + } else { + nm_dhcp_client_accept(priv->dhcp_data_4.client, NULL); + _dev_dhcpx_set_state(self, AF_INET, DHCP_STATE_BOUND); } - nm_clear_g_source(&priv->ipv4ll_timeout); + _set_ip_state_check(self, AF_INET); } -static NMIP4Config * -ipv4ll_get_ip4_config(NMDevice *self, guint32 lla) +static gboolean +_dev_dhcpx_set_state(NMDevice *self, int addr_family, DhcpState state) { - NMIP4Config * config = NULL; - NMPlatformIP4Address address; - NMPlatformIP4Route route; - - config = nm_device_ip4_config_new(self); - g_assert(config); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const int IS_IPv4 = NM_IS_IPv4(addr_family); - memset(&address, 0, sizeof(address)); - nm_platform_ip4_address_set_addr(&address, lla, 16); - address.addr_source = NM_IP_CONFIG_SOURCE_IP4LL; - nm_ip4_config_add_address(config, &address); + if (priv->dhcp_data_x[IS_IPv4].state == state) + return FALSE; - /* Add a multicast route for link-local connections: destination= 224.0.0.0, netmask=240.0.0.0 */ - memset(&route, 0, sizeof(route)); - route.network = htonl(0xE0000000L); - route.plen = 4; - route.rt_source = NM_IP_CONFIG_SOURCE_IP4LL; - route.table_coerced = nm_platform_route_table_coerce(nm_device_get_route_table(self, AF_INET)); - route.metric = nm_device_get_route_metric(self, AF_INET); - nm_ip4_config_add_route(config, &route, NULL); + _LOGD(LOGD_DHCPX(IS_IPv4), + "dhcp%c: set state '%s' (was '%s')", + nm_utils_addr_family_to_char(addr_family), + _dhcp_state_to_string(state), + _dhcp_state_to_string(priv->dhcp_data_x[IS_IPv4].state)); - return config; + priv->dhcp_data_x[IS_IPv4].state = state; + return TRUE; } static void -nm_device_handle_ipv4ll_event(sd_ipv4ll *ll, int event, void *data) +_dev_dhcpx_cleanup(NMDevice *self, int addr_family, gboolean reset_dhcp_config, gboolean release) { - NMDevice * self = data; - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - struct in_addr address; - NMIP4Config * config; - int r; - - if (priv->act_request.obj == NULL) - return; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const int IS_IPv4 = NM_IS_IPv4(addr_family); - nm_assert(nm_streq(nm_device_get_effective_ip_config_method(self, AF_INET), - NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)); + if (!IS_IPv4) + priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_NONE; - switch (event) { - case SD_IPV4LL_EVENT_BIND: - r = sd_ipv4ll_get_address(ll, &address); - if (r < 0) { - _LOGE(LOGD_AUTOIP4, "invalid IPv4 link-local address received, error %d.", r); - nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED); - return; - } + nm_clear_g_source_inst(&priv->dhcp_data_x[IS_IPv4].grace_source); - if (!nm_utils_ip4_address_is_link_local(address.s_addr)) { - _LOGE(LOGD_AUTOIP4, "invalid address %08x received (not link-local).", address.s_addr); - nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_AUTOIP_ERROR); - return; - } + _dev_dhcpx_set_state(self, addr_family, DHCP_STATE_NONE); - config = ipv4ll_get_ip4_config(self, address.s_addr); - if (config == NULL) { - _LOGE(LOGD_AUTOIP4, "failed to get IPv4LL config"); - nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_AUTOIP_FAILED); - return; - } + _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_DHCP_X(IS_IPv4), NULL, FALSE); - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF) { - nm_clear_g_source(&priv->ipv4ll_timeout); - nm_device_activate_schedule_ip_config_result(self, AF_INET, NM_IP_CONFIG_CAST(config)); - } else if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE) { - applied_config_init(&priv->dev_ip_config_4, config); - if (!ip_config_merge_and_apply(self, AF_INET, TRUE)) { - _LOGE(LOGD_AUTOIP4, "failed to update IP4 config for autoip change."); - nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_AUTOIP_FAILED); - } - } else - g_assert_not_reached(); + if (priv->dhcp_data_x[IS_IPv4].client) { + /* Stop any ongoing DHCP transaction on this device */ + nm_clear_g_signal_handler(priv->dhcp_data_x[IS_IPv4].client, + &priv->dhcp_data_x[IS_IPv4].state_sigid); + if (!IS_IPv4) + nm_clear_g_signal_handler(priv->dhcp_data_6.client, &priv->dhcp6.prefix_sigid); + nm_dhcp_client_stop(priv->dhcp_data_x[IS_IPv4].client, release); + g_clear_object(&priv->dhcp_data_x[IS_IPv4].client); + } - g_object_unref(config); - break; - default: - _LOGW(LOGD_AUTOIP4, "IPv4LL address no longer valid after event %d.", event); - nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_AUTOIP_FAILED); + if (reset_dhcp_config) { + if (nm_dbus_object_clear_and_unexport(&priv->dhcp_data_x[IS_IPv4].config)) + _notify(self, PROP_DHCPX_CONFIG(IS_IPv4)); } } static gboolean -ipv4ll_timeout_cb(gpointer user_data) +_dev_dhcpx_grace_period_expired(NMDevice *self, int addr_family) { - NMDevice * self = NM_DEVICE(user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const int IS_IPv4 = NM_IS_IPv4(addr_family); - if (priv->ipv4ll_timeout) { - _LOGI(LOGD_AUTOIP4, "IPv4LL configuration timed out."); - priv->ipv4ll_timeout = 0; - ipv4ll_cleanup(self); + nm_clear_g_source_inst(&priv->dhcp_data_x[IS_IPv4].grace_source); - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF) - nm_device_activate_schedule_ip_config_timeout(self, AF_INET); - } + _LOGD(LOGD_DHCPX(IS_IPv4), + "dhcp%c: grace period expired", + nm_utils_addr_family_to_char(addr_family)); - return FALSE; + _set_ip_state_check(self, addr_family); + return G_SOURCE_CONTINUE; } -static NMActStageReturn -ipv4ll_start(NMDevice *self) +static gboolean +_dev_dhcpx_grace_period_expired_4(gpointer user_data) { - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - const struct ether_addr *addr; - int ifindex, r; - size_t addr_len; - - ipv4ll_cleanup(self); - - r = sd_ipv4ll_new(&priv->ipv4ll); - if (r < 0) { - _LOGE(LOGD_AUTOIP4, "IPv4LL: new() failed with error %d", r); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - r = sd_ipv4ll_attach_event(priv->ipv4ll, NULL, 0); - if (r < 0) { - _LOGE(LOGD_AUTOIP4, "IPv4LL: attach_event() failed with error %d", r); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - ifindex = nm_device_get_ip_ifindex(self); - addr = nm_platform_link_get_address(nm_device_get_platform(self), ifindex, &addr_len); - if (!addr || addr_len != ETH_ALEN) { - _LOGE(LOGD_AUTOIP4, "IPv4LL: can't retrieve hardware address"); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - r = sd_ipv4ll_set_mac(priv->ipv4ll, addr); - if (r < 0) { - _LOGE(LOGD_AUTOIP4, "IPv4LL: set_mac() failed with error %d", r); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - r = sd_ipv4ll_set_ifindex(priv->ipv4ll, ifindex); - if (r < 0) { - _LOGE(LOGD_AUTOIP4, "IPv4LL: set_ifindex() failed with error %d", r); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - r = sd_ipv4ll_set_callback(priv->ipv4ll, nm_device_handle_ipv4ll_event, self); - if (r < 0) { - _LOGE(LOGD_AUTOIP4, "IPv4LL: set_callback() failed with error %d", r); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - r = sd_ipv4ll_start(priv->ipv4ll); - if (r < 0) { - _LOGE(LOGD_AUTOIP4, "IPv4LL: start() failed with error %d", r); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - _LOGI(LOGD_DEVICE | LOGD_AUTOIP4, "IPv4LL: started"); - - /* Start a timeout to bound the address attempt */ - priv->ipv4ll_timeout = g_timeout_add_seconds(20, ipv4ll_timeout_cb, self); - return NM_ACT_STAGE_RETURN_POSTPONE; + return _dev_dhcpx_grace_period_expired(user_data, AF_INET); } -/*****************************************************************************/ +static gboolean +_dev_dhcpx_grace_period_expired_6(gpointer user_data) +{ + return _dev_dhcpx_grace_period_expired(user_data, AF_INET6); +} -static void -ensure_con_ip_config(NMDevice *self, int addr_family) +static gboolean +_dev_dhcpx_grace_period_start(NMDevice *self, + int addr_family, + guint32 timeout_sec, + gboolean force_restart) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMConnection * connection; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); const int IS_IPv4 = NM_IS_IPv4(addr_family); - NMIPConfig * con_ip_config; - - if (priv->con_ip_config_x[IS_IPv4]) - return; - - connection = nm_device_get_applied_connection(self); - if (!connection) - return; - con_ip_config = nm_device_ip_config_new(self, addr_family); - - if (IS_IPv4) { - nm_ip4_config_merge_setting(NM_IP4_CONFIG(con_ip_config), - nm_connection_get_setting_ip4_config(connection), - _prop_get_connection_mdns(self), - _prop_get_connection_llmnr(self), - nm_device_get_route_table(self, addr_family), - nm_device_get_route_metric(self, addr_family)); - } else { - nm_ip6_config_merge_setting(NM_IP6_CONFIG(con_ip_config), - nm_connection_get_setting_ip6_config(connection), - nm_device_get_route_table(self, addr_family), - nm_device_get_route_metric(self, addr_family)); + /* In any other case (expired lease, assumed connection, etc.), + * wait for some time before failing the IP method. + */ + if (!force_restart && priv->dhcp_data_x[IS_IPv4].grace_source) { + /* already pending. */ + return FALSE; } - if (nm_device_sys_iface_state_is_external_or_assume(self)) { - /* For assumed connections ignore all addresses and routes. */ - nm_ip_config_reset_addresses(con_ip_config); - nm_ip_config_reset_routes(con_ip_config); - } + /* Start a grace period equal to the DHCP timeout multiplied + * by a constant factor. */ - priv->con_ip_config_x[IS_IPv4] = con_ip_config; -} + nm_clear_g_source_inst(&priv->dhcp_data_x[IS_IPv4].grace_source); -/*****************************************************************************/ + if (timeout_sec == 0) + timeout_sec = _prop_get_ipvx_dhcp_timeout(self, addr_family); -static const char * -_device_get_dhcp_anycast_address(NMDevice *self) -{ - NMDeviceClass *klass; + if (timeout_sec == NM_DHCP_TIMEOUT_INFINITY) { + _LOGD(LOGD_DHCPX(IS_IPv4), + "dhcp%c: trying to acquire a new lease", + nm_utils_addr_family_to_char(addr_family)); + priv->dhcp_data_x[IS_IPv4].grace_source = g_source_ref(nm_g_source_sentinel_get(0)); + } else { + guint timeout_msec; - nm_assert(NM_IS_DEVICE(self)); + if (timeout_sec < G_MAXUINT / 1000u) + timeout_msec = timeout_sec * 1000u; + else + timeout_msec = G_MAXUINT; - klass = NM_DEVICE_GET_CLASS(self); + _LOGD(LOGD_DHCPX(IS_IPv4), + "dhcp%c: trying to acquire a new lease within %u seconds", + nm_utils_addr_family_to_char(addr_family), + timeout_sec); - if (klass->get_dhcp_anycast_address) - return klass->get_dhcp_anycast_address(self); + priv->dhcp_data_x[IS_IPv4].grace_source = + nm_g_source_attach(nm_g_timeout_source_new(timeout_msec, + G_PRIORITY_DEFAULT, + IS_IPv4 ? _dev_dhcpx_grace_period_expired_4 + : _dev_dhcpx_grace_period_expired_6, + self, + NULL), + NULL); + } - return NULL; + return TRUE; } static void -dhcp4_cleanup(NMDevice *self, CleanupType cleanup_type, gboolean release) +_dev_dhcpx_state_changed(NMDevice * self, + int addr_family, + NMDhcpState state, + const NML3ConfigData *l3cd) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + nm_auto_unref_l3cd const NML3ConfigData *l3cd_merged = NULL; + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + const int IS_IPv4 = NM_IS_IPv4(addr_family); - priv->dhcp_data_4.was_active = FALSE; - nm_clear_g_source(&priv->dhcp_data_4.grace_id); - priv->dhcp_data_4.grace_pending = FALSE; - nm_clear_g_free(&priv->dhcp4.pac_url); + nm_assert(NM_IN_SET(state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED) == (!!l3cd)); - if (priv->dhcp_data_4.client) { - /* Stop any ongoing DHCP transaction on this device */ - nm_clear_g_signal_handler(priv->dhcp_data_4.client, &priv->dhcp_data_4.state_sigid); + _LOGD(LOGD_DHCPX(IS_IPv4), + "dhcp%c: new DHCP client state %s", + nm_utils_addr_family_to_char(addr_family), + nm_dhcp_state_to_string(state)); - if (cleanup_type == CLEANUP_TYPE_DECONFIGURE || cleanup_type == CLEANUP_TYPE_REMOVED) - nm_dhcp_client_stop(priv->dhcp_data_4.client, release); + switch (state) { + case NM_DHCP_STATE_BOUND: + case NM_DHCP_STATE_EXTENDED: - g_clear_object(&priv->dhcp_data_4.client); - } + nm_assert(l3cd); - if (priv->dhcp_data_4.config) { - nm_dbus_object_clear_and_unexport(&priv->dhcp_data_4.config); - _notify(self, PROP_DHCP4_CONFIG); - } -} + /* If the server sends multiple IPv6 addresses, we receive a state + * changed event for each of them. Use the event ID to merge IPv6 + * addresses from the same transaction into a single configuration. + */ + if (!IS_IPv4) { + if (nm_dhcp_utils_merge_new_dhcp6_lease(priv->l3cds[L3_CONFIG_DATA_TYPE_DHCP_6].d, + l3cd, + &l3cd_merged)) { + _LOGD(LOGD_DHCP6, "merged DHCPv6 lease with previous lease"); + l3cd = l3cd_merged; + } + } -static gboolean -ip_config_merge_and_apply(NMDevice *self, int addr_family, gboolean commit) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - gboolean success; - gs_unref_object NMIPConfig *composite = NULL; - NMIPConfig * config; - gs_unref_ptrarray GPtrArray *ip4_dev_route_blacklist = NULL; - NMConnection * connection; - gboolean ignore_auto_routes = FALSE; - gboolean ignore_auto_dns = FALSE; - gboolean ignore_default_routes = FALSE; - GSList * iter; - const char * ip6_addr_gen_token = NULL; - const int IS_IPv4 = NM_IS_IPv4(addr_family); + nm_clear_g_source_inst(&priv->dhcp_data_x[IS_IPv4].grace_source); - if (nm_device_sys_iface_state_is_external(self)) - commit = FALSE; + _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_DHCP_X(IS_IPv4), l3cd, FALSE); - connection = nm_device_get_applied_connection(self); + nm_dhcp_config_set_lease(priv->dhcp_data_x[IS_IPv4].config, l3cd); - /* Apply ignore-auto-routes and ignore-auto-dns settings */ - if (connection) { - NMSettingIPConfig *s_ip; + _set_ip_state_check(self, addr_family); - s_ip = nm_connection_get_setting_ip_config(connection, addr_family); - if (s_ip) { - ignore_auto_routes = nm_setting_ip_config_get_ignore_auto_routes(s_ip); - ignore_auto_dns = nm_setting_ip_config_get_ignore_auto_dns(s_ip); - - /* if the connection has an explicit gateway, we also ignore - * the default routes from other sources. */ - ignore_default_routes = nm_setting_ip_config_get_never_default(s_ip) - || nm_setting_ip_config_get_gateway(s_ip); - - if (!IS_IPv4) { - NMSettingIP6Config *s_ip6 = NM_SETTING_IP6_CONFIG(s_ip); - - if (nm_setting_ip6_config_get_addr_gen_mode(s_ip6) - == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64) - ip6_addr_gen_token = nm_setting_ip6_config_get_token(s_ip6); - } - } - } - - composite = nm_device_ip_config_new(self, addr_family); - - if (!IS_IPv4) { - nm_ip6_config_set_privacy(NM_IP6_CONFIG(composite), - priv->ndisc ? priv->ndisc_use_tempaddr - : NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - } - - init_ip_config_dns_priority(self, composite); - - if (commit) { - if (priv->queued_ip_config_id_x[IS_IPv4]) - update_ext_ip_config(self, addr_family, FALSE); - ensure_con_ip_config(self, addr_family); - } - - if (!IS_IPv4) { - if (commit && priv->ipv6ll_has) { - const NMPlatformIP6Address ll_a = { - .address = priv->ipv6ll_addr, - .plen = 64, - .addr_source = NM_IP_CONFIG_SOURCE_IP6LL, - }; - const NMPlatformIP6Route ll_r = { - .network.s6_addr16[0] = htons(0xfe80u), - .plen = 64, - .metric = nm_device_get_route_metric(self, addr_family), - .rt_source = NM_IP_CONFIG_SOURCE_IP6LL, - }; - - nm_assert(IN6_IS_ADDR_LINKLOCAL(&priv->ipv6ll_addr)); - - nm_ip6_config_add_address(NM_IP6_CONFIG(composite), &ll_a); - nm_ip6_config_add_route(NM_IP6_CONFIG(composite), &ll_r, NULL); - } - } - - if (commit) { - gboolean v; - - v = default_route_metric_penalty_detect(self, addr_family); - if (IS_IPv4) - priv->default_route_metric_penalty_ip4_has = v; - else - priv->default_route_metric_penalty_ip6_has = v; - } - - /* Merge all the IP configs into the composite config */ - - if (IS_IPv4) { - config = applied_config_get_current(&priv->dev_ip_config_4); - if (config) { - nm_ip4_config_merge( - NM_IP4_CONFIG(composite), - NM_IP4_CONFIG(config), - (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) - | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) - | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), - default_route_metric_penalty_get(self, addr_family)); - } - } - - if (!IS_IPv4) { - config = applied_config_get_current(&priv->ac_ip6_config); - if (config) { - nm_ip6_config_merge( - NM_IP6_CONFIG(composite), - NM_IP6_CONFIG(config), - (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) - | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) - | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), - default_route_metric_penalty_get(self, addr_family)); - } - } - - if (!IS_IPv4) { - config = applied_config_get_current(&priv->dhcp6.ip6_config); - if (config) { - nm_ip6_config_merge( - NM_IP6_CONFIG(composite), - NM_IP6_CONFIG(config), - (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) - | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) - | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), - default_route_metric_penalty_get(self, addr_family)); - } - } - - for (iter = priv->vpn_configs_x[IS_IPv4]; iter; iter = iter->next) - nm_ip_config_merge(composite, iter->data, NM_IP_CONFIG_MERGE_DEFAULT, 0); - - if (priv->ext_ip_config_x[IS_IPv4]) - nm_ip_config_merge(composite, - priv->ext_ip_config_x[IS_IPv4], - NM_IP_CONFIG_MERGE_EXTERNAL, - 0); + _dev_l3_cfg_commit(self, TRUE); - /* Merge WWAN config *last* to ensure modem-given settings overwrite - * any external stuff set by pppd or other scripts. - */ - config = applied_config_get_current(&priv->dev2_ip_config_x[IS_IPv4]); - if (config) { - nm_ip_config_merge(composite, - config, - (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) - | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) - | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), - default_route_metric_penalty_get(self, addr_family)); - } - - if (!IS_IPv4) { - if (priv->rt6_temporary_not_available) { - const NMPObject *o; - GHashTableIter hiter; - - g_hash_table_iter_init(&hiter, priv->rt6_temporary_not_available); - while (g_hash_table_iter_next(&hiter, (gpointer *) &o, NULL)) { - nm_ip6_config_add_route(NM_IP6_CONFIG(composite), - NMP_OBJECT_CAST_IP6_ROUTE(o), - NULL); - } - } - } + _dev_l3_notify_change(self, addr_family); - /* Merge user overrides into the composite config. For assumed connections, - * con_ip_config_x is empty. */ - if (priv->con_ip_config_x[IS_IPv4]) { - nm_ip_config_merge(composite, - priv->con_ip_config_x[IS_IPv4], - NM_IP_CONFIG_MERGE_DEFAULT, - default_route_metric_penalty_get(self, addr_family)); - } - - if (commit) { - gboolean is_vrf; - - is_vrf = priv->master && nm_device_get_device_type(priv->master) == NM_DEVICE_TYPE_VRF; - - if (IS_IPv4) { - nm_ip4_config_add_dependent_routes(NM_IP4_CONFIG(composite), - nm_device_get_route_table(self, addr_family), - nm_device_get_route_metric(self, addr_family), - is_vrf, - &ip4_dev_route_blacklist); - } else { - nm_ip6_config_add_dependent_routes(NM_IP6_CONFIG(composite), - nm_device_get_route_table(self, addr_family), - nm_device_get_route_metric(self, addr_family), - is_vrf); - } - } - - if (IS_IPv4) { - if (commit) { - if (NM_DEVICE_GET_CLASS(self)->ip4_config_pre_commit) - NM_DEVICE_GET_CLASS(self)->ip4_config_pre_commit(self, NM_IP4_CONFIG(composite)); - } - } - - if (!IS_IPv4) { - NMUtilsIPv6IfaceId iid; - - if (commit && priv->ndisc_started && ip6_addr_gen_token - && nm_utils_ipv6_interface_identifier_get_from_token(&iid, ip6_addr_gen_token)) { - set_ipv6_token(self, iid, ip6_addr_gen_token); + if (!IS_IPv4) { + /* FIXME(l3cfg): check where and how to dispatch DHCP change notifications. */ + nm_dispatcher_call_device(NM_DISPATCHER_ACTION_DHCP6_CHANGE, + self, + NULL, + NULL, + NULL, + NULL); } - } - success = - nm_device_set_ip_config(self, addr_family, composite, commit, ip4_dev_route_blacklist); - if (commit) { - if (IS_IPv4) - priv->v4_commit_first_time = FALSE; - else - priv->v6_commit_first_time = FALSE; - } - - return success; -} - -static gboolean -dhcp4_lease_change(NMDevice *self, NMIP4Config *config, gboolean bound) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - gs_free_error GError *error = NULL; - - g_return_val_if_fail(config, FALSE); - - applied_config_init(&priv->dev_ip_config_4, config); - - if (!ip_config_merge_and_apply(self, AF_INET, TRUE)) { - _LOGW(LOGD_DHCP4, "failed to update IPv4 config for DHCP change."); - return FALSE; - } - - /* TODO: we should perform DAD again whenever we obtain a - * new lease after an expiry. But what should we do if - * a duplicate address is detected? Fail the connection; - * restart DHCP; continue without an address? */ - if (bound && !nm_dhcp_client_accept(priv->dhcp_data_4.client, &error)) { - _LOGW(LOGD_DHCP4, "error accepting lease: %s", error->message); - return FALSE; + break; + case NM_DHCP_STATE_TIMEOUT: + goto out_fail; + case NM_DHCP_STATE_EXPIRE: + /* Ignore expiry before we even have a lease (NAK, old lease, etc) */ + if (priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF) + break; + /* fall-through */ + case NM_DHCP_STATE_DONE: + case NM_DHCP_STATE_FAIL: + case NM_DHCP_STATE_TERMINATED: + goto out_fail; + default: + break; } - nm_dispatcher_call_device(NM_DISPATCHER_ACTION_DHCP4_CHANGE, self, NULL, NULL, NULL, NULL); - - return TRUE; -} - -static gboolean -dhcp_grace_period_expired(NMDevice *self, int addr_family) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - const int IS_IPv4 = NM_IS_IPv4(addr_family); - - priv->dhcp_data_x[IS_IPv4].grace_id = 0; - priv->dhcp_data_x[IS_IPv4].grace_pending = FALSE; - - _LOGI(LOGD_DHCPX(IS_IPv4), - "DHCPv%c: grace period expired", - nm_utils_addr_family_to_char(addr_family)); - - nm_device_ip_method_failed(self, addr_family, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED); - /* If the device didn't fail, the DHCP client will continue */ +out_fail: + //XXX _LOGD(LOGD_DHCPX(IS_IPv4), + //XXX "dhcp%c failed (ip_state %s, was_active %d)", + //XXX nm_utils_addr_family_to_char(addr_family), + //XXX nm_device_ip_state_to_str(priv->ip_state_x[IS_IPv4]), + //XXX (int) priv->dhcp_data_x[IS_IPv4].was_active); - return G_SOURCE_REMOVE; + _dev_dhcpx_grace_period_start(self, addr_family, 0, FALSE); + //XXX priv->dhcp_data_x[IS_IPv4].is_bad = TRUE; + _set_ip_state_check(self, addr_family); } -static gboolean -dhcp_grace_period_expired_4(gpointer user_data) -{ - return dhcp_grace_period_expired(user_data, AF_INET); -} +/*****************************************************************************/ -static gboolean -dhcp_grace_period_expired_6(gpointer user_data) +static void +_dev_dhcpx_state_changed_4(NMDhcpClient * client, + guint state, + const NML3ConfigData *l3cd, + gpointer user_data) { - return dhcp_grace_period_expired(user_data, AF_INET6); + _dev_dhcpx_state_changed(user_data, AF_INET, state, l3cd); } -static gboolean -dhcp_grace_period_start(NMDevice *self, int addr_family) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - const int IS_IPv4 = NM_IS_IPv4(addr_family); - guint32 timeout; - - /* In any other case (expired lease, assumed connection, etc.), - * wait for some time before failing the IP method. - */ - if (priv->dhcp_data_x[IS_IPv4].grace_pending) { - /* already pending. */ - return FALSE; - } - - /* Start a grace period equal to the DHCP timeout multiplied - * by a constant factor. */ - timeout = _prop_get_ipvx_dhcp_timeout(self, addr_family); - if (timeout == NM_DHCP_TIMEOUT_INFINITY) - _LOGI(LOGD_DHCPX(IS_IPv4), - "DHCPv%c: trying to acquire a new lease", - nm_utils_addr_family_to_char(addr_family)); - else { - timeout = dhcp_grace_period_from_timeout(timeout); - _LOGI(LOGD_DHCPX(IS_IPv4), - "DHCPv%c: trying to acquire a new lease within %u seconds", - nm_utils_addr_family_to_char(addr_family), - timeout); - nm_assert(!priv->dhcp_data_x[IS_IPv4].grace_id); - priv->dhcp_data_x[IS_IPv4].grace_id = g_timeout_add_seconds( - timeout, - IS_IPv4 ? dhcp_grace_period_expired_4 : dhcp_grace_period_expired_6, - self); - } - - priv->dhcp_data_x[IS_IPv4].grace_pending = TRUE; - - return TRUE; -} static void -dhcp4_fail(NMDevice *self, NMDhcpState dhcp_state) +_dev_dhcpx_state_changed_6(NMDhcpClient * client, + guint state, + const NML3ConfigData *l3cd, + gpointer user_data) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - _LOGD(LOGD_DHCP4, - "DHCPv4 failed (ip_state %s, was_active %d)", - 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. */ - - /* Nothing to do if we failed before... */ - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_FAIL) - goto clear_config; - - /* ... and also if there are static addresses configured - * on the interface. - */ - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE && priv->con_ip_config_4 - && nm_ip4_config_get_num_addresses(priv->con_ip_config_4) > 0) - goto clear_config; - - /* Fail the method when one of the following is true: - * 1) the DHCP client terminated: it does not make sense to start a grace - * period without a client running; - * 2) we failed to get an initial lease AND the client was - * not active before. - */ - if (dhcp_state == NM_DHCP_STATE_TERMINATED - || (!priv->dhcp_data_4.was_active && priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF)) { - nm_device_activate_schedule_ip_config_timeout(self, AF_INET); - return; - } - - if (dhcp_grace_period_start(self, AF_INET)) - goto clear_config; - - return; - -clear_config: - /* The previous configuration is no longer valid */ - if (priv->dhcp_data_4.config) { - nm_dbus_object_clear_and_unexport(&priv->dhcp_data_4.config); - priv->dhcp_data_4.config = nm_dhcp_config_new(AF_INET); - _notify(self, PROP_DHCP4_CONFIG); - } + _dev_dhcpx_state_changed(user_data, AF_INET6, state, l3cd); } static void -dhcp4_dad_cb(NMDevice *self, NMIP4Config **configs, gboolean success) +_dev_dhcp6_prefix_delegated(NMDhcpClient *client, NMPlatformIP6Address *prefix, gpointer user_data) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMDevice *self = NM_DEVICE(user_data); - if (success) { - nm_device_activate_schedule_ip_config_result(self, AF_INET, NM_IP_CONFIG_CAST(configs[1])); - } else { - nm_dhcp_client_decline(priv->dhcp_data_4.client, "Address conflict detected", NULL); - nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE); - } + /* Just re-emit. The device just contributes the prefix to the + * pool in NMPolicy, which decides about subnet allocation + * on the shared devices. */ + g_signal_emit(self, signals[IP6_PREFIX_DELEGATED], 0, prefix); } -static void -dhcp4_state_changed(NMDhcpClient *client, - NMDhcpState state, - NMIP4Config * ip4_config, - GHashTable * options, - gpointer user_data) +static gboolean +_dev_dhcpx_start(NMDevice *self, int addr_family) { - NMDevice * self = NM_DEVICE(user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMIP4Config * manual, **configs; - NMConnection * connection; - - g_return_if_fail(nm_dhcp_client_get_addr_family(client) == AF_INET); - g_return_if_fail(!ip4_config || NM_IS_IP4_CONFIG(ip4_config)); - - _LOGD(LOGD_DHCP4, "new DHCPv4 client state %d", state); + const int IS_IPv4 = NM_IS_IPv4(addr_family); + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMConnection * connection; + NMSettingConnection *s_con; + NMSettingIPConfig * s_ip; + struct in6_addr ll_addr = IN6ADDR_ANY_INIT; + gs_unref_bytes GBytes *hwaddr = NULL; + gboolean enforce_duid = FALSE; + gs_free char * mud_url_free = NULL; + gs_free_error GError *error = NULL; + const NMPlatformLink *pllink; + guint32 timeout_sec; + int ifindex; + const char * str; + gboolean request_broadcast; - switch (state) { - case NM_DHCP_STATE_BOUND: - case NM_DHCP_STATE_EXTENDED: - if (!ip4_config) { - _LOGW(LOGD_DHCP4, "failed to get IPv4 config in response to DHCP event."); - dhcp4_fail(self, state); - break; - } + nm_assert(priv->dhcp_data_x[IS_IPv4].client == NULL); - nm_clear_g_source(&priv->dhcp_data_4.grace_id); - priv->dhcp_data_4.grace_pending = FALSE; + if (nm_device_sys_iface_state_is_external(self)) + g_return_val_if_reached(TRUE); - /* After some failures, we have been able to renew the lease: - * update the ip state - */ - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_FAIL) - _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_CONF); + connection = nm_device_get_applied_connection(self); + g_return_val_if_fail(connection, FALSE); - g_free(priv->dhcp4.pac_url); - priv->dhcp4.pac_url = g_strdup(g_hash_table_lookup(options, "wpad")); - nm_device_set_proxy_config(self, priv->dhcp4.pac_url); + s_con = nm_connection_get_setting_connection(connection); + s_ip = nm_connection_get_setting_ip_config(connection, addr_family); + nm_assert(s_con); + nm_assert(s_ip); - nm_dhcp_config_set_options(priv->dhcp_data_4.config, options); - _notify(self, PROP_DHCP4_CONFIG); + ifindex = 0; - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF) { - connection = nm_device_get_applied_connection(self); - g_assert(connection); + pllink = nm_l3cfg_get_pllink(priv->l3cfg, TRUE); + if (pllink) { + ifindex = pllink->ifindex; + nm_assert(ifindex > 0); + nm_assert(ifindex == nm_device_get_ip_ifindex(self)); + } - manual = nm_device_ip4_config_new(self); - nm_ip4_config_merge_setting(manual, - nm_connection_get_setting_ip4_config(connection), - NM_SETTING_CONNECTION_MDNS_DEFAULT, - NM_SETTING_CONNECTION_LLMNR_DEFAULT, - nm_device_get_route_table(self, AF_INET), - nm_device_get_route_metric(self, AF_INET)); + if (ifindex <= 0) + g_return_val_if_reached(TRUE); - configs = g_new0(NMIP4Config *, 3); - configs[0] = manual; - configs[1] = g_object_ref(ip4_config); + hwaddr = nmp_link_address_get_as_bytes(&pllink->l_address); - ipv4_dad_start(self, configs, dhcp4_dad_cb); - } else if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE) { - if (dhcp4_lease_change(self, ip4_config, state == NM_DHCP_STATE_BOUND)) - nm_device_update_metered(self); - else - dhcp4_fail(self, state); + if (!IS_IPv4) { + if (!hwaddr) { + _LOGD(LOGD_DHCP6, "dhcp6: cannot start DHCP with no suitable interface"); + return FALSE; } - break; - case NM_DHCP_STATE_TIMEOUT: - dhcp4_fail(self, state); - break; - case NM_DHCP_STATE_EXPIRE: - /* Ignore expiry before we even have a lease (NAK, old lease, etc) */ - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF) - break; - /* fall-through */ - case NM_DHCP_STATE_DONE: - case NM_DHCP_STATE_FAIL: - case NM_DHCP_STATE_TERMINATED: - dhcp4_fail(self, state); - break; - default: - break; } -} - -static NMActStageReturn -dhcp4_start(NMDevice *self) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMSettingIPConfig *s_ip4; - gs_unref_bytes GBytes *vendor_class_identifier = NULL; - 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); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - - s_con = nm_connection_get_setting_connection(connection); - nm_assert(s_con); - - /* Clear old exported DHCP options */ - 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)) { @@ -9454,103 +9271,154 @@ dhcp4_start(NMDevice *self) } } - client_id = _prop_get_ipv4_dhcp_client_id(self, connection, hwaddr); - vendor_class_identifier = - _prop_get_ipv4_dhcp_vendor_class_identifier(self, NM_SETTING_IP4_CONFIG(s_ip4)); - 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), - 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, &mud_url_free), - 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); - return NM_ACT_STAGE_RETURN_FAILURE; + timeout_sec = _prop_get_ipvx_dhcp_timeout(self, addr_family); + + _dev_dhcpx_grace_period_start(self, addr_family, timeout_sec, TRUE); + + if (!IS_IPv4) { + if (!_dev_ll6_start(self, &ll_addr)) { + /* wait for the LL address to show up */ + return TRUE; + } } - priv->dhcp_data_4.state_sigid = g_signal_connect(priv->dhcp_data_4.client, - NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, - G_CALLBACK(dhcp4_state_changed), - self); + if (IS_IPv4) { + gs_unref_bytes GBytes *bcast_hwaddr = NULL; + gs_unref_bytes GBytes *client_id = NULL; + gs_unref_bytes GBytes *vendor_class_identifier = NULL; + const char *const * reject_servers; - if (nm_device_sys_iface_state_is_external_or_assume(self)) - priv->dhcp_data_4.was_active = TRUE; + client_id = _prop_get_ipv4_dhcp_client_id(self, connection, hwaddr); + vendor_class_identifier = + _prop_get_ipv4_dhcp_vendor_class_identifier(self, NM_SETTING_IP4_CONFIG(s_ip)); + reject_servers = nm_setting_ip_config_get_dhcp_reject_servers(s_ip, NULL); - /* DHCP devices will be notified by the DHCP manager when stuff happens */ - return NM_ACT_STAGE_RETURN_POSTPONE; + bcast_hwaddr = nmp_link_address_get_as_bytes(&pllink->l_broadcast); + + 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), + request_broadcast ? NM_DHCP_CLIENT_FLAGS_REQUEST_BROADCAST : NM_DHCP_CLIENT_FLAGS_NONE, + nm_setting_ip_config_get_dhcp_send_hostname(s_ip), + nm_setting_ip_config_get_dhcp_hostname(s_ip), + nm_setting_ip4_config_get_dhcp_fqdn(NM_SETTING_IP4_CONFIG(s_ip)), + _prop_get_ipvx_dhcp_hostname_flags(self, AF_INET), + _prop_get_connection_mud_url(self, s_con, &mud_url_free), + client_id, + timeout_sec, + _device_get_dhcp_anycast_address(self), + NULL, + vendor_class_identifier, + reject_servers, + &error); + } else { + gs_unref_bytes GBytes *duid = NULL; + gboolean iaid_explicit; + guint32 iaid; + + iaid = _prop_get_ipvx_dhcp_iaid(self, AF_INET6, connection, FALSE, &iaid_explicit); + duid = _prop_get_ipv6_dhcp_duid(self, connection, hwaddr, &enforce_duid); + + priv->dhcp_data_6.client = nm_dhcp_manager_start_ip6( + nm_dhcp_manager_get(), + nm_device_get_multi_index(self), + nm_device_get_ip_iface(self), + ifindex, + &ll_addr, + nm_connection_get_uuid(connection), + (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_ip), + nm_setting_ip_config_get_dhcp_hostname(s_ip), + _prop_get_ipvx_dhcp_hostname_flags(self, AF_INET6), + _prop_get_connection_mud_url(self, s_con, &mud_url_free), + duid, + enforce_duid, + iaid, + iaid_explicit, + _prop_get_ipvx_dhcp_timeout(self, AF_INET6), + _device_get_dhcp_anycast_address(self), + nm_setting_ip6_config_get_ip6_privacy(NM_SETTING_IP6_CONFIG(s_ip)), + priv->dhcp6.needed_prefixes, + &error); + } + + if (nm_device_sys_iface_state_is_external_or_assume(self)) { + //XXX priv->dhcp_data_x[IS_IPv4].was_active = TRUE; + } + + if (!priv->dhcp_data_x[IS_IPv4].client) { + _LOGW(LOGD_DHCPX(IS_IPv4), + "dhcp%c: failure to start DHCP client: %s", + nm_utils_addr_family_to_char(addr_family), + error->message); + _dev_dhcpx_cleanup(self, addr_family, TRUE, TRUE); + return FALSE; + } + + priv->dhcp_data_x[IS_IPv4].state_sigid = g_signal_connect( + priv->dhcp_data_x[IS_IPv4].client, + NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, + IS_IPv4 ? G_CALLBACK(_dev_dhcpx_state_changed_4) : G_CALLBACK(_dev_dhcpx_state_changed_6), + self); + if (!IS_IPv4) { + priv->dhcp6.prefix_sigid = g_signal_connect(priv->dhcp_data_6.client, + NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED, + G_CALLBACK(_dev_dhcp6_prefix_delegated), + self); + } + + if (!priv->dhcp_data_x[IS_IPv4].config) { + priv->dhcp_data_x[IS_IPv4].config = nm_dhcp_config_new(addr_family); + _notify(self, PROP_DHCPX_CONFIG(IS_IPv4)); + } else + nm_dhcp_config_set_lease(priv->dhcp_data_x[IS_IPv4].config, NULL); + + return TRUE; } -gboolean -nm_device_dhcp4_renew(NMDevice *self, gboolean release) +static void +_dev_dhcp6_set_dhcp_level(NMDevice *self, NMNDiscDHCPLevel dhcp_level) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - g_return_val_if_fail(priv->dhcp_data_4.client != NULL, FALSE); + if (priv->dhcp6.mode == dhcp_level) + return; + + _LOGD(LOGD_DEVICE | LOGD_DHCP6, "reset DHCPv6 level to %d", (int) dhcp_level); - _LOGI(LOGD_DHCP4, "DHCPv4 lease renewal requested"); + _dev_dhcpx_cleanup(self, AF_INET6, TRUE, TRUE); - /* Terminate old DHCP instance and release the old lease */ - dhcp4_cleanup(self, CLEANUP_TYPE_DECONFIGURE, release); + priv->dhcp6.mode = dhcp_level; + if (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_NONE) + return; - /* Start DHCP again on the interface */ - return dhcp4_start(self) != NM_ACT_STAGE_RETURN_FAILURE; + _dev_dhcpx_start(self, AF_INET6); } /*****************************************************************************/ -static NMIP4Config * -shared4_new_config(NMDevice *self, NMConnection *connection) +gboolean +nm_device_dhcp_renew(NMDevice *self, int addr_family, gboolean release) { - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMIP4Config * config; - NMSettingIPConfig * s_ip4; - NMPlatformIP4Address address = { - .addr_source = NM_IP_CONFIG_SOURCE_SHARED, - }; - - g_return_val_if_fail(self, NULL); - g_return_val_if_fail(connection, NULL); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const int IS_IPv4 = NM_IS_IPv4(addr_family); - s_ip4 = nm_connection_get_setting_ip4_config(connection); - if (s_ip4 && nm_setting_ip_config_get_num_addresses(s_ip4) > 0) { - /* Use the first user-supplied address */ - NMIPAddress *user = nm_setting_ip_config_get_address(s_ip4, 0); - in_addr_t a; + if (!priv->dhcp_data_x[IS_IPv4].client) + g_return_val_if_reached(FALSE); - nm_ip_address_get_address_binary(user, &a); - nm_platform_ip4_address_set_addr(&address, a, nm_ip_address_get_prefix(user)); - nm_clear_pointer(&priv->shared_ip_handle, nm_netns_shared_ip_release); - } else { - if (!priv->shared_ip_handle) - priv->shared_ip_handle = nm_netns_shared_ip_reserve(nm_device_get_netns(self)); - nm_platform_ip4_address_set_addr(&address, priv->shared_ip_handle->addr, 24); - } + _LOGI(LOGD_DHCPX(IS_IPv4), + "dhcp%c lease renewal requested", + nm_utils_addr_family_to_char(addr_family)); - config = nm_device_ip4_config_new(self); - nm_ip4_config_add_address(config, &address); + _dev_dhcpx_cleanup(self, addr_family, FALSE, release); - return config; + return _dev_dhcpx_start(self, addr_family); } /*****************************************************************************/ @@ -9610,402 +9478,41 @@ connection_requires_carrier(NMConnection *connection) if (ip6_carrier_wanted) { /* If IPv6 wants a carrier and cannot fail, the whole connection * requires a carrier regardless of the IPv4 method. - */ - s_ip6 = nm_connection_get_setting_ip6_config(connection); - if (s_ip6 && !nm_setting_ip_config_get_may_fail(s_ip6)) - return TRUE; - } - - /* If an IP version wants a carrier and the other IP version isn't - * used, the connection requires carrier since it will just fail without one. - */ - if (ip4_carrier_wanted && !ip6_used) - return TRUE; - if (ip6_carrier_wanted && !ip4_used) - return TRUE; - - /* If both want a carrier, the whole connection wants a carrier */ - return ip4_carrier_wanted && ip6_carrier_wanted; -} - -static gboolean -have_any_ready_slaves(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - SlaveInfo * info; - CList * iter; - - /* Any enslaved slave is "ready" in the generic case as it's - * at least >= NM_DEVCIE_STATE_IP_CONFIG and has had Layer 2 - * properties set up. - */ - c_list_for_each (iter, &priv->slaves) { - info = c_list_entry(iter, SlaveInfo, lst_slave); - if (NM_DEVICE_GET_PRIVATE(info->slave)->is_enslaved) - return TRUE; - } - return FALSE; -} - -/*****************************************************************************/ -/* DHCPv6 stuff */ - -static void -dhcp6_cleanup(NMDevice *self, CleanupType cleanup_type, gboolean release) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - priv->dhcp_data_6.was_active = FALSE; - priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_NONE; - applied_config_clear(&priv->dhcp6.ip6_config); - nm_clear_g_free(&priv->dhcp6.event_id); - nm_clear_g_source(&priv->dhcp_data_6.grace_id); - priv->dhcp_data_6.grace_pending = FALSE; - - if (priv->dhcp_data_6.client) { - nm_clear_g_signal_handler(priv->dhcp_data_6.client, &priv->dhcp_data_6.state_sigid); - nm_clear_g_signal_handler(priv->dhcp_data_6.client, &priv->dhcp6.prefix_sigid); - - if (cleanup_type == CLEANUP_TYPE_DECONFIGURE || cleanup_type == CLEANUP_TYPE_REMOVED) - nm_dhcp_client_stop(priv->dhcp_data_6.client, release); - - g_clear_object(&priv->dhcp_data_6.client); - } - - if (priv->dhcp_data_6.config) { - nm_dbus_object_clear_and_unexport(&priv->dhcp_data_6.config); - _notify(self, PROP_DHCP6_CONFIG); - } -} - -static gboolean -dhcp6_lease_change(NMDevice *self) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMSettingsConnection *settings_connection; - - if (!applied_config_get_current(&priv->dhcp6.ip6_config)) { - _LOGW(LOGD_DHCP6, "failed to get DHCPv6 config for rebind"); - return FALSE; - } - - g_assert(priv->dhcp_data_6.client); /* sanity check */ - - settings_connection = nm_device_get_settings_connection(self); - g_assert(settings_connection); - - /* Apply the updated config */ - if (!ip_config_merge_and_apply(self, AF_INET6, TRUE)) { - _LOGW(LOGD_DHCP6, "failed to update IPv6 config in response to DHCP event"); - return FALSE; - } - - nm_dispatcher_call_device(NM_DISPATCHER_ACTION_DHCP6_CHANGE, self, NULL, NULL, NULL, NULL); - - return TRUE; -} - -static void -dhcp6_fail(NMDevice *self, NMDhcpState dhcp_state) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - gboolean is_dhcp_managed; - - _LOGD(LOGD_DHCP6, - "DHCPv6 failed (ip_state %s, was_active %d)", - 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. */ - - /* Nothing to do if we failed before... */ - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_FAIL) - goto clear_config; - - is_dhcp_managed = (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_MANAGED); - - if (is_dhcp_managed) { - /* ... and also if there are static addresses configured - * on the interface. - */ - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE && priv->con_ip_config_6 - && nm_ip6_config_get_num_addresses(priv->con_ip_config_6)) - goto clear_config; - - /* Fail the method when one of the following is true: - * 1) the DHCP client terminated: it does not make sense to start a grace - * period without a client running; - * 2) we failed to get an initial lease AND the client was - * not active before. - */ - if (dhcp_state == NM_DHCP_STATE_TERMINATED - || (!priv->dhcp_data_6.was_active && priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF)) { - nm_device_activate_schedule_ip_config_timeout(self, AF_INET6); - return; - } - - if (dhcp_grace_period_start(self, AF_INET6)) - goto clear_config; - } else { - /* not a hard failure; just live with the RA info */ - dhcp6_cleanup(self, CLEANUP_TYPE_DECONFIGURE, FALSE); - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF) - nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); - } - return; - -clear_config: - /* The previous configuration is no longer valid */ - if (priv->dhcp_data_6.config) { - nm_dbus_object_clear_and_unexport(&priv->dhcp_data_6.config); - priv->dhcp_data_6.config = nm_dhcp_config_new(AF_INET6); - _notify(self, PROP_DHCP6_CONFIG); - } -} - -static void -dhcp6_state_changed(NMDhcpClient *client, - NMDhcpState state, - NMIP6Config * ip6_config, - GHashTable * options, - gpointer user_data) -{ - NMDevice * self = NM_DEVICE(user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - gs_free char * event_id = NULL; - - g_return_if_fail(nm_dhcp_client_get_addr_family(client) == AF_INET6); - g_return_if_fail(!ip6_config || NM_IS_IP6_CONFIG(ip6_config)); - - _LOGD(LOGD_DHCP6, "new DHCPv6 client state %d", state); - - switch (state) { - case NM_DHCP_STATE_BOUND: - case NM_DHCP_STATE_EXTENDED: - nm_clear_g_source(&priv->dhcp_data_6.grace_id); - priv->dhcp_data_6.grace_pending = FALSE; - /* If the server sends multiple IPv6 addresses, we receive a state - * changed event for each of them. Use the event ID to merge IPv6 - * addresses from the same transaction into a single configuration. - */ - - event_id = nm_dhcp_utils_get_dhcp6_event_id(options); - - if (ip6_config && event_id && priv->dhcp6.event_id - && nm_streq(event_id, priv->dhcp6.event_id)) { - NMDedupMultiIter ipconf_iter; - const NMPlatformIP6Address *a; - - nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6_config, &a) - applied_config_add_address(&priv->dhcp6.ip6_config, NM_PLATFORM_IP_ADDRESS_CAST(a)); - } else { - nm_clear_g_free(&priv->dhcp6.event_id); - if (ip6_config) { - applied_config_init(&priv->dhcp6.ip6_config, ip6_config); - priv->dhcp6.event_id = g_strdup(event_id); - nm_dhcp_config_set_options(priv->dhcp_data_6.config, options); - _notify(self, PROP_DHCP6_CONFIG); - } else - applied_config_clear(&priv->dhcp6.ip6_config); - } - - /* After long time we have been able to renew the lease: - * update the ip state - */ - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_FAIL) - _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_CONF); - - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF) { - if (!applied_config_get_current(&priv->dhcp6.ip6_config)) { - nm_device_ip_method_failed(self, AF_INET6, NM_DEVICE_STATE_REASON_DHCP_FAILED); - break; - } - nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); - } else if (priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) - if (!dhcp6_lease_change(self)) - dhcp6_fail(self, state); - break; - case NM_DHCP_STATE_TIMEOUT: - if (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_MANAGED) - dhcp6_fail(self, state); - else { - /* not a hard failure; just live with the RA info */ - dhcp6_cleanup(self, CLEANUP_TYPE_DECONFIGURE, FALSE); - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF) - nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); - } - break; - case NM_DHCP_STATE_EXPIRE: - /* Ignore expiry before we even have a lease (NAK, old lease, etc) */ - if (priv->ip_state_6 != NM_DEVICE_IP_STATE_CONF) - dhcp6_fail(self, state); - break; - case NM_DHCP_STATE_TERMINATED: - /* In IPv6 info-only mode, the client doesn't handle leases so it - * may exit right after getting a response from the server. That's - * normal. In that case we just ignore the exit. - */ - if (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) - break; - /* fall-through */ - case NM_DHCP_STATE_DONE: - case NM_DHCP_STATE_FAIL: - dhcp6_fail(self, state); - break; - default: - break; - } -} - -static void -dhcp6_prefix_delegated(NMDhcpClient *client, NMPlatformIP6Address *prefix, gpointer user_data) -{ - NMDevice *self = NM_DEVICE(user_data); - - /* Just re-emit. The device just contributes the prefix to the - * pool in NMPolicy, which decides about subnet allocation - * on the shared devices. */ - g_signal_emit(self, signals[IP6_PREFIX_DELEGATED], 0, prefix); -} - -/*****************************************************************************/ - -static gboolean -dhcp6_start_with_link_ready(NMDevice *self, NMConnection *connection) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMSettingIPConfig *s_ip6; - gs_unref_bytes GBytes *hwaddr = NULL; - gs_unref_bytes GBytes * duid = NULL; - gboolean enforce_duid = FALSE; - const NMPlatformLink * pllink; - gs_free char * mud_url_free = NULL; - GError * error = NULL; - guint32 iaid; - gboolean iaid_explicit; - NMSettingConnection * s_con; - const NMPlatformIP6Address *ll_addr = NULL; - - g_return_val_if_fail(connection, FALSE); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - nm_assert(s_ip6); - s_con = nm_connection_get_setting_connection(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); - } - - if (!ll_addr) { - _LOGW(LOGD_DHCP6, "can't start DHCPv6: no link-local address"); - return 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); - - iaid = _prop_get_ipvx_dhcp_iaid(self, AF_INET6, connection, TRUE, &iaid_explicit); - duid = _prop_get_ipv6_dhcp_duid(self, connection, hwaddr, &enforce_duid); - - priv->dhcp_data_6.client = nm_dhcp_manager_start_ip6( - nm_dhcp_manager_get(), - nm_device_get_multi_index(self), - nm_device_get_ip_iface(self), - nm_device_get_ip_ifindex(self), - &ll_addr->address, - 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), - duid, - enforce_duid, - iaid, - iaid_explicit, - _prop_get_ipvx_dhcp_timeout(self, AF_INET6), - _device_get_dhcp_anycast_address(self), - nm_setting_ip6_config_get_ip6_privacy(NM_SETTING_IP6_CONFIG(s_ip6)), - priv->dhcp6.needed_prefixes, - &error); - if (!priv->dhcp_data_6.client) { - _LOGW(LOGD_DHCP6, "failure to start DHCPv6: %s", error->message); - g_clear_error(&error); - if (nm_device_sys_iface_state_is_external_or_assume(self)) - priv->dhcp_data_6.was_active = TRUE; - return FALSE; + */ + s_ip6 = nm_connection_get_setting_ip6_config(connection); + if (s_ip6 && !nm_setting_ip_config_get_may_fail(s_ip6)) + return TRUE; } - priv->dhcp_data_6.state_sigid = g_signal_connect(priv->dhcp_data_6.client, - NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, - G_CALLBACK(dhcp6_state_changed), - self); - priv->dhcp6.prefix_sigid = g_signal_connect(priv->dhcp_data_6.client, - NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED, - G_CALLBACK(dhcp6_prefix_delegated), - self); - - if (nm_device_sys_iface_state_is_external_or_assume(self)) - priv->dhcp_data_6.was_active = TRUE; + /* If an IP version wants a carrier and the other IP version isn't + * used, the connection requires carrier since it will just fail without one. + */ + if (ip4_carrier_wanted && !ip6_used) + return TRUE; + if (ip6_carrier_wanted && !ip4_used) + return TRUE; - return TRUE; + /* If both want a carrier, the whole connection wants a carrier */ + return ip4_carrier_wanted && ip6_carrier_wanted; } static gboolean -dhcp6_start(NMDevice *self, gboolean wait_for_ll) +have_any_ready_slaves(NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMConnection * connection; - - nm_dbus_object_clear_and_unexport(&priv->dhcp_data_6.config); - priv->dhcp_data_6.config = nm_dhcp_config_new(AF_INET6); - - nm_assert(!applied_config_get_current(&priv->dhcp6.ip6_config)); - applied_config_clear(&priv->dhcp6.ip6_config); - nm_clear_g_free(&priv->dhcp6.event_id); - - connection = nm_device_get_applied_connection(self); - g_return_val_if_fail(connection, FALSE); + SlaveInfo * info; + CList * iter; - if (wait_for_ll) { - /* ensure link local is ready... */ - if (!linklocal6_start(self)) { - /* wait for the LL address to show up */ + /* Any enslaved slave is "ready" in the generic case as it's + * at least >= NM_DEVCIE_STATE_IP_CONFIG and has had Layer 2 + * properties set up. + */ + c_list_for_each (iter, &priv->slaves) { + info = c_list_entry(iter, SlaveInfo, lst_slave); + if (NM_DEVICE_GET_PRIVATE(info->slave)->is_enslaved) return TRUE; - } - /* already have the LL address; kick off DHCP */ } - - if (!dhcp6_start_with_link_ready(self, connection)) - return FALSE; - - return TRUE; -} - -gboolean -nm_device_dhcp6_renew(NMDevice *self, gboolean release) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMNDiscDHCPLevel mode; - - g_return_val_if_fail(priv->dhcp_data_6.client != NULL, FALSE); - - _LOGI(LOGD_DHCP6, "DHCPv6 lease renewal requested"); - - /* Terminate old DHCP instance and release the old lease */ - mode = priv->dhcp6.mode; - dhcp6_cleanup(self, CLEANUP_TYPE_DECONFIGURE, release); - priv->dhcp6.mode = mode; - - /* Start DHCP again on the interface */ - return dhcp6_start(self, FALSE); + return FALSE; } /*****************************************************************************/ @@ -10023,7 +9530,7 @@ nm_device_request_ip6_prefixes(NMDevice *self, int needed_prefixes) if (priv->dhcp_data_6.client) { _LOGD(LOGD_IP6, "ipv6-pd: asking DHCPv6 for %d prefixes", needed_prefixes); - nm_device_dhcp6_renew(self, FALSE); + nm_device_dhcp_renew(self, AF_INET6, FALSE); } else { _LOGI(LOGD_IP6, "ipv6-pd: device doesn't use DHCPv6, can't request prefixes"); } @@ -10042,25 +9549,24 @@ nm_device_needs_ip6_subnet(NMDevice *self) void nm_device_use_ip6_subnet(NMDevice *self, const NMPlatformIP6Address *subnet) { - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMPlatformIP6Address address = *subnet; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + char sbuf[sizeof(_nm_utils_to_string_buffer)]; + NMPlatformIP6Address address; - if (!applied_config_get_current(&priv->ac_ip6_config)) - applied_config_init_new(&priv->ac_ip6_config, self, AF_INET6); + l3cd = nm_device_create_l3_config_data(self); /* Assign a ::1 address in the subnet for us. */ + address = *subnet; address.address.s6_addr32[3] |= htonl(1); - applied_config_add_address(&priv->ac_ip6_config, NM_PLATFORM_IP_ADDRESS_CAST(&address)); + + nm_l3_config_data_add_address_6(l3cd, &address); _LOGD(LOGD_IP6, - "ipv6-pd: using %s address (preferred for %u seconds)", - _nm_utils_inet6_ntop(&address.address, sbuf), - subnet->preferred); + "ipv6-pd: using %s", + nm_platform_ip6_address_to_string(&address, sbuf, sizeof(sbuf))); - /* This also updates the ndisc if there are actual changes. */ - if (!ip_config_merge_and_apply(self, AF_INET6, TRUE)) - _LOGW(LOGD_IP6, "ipv6-pd: failed applying IP6 config for connection sharing"); + _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_PD_6, l3cd, FALSE); + _dev_l3_cfg_commit(self, TRUE); } /* @@ -10070,41 +9576,47 @@ nm_device_use_ip6_subnet(NMDevice *self, const NMPlatformIP6Address *subnet) void nm_device_copy_ip6_dns_config(NMDevice *self, NMDevice *from_device) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMIP6Config * from_config = NULL; - guint i, len; + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMDevicePrivate * priv_src; + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + const NML3ConfigData * l3cd_src; + + /* FIXME(l3fcg): this entire code an approach seems flawed. It's flawed, because the + * very next RA will reset the changes. */ - if (applied_config_get_current(&priv->ac_ip6_config)) { - applied_config_reset_nameservers(&priv->ac_ip6_config); - applied_config_reset_searches(&priv->ac_ip6_config); + if (priv->l3cds[L3_CONFIG_DATA_TYPE_AC_6].d) { + l3cd = nm_l3_config_data_new_clone(priv->l3cds[L3_CONFIG_DATA_TYPE_AC_6].d, 0); + nm_l3_config_data_clear_nameservers(l3cd, AF_INET6); + nm_l3_config_data_clear_searches(l3cd, AF_INET6); } else - applied_config_init_new(&priv->ac_ip6_config, self, AF_INET6); + l3cd = nm_device_create_l3_config_data(self); - if (from_device) - from_config = nm_device_get_ip6_config(from_device); - if (!from_config) - return; + priv_src = NM_DEVICE_GET_PRIVATE(from_device); + l3cd_src = priv_src->l3cds[L3_CONFIG_DATA_TYPE_AC_6].d; + if (l3cd_src) { + const char *const * strvarr; + const struct in6_addr *const *addrs; + guint n; + guint i; - len = nm_ip6_config_get_num_nameservers(from_config); - for (i = 0; i < len; i++) { - applied_config_add_nameserver( - &priv->ac_ip6_config, - (const NMIPAddr *) nm_ip6_config_get_nameserver(from_config, i)); - } + addrs = nm_l3_config_data_get_nameservers(l3cd_src, AF_INET6, &n); + for (i = 0; i < n; i++) + nm_l3_config_data_add_nameserver(l3cd, AF_INET6, addrs[i]); - len = nm_ip6_config_get_num_searches(from_config); - for (i = 0; i < len; i++) { - applied_config_add_search(&priv->ac_ip6_config, nm_ip6_config_get_search(from_config, i)); + strvarr = nm_l3_config_data_get_searches(l3cd_src, AF_INET6, &n); + for (i = 0; i < n; i++) + nm_l3_config_data_add_search(l3cd, AF_INET6, strvarr[i]); } - if (!ip_config_merge_and_apply(self, AF_INET6, TRUE)) - _LOGW(LOGD_IP6, "ipv6-pd: failed applying DNS config for connection sharing"); + _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_AC_6, l3cd, FALSE); + + _dev_l3_cfg_commit(self, TRUE); } /*****************************************************************************/ static void -linklocal6_failed(NMDevice *self) +_dev_ll6_failed(NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); @@ -10113,17 +9625,18 @@ linklocal6_failed(NMDevice *self) } static gboolean -linklocal6_timeout_cb(gpointer user_data) +_dev_ll6_timeout_cb(gpointer user_data) { NMDevice *self = user_data; _LOGD(LOGD_DEVICE, "linklocal6: waiting for link-local addresses failed due to timeout"); - linklocal6_failed(self); + _dev_ll6_failed(self); return G_SOURCE_REMOVE; } -static void -linklocal6_check_complete(NMDevice *self) +//XXX +_nm_unused static void +_dev_ll6_check_complete(NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); NMConnection * connection; @@ -10134,18 +9647,18 @@ linklocal6_check_complete(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)) { - /* we don't have a non-tentative link local address yet. Wait longer. */ - return; - } + //XXX if ( !priv->ext_ip6_config_captured + //XXX || !nm_ip6_config_find_first_address (priv->ext_ip6_config_captured, + //XXX NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL + //XXX | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) { + //XXX /* we don't have a non-tentative link local address yet. Wait longer. */ + //XXX return; + //XXX } nm_clear_g_source(&priv->linklocal6_timeout_id); connection = nm_device_get_applied_connection(self); - g_assert(connection); + g_return_if_fail(connection); method = nm_device_get_effective_ip_config_method(self, AF_INET6); @@ -10156,14 +9669,14 @@ linklocal6_check_complete(NMDevice *self) if (NM_IN_STRSET(method, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NM_SETTING_IP6_CONFIG_METHOD_SHARED)) - addrconf6_start_with_link_ready(self); + _dev_ac6_start(self); else if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) { - if (!dhcp6_start_with_link_ready(self, connection)) { + if (!_dev_dhcpx_start(self, AF_INET6)) { /* Time out IPv6 instead of failing the entire activation */ nm_device_activate_schedule_ip_config_timeout(self, AF_INET6); } } else if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) - nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); + nm_device_activate_schedule_ip_config_result(self, AF_INET6); else g_return_if_fail(FALSE); } @@ -10182,17 +9695,18 @@ check_and_add_ipv6ll_addr(NMDevice *self) if (!priv->ipv6ll_handle) 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)) { - /* Already have an LL address, nothing to do */ - return; - } + //XXX if ( priv->ext_ip6_config_captured + //XXX && nm_ip6_config_find_first_address (priv->ext_ip6_config_captured, + //XXX NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL + //XXX | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL + //XXX | NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE)) { + //XXX /* Already have an LL address, nothing to do */ + //XXX return; + //XXX } priv->ipv6ll_has = FALSE; memset(&priv->ipv6ll_addr, 0, sizeof(priv->ipv6ll_addr)); + _dev_l3_set_l3cd_ll_6(self); memset(&lladdr, 0, sizeof(lladdr)); lladdr.s6_addr16[0] = htons(0xfe80); @@ -10216,7 +9730,7 @@ check_and_add_ipv6ll_addr(NMDevice *self) &error)) { _LOGW(LOGD_IP6, "linklocal6: failed to generate an address: %s", error->message); g_clear_error(&error); - linklocal6_failed(self); + _dev_ll6_failed(self); return; } addr_type = "stable-privacy"; @@ -10227,7 +9741,7 @@ check_and_add_ipv6ll_addr(NMDevice *self) /* We already started and attempt to add a LL address. For the EUI-64 * mode we can't pick a new one, we'll just fail. */ _LOGW(LOGD_IP6, "linklocal6: DAD failed for an EUI-64 address"); - linklocal6_failed(self); + _dev_ll6_failed(self); return; } @@ -10245,21 +9759,36 @@ check_and_add_ipv6ll_addr(NMDevice *self) _nm_utils_inet6_ntop(&lladdr, sbuf)); priv->ipv6ll_has = TRUE; priv->ipv6ll_addr = lladdr; - ip_config_merge_and_apply(self, AF_INET6, TRUE); + _dev_l3_cfg_commit(self, TRUE); } static gboolean -linklocal6_start(NMDevice *self) +_dev_ll6_start(NMDevice *self, struct in6_addr *out_ll_addr) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + int ifindex; - nm_clear_g_source(&priv->linklocal6_timeout_id); + ifindex = nm_device_get_ip_ifindex(self); + if (ifindex > 0) { + const NMPObject *plobj; + NMDedupMultiIter iter; + NMPLookup lookup; + + nm_platform_iter_obj_for_each ( + &iter, + nm_device_get_platform(self), + nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP6_ADDRESS, ifindex), + &plobj) { + if (nm_platform_ip6_address_match(NMP_OBJECT_CAST_IP6_ADDRESS(plobj), + NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL + | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) { + NM_SET_OUT(out_ll_addr, NMP_OBJECT_CAST_IP6_ADDRESS(plobj)->address); + return TRUE; + } + } + } - 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)) - return TRUE; + nm_clear_g_source(&priv->linklocal6_timeout_id); _LOGD(LOGD_DEVICE, "linklocal6: starting IPv6 with method '%s', but the device has no link-local addresses " @@ -10273,7 +9802,7 @@ linklocal6_start(NMDevice *self) * FIXME: use dad/retrans sysctl values if they are higher than a minimum time. * (rh #1101809) */ - priv->linklocal6_timeout_id = g_timeout_add_seconds(15, linklocal6_timeout_cb, self); + priv->linklocal6_timeout_id = g_timeout_add_seconds(15, _dev_ll6_timeout_cb, self); return FALSE; } @@ -10437,13 +9966,16 @@ set_platform_mtu(NMDevice *self, guint32 mtu) } static void -_commit_mtu(NMDevice *self, const NMIP4Config *config) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMDeviceMtuSource source = NM_DEVICE_MTU_SOURCE_NONE; - guint32 ip6_mtu, ip6_mtu_orig; - guint32 mtu_desired, mtu_desired_orig; - guint32 mtu_plat; +_commit_mtu(NMDevice *self) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMDeviceMtuSource source = NM_DEVICE_MTU_SOURCE_NONE; + const NML3ConfigData *l3cd; + guint32 ip6_mtu_orig; + guint32 ip6_mtu; + guint32 mtu_desired_orig; + guint32 mtu_desired; + guint32 mtu_plat; struct { gboolean initialized; guint32 value; @@ -10451,7 +9983,9 @@ _commit_mtu(NMDevice *self, const NMIP4Config *config) 0, }; int ifindex; - char sbuf[64], sbuf1[64], sbuf2[64]; + char sbuf[64]; + char sbuf1[64]; + char sbuf2[64]; gboolean success = TRUE; ifindex = nm_device_get_ip_ifindex(self); @@ -10465,8 +9999,11 @@ _commit_mtu(NMDevice *self, const NMIP4Config *config) return; } + l3cd = nm_l3cfg_get_combined_l3cd(priv->l3cfg, FALSE); + { - guint32 mtu = 0; + guint32 mtu = 0; + guint32 mtu2; gboolean force = FALSE; /* We take the MTU from various sources: (in order of increasing @@ -10493,9 +10030,9 @@ _commit_mtu(NMDevice *self, const NMIP4Config *config) if (NM_DEVICE_GET_CLASS(self)->get_configured_mtu) mtu = NM_DEVICE_GET_CLASS(self)->get_configured_mtu(self, &source, &force); - if (config && !force && source < NM_DEVICE_MTU_SOURCE_IP_CONFIG - && nm_ip4_config_get_mtu(config)) { - mtu = nm_ip4_config_get_mtu(config); + if (l3cd && !force && source < NM_DEVICE_MTU_SOURCE_IP_CONFIG + && (mtu2 = nm_l3_config_data_get_mtu(l3cd)) > 0) { + mtu = mtu2; source = NM_DEVICE_MTU_SOURCE_IP_CONFIG; } @@ -10678,244 +10215,148 @@ nm_device_commit_mtu(NMDevice *self) state = nm_device_get_state(self); if (state >= NM_DEVICE_STATE_CONFIG && state < NM_DEVICE_STATE_DEACTIVATING) { _LOGT(LOGD_DEVICE, "mtu: commit-mtu..."); - _commit_mtu(self, NM_DEVICE_GET_PRIVATE(self)->ip_config_4); + _commit_mtu(self); } else _LOGT(LOGD_DEVICE, "mtu: commit-mtu... skip due to state %s", nm_device_state_to_str(state)); } +/*****************************************************************************/ + static void -ndisc_config_changed(NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_int, NMDevice *self) +_dev_ac6_ndisc_config_changed(NMNDisc * ndisc, + const NMNDiscData *rdata, + guint changed_i, + NMDevice * self) { - NMNDiscConfigMap changed = changed_int; - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - guint i; - - g_return_if_fail(priv->act_request.obj); - - if (!applied_config_get_current(&priv->ac_ip6_config)) - applied_config_init_new(&priv->ac_ip6_config, self, AF_INET6); - - if (changed & NM_NDISC_CONFIG_ADDRESSES) { - guint8 plen; - guint32 ifa_flags; - - /* Check, whether kernel is recent enough to help user space handling RA. - * If it's not supported, we have no ipv6-privacy and must add autoconf - * addresses as /128. The reason for the /128 is to prevent the kernel - * from adding a prefix route for this address. */ - ifa_flags = 0; - if (nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS)) { - ifa_flags |= IFA_F_NOPREFIXROUTE; - if (NM_IN_SET(priv->ndisc_use_tempaddr, - NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, - NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR)) - ifa_flags |= IFA_F_MANAGETEMPADDR; - plen = 64; - } else - plen = 128; - - nm_ip6_config_reset_addresses_ndisc((NMIP6Config *) priv->ac_ip6_config.orig, - rdata->addresses, - rdata->addresses_n, - plen, - ifa_flags); - if (priv->ac_ip6_config.current) { - nm_ip6_config_reset_addresses_ndisc((NMIP6Config *) priv->ac_ip6_config.current, - rdata->addresses, - rdata->addresses_n, - plen, - ifa_flags); - } - } - - if (NM_FLAGS_ANY(changed, NM_NDISC_CONFIG_ROUTES | NM_NDISC_CONFIG_GATEWAYS)) { - nm_ip6_config_reset_routes_ndisc( - (NMIP6Config *) priv->ac_ip6_config.orig, - rdata->gateways, - rdata->gateways_n, - rdata->routes, - rdata->routes_n, - nm_device_get_route_table(self, AF_INET6), - nm_device_get_route_metric(self, AF_INET6), - nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF)); - if (priv->ac_ip6_config.current) { - nm_ip6_config_reset_routes_ndisc( - (NMIP6Config *) priv->ac_ip6_config.current, - rdata->gateways, - rdata->gateways_n, - rdata->routes, - rdata->routes_n, - nm_device_get_route_table(self, AF_INET6), - nm_device_get_route_metric(self, AF_INET6), - nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF)); - } - } + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + int ifindex; - if (changed & NM_NDISC_CONFIG_DNS_SERVERS) { - /* Rebuild DNS server list from neighbor discovery cache. */ - applied_config_reset_nameservers(&priv->ac_ip6_config); - - for (i = 0; i < rdata->dns_servers_n; i++) - applied_config_add_nameserver(&priv->ac_ip6_config, - (const NMIPAddr *) &rdata->dns_servers[i].address); - } + ifindex = nm_device_get_ip_ifindex(self); + if (ifindex <= 0) + g_return_if_reached(); - if (changed & NM_NDISC_CONFIG_DNS_DOMAINS) { - /* Rebuild domain list from neighbor discovery cache. */ - applied_config_reset_searches(&priv->ac_ip6_config); + l3cd = nm_ndisc_data_to_l3cd( + nm_device_get_multi_index(self), + ifindex, + rdata, + priv->ac6_ip6_privacy, + nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF), + nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS)); - for (i = 0; i < rdata->dns_domains_n; i++) - applied_config_add_search(&priv->ac_ip6_config, rdata->dns_domains[i].domain); - } + _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_AC_6, l3cd, FALSE); - if (changed & NM_NDISC_CONFIG_DHCP_LEVEL) { - dhcp6_cleanup(self, CLEANUP_TYPE_DECONFIGURE, TRUE); + _dev_dhcp6_set_dhcp_level(self, rdata->dhcp_level); - priv->dhcp6.mode = rdata->dhcp_level; - if (priv->dhcp6.mode != NM_NDISC_DHCP_LEVEL_NONE) { - _LOGD(LOGD_DEVICE | LOGD_DHCP6, - "Activation: Stage 3 of 5 (IP Configure Start) starting DHCPv6" - " as requested by IPv6 router..."); - if (!dhcp6_start(self, FALSE)) { - if (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_MANAGED) { - nm_device_state_changed(self, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_DHCP_START_FAILED); - return; - } - } - } - } + _dev_l3_cfg_commit(self, TRUE); +} - if (changed & NM_NDISC_CONFIG_HOP_LIMIT) - nm_platform_sysctl_ip_conf_set_ipv6_hop_limit_safe(nm_device_get_platform(self), - nm_device_get_ip_iface(self), - rdata->hop_limit); +static void +_dev_ac6_handle_timeout(NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (changed & NM_NDISC_CONFIG_REACHABLE_TIME) { - nm_platform_sysctl_ip_neigh_set_ipv6_reachable_time(nm_device_get_platform(self), - nm_device_get_ip_iface(self), - rdata->reachable_time_ms); - } + _LOGD(LOGD_IP6, "ac6: timeout for autoconf (IPv6 router advertisement) reached"); - if (changed & NM_NDISC_CONFIG_RETRANS_TIMER) { - nm_platform_sysctl_ip_neigh_set_ipv6_retrans_time(nm_device_get_platform(self), - nm_device_get_ip_iface(self), - rdata->retrans_timer_ms); - } + nm_clear_g_source_inst(&priv->ac6_ndisc_grace_source); + priv->ac6_ndisc_grace_pending = FALSE; + _set_ip_state_check(self, AF_INET6); +} - if (changed & NM_NDISC_CONFIG_MTU) { - if (priv->ip6_mtu != rdata->mtu) { - _LOGD(LOGD_DEVICE, "mtu: set IPv6 MTU to %u", (guint) rdata->mtu); - priv->ip6_mtu = rdata->mtu; - } - } +static void +_dev_ac6_ndisc_ra_timeout(NMNDisc *ndisc, NMDevice *self) +{ + _dev_ac6_handle_timeout(self); +} - nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); +static gboolean +_dev_ac6_grace_period_expired(gpointer user_data) +{ + _dev_ac6_handle_timeout(user_data); + return G_SOURCE_REMOVE; } -static void -ndisc_ra_timeout(NMNDisc *ndisc, NMDevice *self) +static gboolean +_dev_ac6_grace_period_start(NMDevice *self, guint32 timeout_sec, gboolean force_restart) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - /* We don't want to stop listening for router advertisements completely, - * but instead let device activation continue activating. If an RA - * shows up later, we'll use it as long as the device is not disconnected. + /* In any other case (expired lease, assumed connection, etc.), + * wait for some time before failing the IP method. */ - - _LOGD(LOGD_IP6, "timed out waiting for IPv6 router advertisement"); - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF) { - /* If RA is our only source of addressing information and we don't - * ever receive one, then time out IPv6. But if there is other - * IPv6 configuration, like manual IPv6 addresses or external IPv6 - * config, consider that sufficient for IPv6 success. - * - * FIXME: it doesn't seem correct to determine this based on which - * 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_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); - else - nm_device_activate_schedule_ip_config_timeout(self, AF_INET6); + if (!force_restart && priv->ac6_ndisc_grace_pending) { + /* already pending. */ + return FALSE; } -} -static void -addrconf6_start_with_link_ready(NMDevice *self) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMUtilsIPv6IfaceId iid; + /* Start a grace period equal to the RA timeout multiplied + * by a constant factor. */ - g_assert(priv->ndisc); + nm_clear_g_source_inst(&priv->ac6_ndisc_grace_source); - if (nm_device_get_ip_iface_identifier(self, &iid, FALSE)) { - _LOGD(LOGD_IP6, "addrconf6: using the device EUI-64 identifier"); - nm_ndisc_set_iid(priv->ndisc, iid); - } else { - /* Don't abort the addrconf at this point -- if ndisc needs the iid - * it will notice this itself. */ - _LOGI(LOGD_IP6, "addrconf6: no interface identifier; IPv6 address creation may fail"); + if (timeout_sec == 0) { + priv->ac6_ndisc_grace_pending = FALSE; + return FALSE; } - /* Apply any manual configuration before starting RA */ - if (!ip_config_merge_and_apply(self, AF_INET6, TRUE)) - _LOGW(LOGD_IP6, "failed to apply manual IPv6 configuration"); + nm_assert(timeout_sec <= G_MAXINT32); - if (nm_ndisc_get_node_type(priv->ndisc) == NM_NDISC_NODE_TYPE_ROUTER) { - nm_device_sysctl_ip_conf_set(self, AF_INET6, "forwarding", "1"); - nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); - priv->needs_ip6_subnet = TRUE; - g_signal_emit(self, signals[IP6_SUBNET_NEEDED], 0); - } + if (timeout_sec == NM_RA_TIMEOUT_INFINITY) + _LOGD(LOGD_IP6, "ac6: grace period is infinity"); + else { + guint timeout_msec; - priv->ndisc_changed_id = g_signal_connect(priv->ndisc, - NM_NDISC_CONFIG_RECEIVED, - G_CALLBACK(ndisc_config_changed), - self); - priv->ndisc_timeout_id = g_signal_connect(priv->ndisc, - NM_NDISC_RA_TIMEOUT_SIGNAL, - G_CALLBACK(ndisc_ra_timeout), - self); + _LOGD(LOGD_IP6, "ac6: grace period is %u seconds", timeout_sec); - ndisc_set_router_config(priv->ndisc, self); - nm_ndisc_start(priv->ndisc); - priv->ndisc_started = TRUE; - return; + if (timeout_sec < G_MAXUINT / (GRACE_PERIOD_MULTIPLIER * 1000u)) + timeout_msec = timeout_sec * (GRACE_PERIOD_MULTIPLIER * 1000u); + else + timeout_msec = G_MAXUINT; + + priv->ac6_ndisc_grace_source = + nm_g_source_attach(nm_g_timeout_source_new(timeout_msec, + G_PRIORITY_DEFAULT, + _dev_ac6_grace_period_expired, + self, + NULL), + NULL); + } + + priv->ac6_ndisc_grace_pending = TRUE; + return TRUE; } static gboolean -addrconf6_start(NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) +_dev_ac6_start(NMDevice *self) { NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMSettingIP6Config *s_ip; NMConnection * connection; - NMSettingIP6Config *s_ip6 = NULL; - GError * error = NULL; - NMUtilsStableType stable_type; - const char * stable_id; - NMNDiscNodeType node_type; - int max_addresses; - int router_solicitations; - int router_solicitation_interval; - guint32 ra_timeout; - guint32 default_ra_timeout; + gs_free_error GError *error = NULL; + NMUtilsStableType stable_type; + NMNDiscNodeType node_type; + const char * stable_id; + int max_addresses; + int router_solicitations; + int router_solicitation_interval; + guint32 ra_timeout; + guint32 default_ra_timeout; + NMUtilsIPv6IfaceId iid; connection = nm_device_get_applied_connection(self); - g_assert(connection); - - nm_assert(!applied_config_get_current(&priv->ac_ip6_config)); - applied_config_clear(&priv->ac_ip6_config); + nm_assert(connection); + s_ip = NM_SETTING_IP6_CONFIG(nm_connection_get_setting_ip6_config(connection)); + nm_assert(s_ip); - nm_clear_pointer(&priv->rt6_temporary_not_available, g_hash_table_unref); - nm_clear_g_source(&priv->rt6_temporary_not_available_id); + priv->ac6_ndisc_started = TRUE; - s_ip6 = NM_SETTING_IP6_CONFIG(nm_connection_get_setting_ip6_config(connection)); - g_assert(s_ip6); + if (!_dev_ll6_start(self, NULL)) { + /* wait for the LL address to show up */ + _dev_ac6_grace_period_start(self, 30, TRUE); + return TRUE; + } if (nm_streq(nm_device_get_effective_ip_config_method(self, AF_INET6), NM_SETTING_IP4_CONFIG_METHOD_SHARED)) @@ -10938,28 +10379,30 @@ addrconf6_start(NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) ra_timeout = default_ra_timeout; } - stable_id = _prop_get_connection_stable_id(self, connection, &stable_type); - priv->ndisc = nm_lndp_ndisc_new(nm_device_get_platform(self), - nm_device_get_ip_ifindex(self), - nm_device_get_ip_iface(self), - stable_type, - stable_id, - nm_setting_ip6_config_get_addr_gen_mode(s_ip6), - node_type, - max_addresses, - router_solicitations, - router_solicitation_interval, - ra_timeout, - &error); - if (!priv->ndisc) { + _dev_ac6_grace_period_start(self, ra_timeout, TRUE); + + stable_id = _prop_get_connection_stable_id(self, connection, &stable_type); + + priv->ac6_ndisc = nm_lndp_ndisc_new(nm_device_get_platform(self), + nm_device_get_ip_ifindex(self), + nm_device_get_ip_iface(self), + stable_type, + stable_id, + nm_setting_ip6_config_get_addr_gen_mode(s_ip), + node_type, + max_addresses, + router_solicitations, + router_solicitation_interval, + ra_timeout, + &error); + if (!priv->ac6_ndisc) { _LOGE(LOGD_IP6, "addrconf6: failed to start neighbor discovery: %s", error->message); - g_error_free(error); return FALSE; } - priv->ndisc_use_tempaddr = use_tempaddr; + priv->ac6_ip6_privacy = _prop_get_ipv6_ip6_privacy(self); - if (NM_IN_SET(use_tempaddr, + if (NM_IN_SET(priv->ac6_ip6_privacy, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR) && !nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS)) { @@ -10968,32 +10411,58 @@ addrconf6_start(NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) "IPv6 private addresses. This feature is not available"); } - /* ensure link local is ready... */ - if (!linklocal6_start(self)) { - /* wait for the LL address to show up */ - return TRUE; + if (nm_device_get_ip_iface_identifier(self, &iid, FALSE)) { + _LOGD(LOGD_IP6, "addrconf6: using the device EUI-64 identifier"); + nm_ndisc_set_iid(priv->ac6_ndisc, iid); + } else { + /* Don't abort the addrconf at this point -- if ndisc needs the iid + * it will notice this itself. */ + _LOGD(LOGD_IP6, "addrconf6: no interface identifier; IPv6 address creation may fail"); + } + + _dev_l3_cfg_commit(self, TRUE); + + if (nm_ndisc_get_node_type(priv->ac6_ndisc) == NM_NDISC_NODE_TYPE_ROUTER) { + nm_device_sysctl_ip_conf_set(self, AF_INET6, "forwarding", "1"); + nm_device_activate_schedule_ip_config_result(self, AF_INET6); + priv->needs_ip6_subnet = TRUE; + g_signal_emit(self, signals[IP6_SUBNET_NEEDED], 0); } - /* already have the LL address; kick off neighbor discovery */ - addrconf6_start_with_link_ready(self); + priv->ac6_ndisc_changed_id = g_signal_connect(priv->ac6_ndisc, + NM_NDISC_CONFIG_RECEIVED, + G_CALLBACK(_dev_ac6_ndisc_config_changed), + self); + priv->ac6_ndisc_timeout_id = g_signal_connect(priv->ac6_ndisc, + NM_NDISC_RA_TIMEOUT_SIGNAL, + G_CALLBACK(_dev_ac6_ndisc_ra_timeout), + self); + + _dev_ac6_ndisc_set_router_config(self); + + nm_ndisc_start(priv->ac6_ndisc); + + priv->ac6_ndisc_started = TRUE; + return TRUE; } static void -addrconf6_cleanup(NMDevice *self) +_dev_ac6_cleanup(NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - priv->ndisc_started = FALSE; - nm_clear_g_signal_handler(priv->ndisc, &priv->ndisc_changed_id); - nm_clear_g_signal_handler(priv->ndisc, &priv->ndisc_timeout_id); + priv->ac6_ndisc_started = FALSE; + priv->ac6_ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; + + nm_clear_g_signal_handler(priv->ac6_ndisc, &priv->ac6_ndisc_changed_id); + nm_clear_g_signal_handler(priv->ac6_ndisc, &priv->ac6_ndisc_timeout_id); - applied_config_clear(&priv->ac_ip6_config); - nm_clear_pointer(&priv->rt6_temporary_not_available, g_hash_table_unref); - nm_clear_g_source(&priv->rt6_temporary_not_available_id); - if (priv->ndisc) { - nm_ndisc_stop(priv->ndisc); - g_clear_object(&priv->ndisc); + _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_AC_6, NULL, FALSE); + + if (priv->ac6_ndisc) { + nm_ndisc_stop(priv->ac6_ndisc); + g_clear_object(&priv->ac6_ndisc); } } @@ -11115,10 +10584,10 @@ ip_requires_slaves(NMDevice *self, int addr_family) } static NMActStageReturn -act_stage3_ip_config_start(NMDevice * self, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) +act_stage3_ip_config_start(NMDevice * self, + int addr_family, + const NML3ConfigData **out_l3cd, + NMDeviceStateReason * out_failure_reason) { const int IS_IPv4 = NM_IS_IPv4(addr_family); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); @@ -11167,52 +10636,34 @@ act_stage3_ip_config_start(NMDevice * self, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) { NMSettingIPConfig *s_ip4; - NMIP4Config ** configs, *config; guint num_addresses; + /* FIXME(l3cfg) */ s_ip4 = nm_connection_get_setting_ip4_config(connection); g_return_val_if_fail(s_ip4, NM_ACT_STAGE_RETURN_FAILURE); num_addresses = nm_setting_ip_config_get_num_addresses(s_ip4); if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { - ret = dhcp4_start(self); - if (ret == NM_ACT_STAGE_RETURN_FAILURE) { + if (!_dev_dhcpx_start(self, AF_INET)) { NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_DHCP_START_FAILED); - return ret; + return NM_ACT_STAGE_RETURN_FAILURE; } - } else { + } else g_return_val_if_fail(num_addresses != 0, NM_ACT_STAGE_RETURN_FAILURE); - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } - - if (num_addresses) { - config = nm_device_ip4_config_new(self); - nm_ip4_config_merge_setting(config, - nm_connection_get_setting_ip4_config(connection), - NM_SETTING_CONNECTION_MDNS_DEFAULT, - NM_SETTING_CONNECTION_LLMNR_DEFAULT, - nm_device_get_route_table(self, AF_INET), - nm_device_get_route_metric(self, AF_INET)); - configs = g_new0(NMIP4Config *, 2); - configs[0] = config; - ipv4_dad_start(self, configs, ipv4_manual_method_apply); - } + ret = NM_ACT_STAGE_RETURN_POSTPONE; } else if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) { - ret = ipv4ll_start(self); + ret = _dev_ll4_start(self); if (ret == NM_ACT_STAGE_RETURN_FAILURE) NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED); } else if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) { - if (out_config) { - *out_config = shared4_new_config(self, connection); - if (*out_config) { - priv->dnsmasq_manager = nm_dnsmasq_manager_new(nm_device_get_ip_iface(self)); - ret = NM_ACT_STAGE_RETURN_SUCCESS; - } else { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - ret = NM_ACT_STAGE_RETURN_FAILURE; - } - } else - g_return_val_if_reached(NM_ACT_STAGE_RETURN_FAILURE); + gs_free_error GError *error = NULL; + + if (!_dev_shared4_start(self, &error)) { + _LOGW(LOGD_SHARING, "Activation: start sharing failed: %s", error->message); + NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_SHARED_START_FAILED); + return NM_ACT_STAGE_RETURN_FAILURE; + } + ret = NM_ACT_STAGE_RETURN_SUCCESS; } else if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) ret = NM_ACT_STAGE_RETURN_SUCCESS; else @@ -11220,10 +10671,7 @@ act_stage3_ip_config_start(NMDevice * self, return ret; } else { - NMSettingIP6ConfigPrivacy ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; - const char * ip6_privacy_str = "0"; - NMPlatform * platform; - int ifindex; + int ifindex; if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) { nm_device_sysctl_ip_conf_set(self, AF_INET6, "disable_ipv6", "1"); @@ -11241,15 +10689,12 @@ act_stage3_ip_config_start(NMDevice * self, * slave should not depend on the previous state. Flush * addresses and routes on activation. */ - ifindex = nm_device_get_ip_ifindex(self); - platform = nm_device_get_platform(self); - + ifindex = nm_device_get_ip_ifindex(self); if (ifindex > 0) { - gs_unref_object NMIP6Config *config = nm_device_ip6_config_new(self); - - nm_platform_ip_route_flush(platform, AF_INET6, ifindex); - nm_platform_ip_address_flush(platform, AF_INET6, ifindex); - nm_device_set_ip_config(self, AF_INET6, (NMIPConfig *) config, FALSE, NULL); + nm_platform_ip_route_flush(nm_device_get_platform(self), AF_INET6, ifindex); + nm_platform_ip_address_flush(nm_device_get_platform(self), + AF_INET6, + ifindex); } } else { gboolean ipv6ll_handle_old = priv->ipv6ll_handle; @@ -11271,7 +10716,7 @@ act_stage3_ip_config_start(NMDevice * self, * expose any ipv6 sysctls or allow presence of any addresses on the interface, * including LL, which * would make it impossible to autoconfigure MTU to a * correct value. */ - _commit_mtu(self, priv->ip_config_4); + _commit_mtu(self); /* Any method past this point requires an IPv6LL address. Use NM-controlled * IPv6LL if this is not an assumed connection, since assumed connections @@ -11285,33 +10730,30 @@ act_stage3_ip_config_start(NMDevice * self, set_disable_ipv6(self, "0"); /* Synchronize external IPv6 configuration with kernel, since - * linklocal6_start() uses the information there to determine if we can + * _dev_ll6_start() uses the information there to determine if we can * proceed with the selected method (SLAAC, DHCP, link-local). */ nm_platform_process_events(nm_device_get_platform(self)); - g_clear_object(&priv->ext_ip6_config_captured); - priv->ext_ip6_config_captured = - nm_ip6_config_capture(nm_device_get_multi_index(self), - nm_device_get_platform(self), - nm_device_get_ip_ifindex(self), - NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - - ip6_privacy = _prop_get_ipv6_ip6_privacy(self); + //XXX g_clear_object (&priv->ext_ip6_config_captured); + //XXX priv->ext_ip6_config_captured = nm_ip6_config_capture (nm_device_get_multi_index (self), + //XXX nm_device_get_platform (self), + //XXX nm_device_get_ip_ifindex (self), + //XXX NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); if (NM_IN_STRSET(method, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NM_SETTING_IP6_CONFIG_METHOD_SHARED)) { - if (!addrconf6_start(self, ip6_privacy)) { + if (!_dev_ac6_start(self)) { /* IPv6 might be disabled; allow IPv4 to proceed */ ret = NM_ACT_STAGE_RETURN_IP_FAIL; } else ret = NM_ACT_STAGE_RETURN_POSTPONE; } else if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) { - ret = - linklocal6_start(self) ? NM_ACT_STAGE_RETURN_SUCCESS : NM_ACT_STAGE_RETURN_POSTPONE; + ret = _dev_ll6_start(self, NULL) ? NM_ACT_STAGE_RETURN_SUCCESS + : NM_ACT_STAGE_RETURN_POSTPONE; } else if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) { priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_MANAGED; - if (!dhcp6_start(self, TRUE)) { + if (!_dev_dhcpx_start(self, AF_INET6)) { /* IPv6 might be disabled; allow IPv4 to proceed */ ret = NM_ACT_STAGE_RETURN_IP_FAIL; } else @@ -11321,23 +10763,6 @@ act_stage3_ip_config_start(NMDevice * self, else _LOGW(LOGD_IP6, "unhandled IPv6 config method '%s'; will fail", method); - if (ret != NM_ACT_STAGE_RETURN_FAILURE - && !nm_device_sys_iface_state_is_external_or_assume(self)) { - switch (ip6_privacy) { - case NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN: - case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED: - ip6_privacy_str = "0"; - break; - case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR: - ip6_privacy_str = "1"; - break; - case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR: - ip6_privacy_str = "2"; - break; - } - nm_device_sysctl_ip_conf_set(self, AF_INET6, "use_tempaddr", ip6_privacy_str); - } - return ret; } } @@ -11345,13 +10770,13 @@ act_stage3_ip_config_start(NMDevice * self, gboolean nm_device_activate_stage3_ip_start(NMDevice *self, int addr_family) { - const int IS_IPv4 = NM_IS_IPv4(addr_family); - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMActStageReturn ret; - NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - gs_unref_object NMIPConfig *ip_config = NULL; + const int IS_IPv4 = NM_IS_IPv4(addr_family); + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMActStageReturn ret; + NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; - g_assert(priv->ip_state_x[IS_IPv4] == NM_DEVICE_IP_STATE_WAIT); + g_return_val_if_fail(priv->ip_state_x[IS_IPv4] == NM_DEVICE_IP_STATE_WAIT, FALSE); if (nm_device_sys_iface_state_is_external(self)) { _set_ip_state(self, addr_family, NM_DEVICE_IP_STATE_DONE); @@ -11363,22 +10788,13 @@ nm_device_activate_stage3_ip_start(NMDevice *self, int addr_family) ret = NM_DEVICE_GET_CLASS(self)->act_stage3_ip_config_start(self, addr_family, - (gpointer *) &ip_config, + &l3cd, &failure_reason); switch (ret) { case NM_ACT_STAGE_RETURN_SUCCESS: - if (!IS_IPv4) { - /* Here we get a static IPv6 config, like for Shared where it's - * autogenerated or from modems where it comes from ModemManager. - */ - if (!ip_config) - ip_config = nm_device_ip_config_new(self, addr_family); - nm_assert(!applied_config_get_current(&priv->ac_ip6_config)); - applied_config_init(&priv->ac_ip6_config, ip_config); - ip_config = NULL; - } - nm_device_activate_schedule_ip_config_result(self, addr_family, ip_config); + _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_DEV_X(IS_IPv4), l3cd, FALSE); + nm_device_activate_schedule_ip_config_result(self, addr_family); break; case NM_ACT_STAGE_RETURN_IP_DONE: _set_ip_state(self, addr_family, NM_DEVICE_IP_STATE_DONE); @@ -11435,9 +10851,6 @@ activate_stage3_ip_config_start(NMDevice *self) && !nm_device_activate_stage3_ip_start(self, AF_INET6)) return; - /* Proxy */ - nm_device_set_proxy_config(self, NULL); - check_ip_state(self, TRUE, TRUE); } @@ -11628,8 +11041,66 @@ nm_device_activate_schedule_ip_config_timeout(NMDevice *self, int addr_family) addr_family); } +/*****************************************************************************/ + +static const NML3ConfigData * +_dev_shared4_new_l3cd(NMDevice *self, NMConnection *connection, NMPlatformIP4Address *out_addr4) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + NMSettingIPConfig * s_ip4; + NMPlatformIP4Address address = { + .addr_source = NM_IP_CONFIG_SOURCE_SHARED, + }; + + g_return_val_if_fail(self, NULL); + g_return_val_if_fail(connection, NULL); + + s_ip4 = nm_connection_get_setting_ip4_config(connection); + if (s_ip4 && nm_setting_ip_config_get_num_addresses(s_ip4) > 0) { + /* Use the first user-supplied address */ + NMIPAddress *user = nm_setting_ip_config_get_address(s_ip4, 0); + in_addr_t a; + + nm_ip_address_get_address_binary(user, &a); + nm_platform_ip4_address_set_addr(&address, a, nm_ip_address_get_prefix(user)); + nm_clear_pointer(&priv->shared4_ip_handle, nm_netns_shared_ip_release); + } else { + if (!priv->shared4_ip_handle) + priv->shared4_ip_handle = nm_netns_shared_ip_reserve(nm_device_get_netns(self)); + nm_platform_ip4_address_set_addr(&address, priv->shared4_ip_handle->addr, 24); + } + + l3cd = nm_device_create_l3_config_data(self); + nm_l3_config_data_set_source(l3cd, NM_IP_CONFIG_SOURCE_SHARED); + nm_l3_config_data_add_address_4(l3cd, &address); + + NM_SET_OUT(out_addr4, address); + + return nm_l3_config_data_seal(g_steal_pointer(&l3cd)); +} + +static void +_dev_shared4_cleanup(NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + + if (priv->shared4_dnsmasq_manager) { + nm_clear_g_signal_handler(priv->shared4_dnsmasq_manager, &priv->shared4_dnsmasq_state_id); + nm_dnsmasq_manager_stop(priv->shared4_dnsmasq_manager); + g_clear_object(&priv->shared4_dnsmasq_manager); + } + + if (priv->firewall_config) { + nm_firewall_config_apply(priv->firewall_config, FALSE); + nm_clear_pointer(&priv->firewall_config, nm_firewall_config_free); + } + + nm_clear_pointer(&priv->shared4_ip_handle, nm_netns_shared_ip_release); +} + static gboolean -share_init(NMDevice *self, GError **error) +_dev_shared4_init(NMDevice *self, GError **error) { const char *const modules[] = {"ip_tables", "iptable_nat", @@ -11684,29 +11155,37 @@ share_init(NMDevice *self, GError **error) return TRUE; } -static gboolean -start_sharing(NMDevice *self, NMIP4Config *config, GError **error) +static void +_dev_shared4_dnsmasq_state_changed_cb(NMDnsMasqManager *manager, guint status, gpointer user_data) { - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMActRequest * req; - const NMPlatformIP4Address *ip4_addr = NULL; - const char * ip_iface; - GError * local = NULL; - NMConnection * conn; - NMSettingConnection * s_con; - gboolean announce_android_metered; - NMFirewallConfig * firewall_config; - - g_return_val_if_fail(config, FALSE); + NMDevice *self = NM_DEVICE(user_data); - ip_iface = nm_device_get_ip_iface(self); - if (!ip_iface) { - g_set_error(error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "device has no ip interface"); - return FALSE; - } + if (status == NM_DNSMASQ_STATUS_DEAD) + nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_SHARED_START_FAILED); +} - ip4_addr = nm_ip4_config_get_first_address(config); - if (!ip4_addr || !ip4_addr->address) { +static gboolean +_dev_shared4_start(NMDevice *self, GError **error) +{ + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + NMPlatformIP4Address ip4_addr; + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMActRequest * req; + const char * ip_iface; + GError * local = NULL; + NMConnection * conn; + NMSettingConnection * s_con; + gboolean announce_android_metered; + NMConnection * applied; + + nm_assert(!priv->firewall_config); + nm_assert(!priv->shared4_dnsmasq_manager); + nm_assert(priv->shared4_dnsmasq_state_id == 0); + + applied = nm_device_get_applied_connection(self); + + l3cd = _dev_shared4_new_l3cd(self, applied, &ip4_addr); + if (!l3cd) { g_set_error(error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, @@ -11714,15 +11193,18 @@ start_sharing(NMDevice *self, NMIP4Config *config, GError **error) return FALSE; } - if (!share_init(self, error)) + if (!_dev_shared4_init(self, error)) return FALSE; + ip_iface = nm_device_get_ip_iface(self); + g_return_val_if_fail(ip_iface, FALSE); + req = nm_device_get_act_request(self); g_return_val_if_fail(req, FALSE); - firewall_config = nm_firewall_config_new(ip_iface, ip4_addr->address, ip4_addr->plen); + priv->firewall_config = nm_firewall_config_new(ip_iface, ip4_addr.address, ip4_addr.plen); - nm_act_request_set_shared(req, firewall_config); + nm_firewall_config_apply(priv->firewall_config, TRUE); conn = nm_act_request_get_applied_connection(req); s_con = nm_connection_get_setting_connection(conn); @@ -11747,8 +11229,10 @@ start_sharing(NMDevice *self, NMIP4Config *config, GError **error) break; } - if (!nm_dnsmasq_manager_start(priv->dnsmasq_manager, - config, + priv->shared4_dnsmasq_manager = nm_dnsmasq_manager_new(nm_device_get_ip_iface(self)); + + if (!nm_dnsmasq_manager_start(priv->shared4_dnsmasq_manager, + l3cd, announce_android_metered, &local)) { g_set_error(error, @@ -11756,81 +11240,29 @@ start_sharing(NMDevice *self, NMIP4Config *config, GError **error) NM_UTILS_ERROR_UNKNOWN, "could not start dnsmasq due to %s", local->message); - g_error_free(local); - nm_act_request_set_shared(req, NULL); + g_clear_error(&local); + _dev_shared4_cleanup(self); return FALSE; } - priv->dnsmasq_state_id = g_signal_connect(priv->dnsmasq_manager, - NM_DNS_MASQ_MANAGER_STATE_CHANGED, - G_CALLBACK(dnsmasq_state_changed_cb), - self); - return TRUE; -} - -static void -arp_cleanup(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - nm_clear_pointer(&priv->acd.announcing, nm_acd_manager_free); -} - -void -nm_device_arp_announce(NMDevice *self) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMConnection * connection; - NMSettingIPConfig *s_ip4; - guint num, i; - const guint8 * hw_addr; - size_t hw_addr_len = 0; - - arp_cleanup(self); - - hw_addr = nm_platform_link_get_address(nm_device_get_platform(self), - nm_device_get_ip_ifindex(self), - &hw_addr_len); - - if (!hw_addr || hw_addr_len != ETH_ALEN) - return; - - /* We only care about manually-configured addresses; DHCP- and autoip-configured - * ones should already have been seen on the network at this point. - */ - connection = nm_device_get_applied_connection(self); - if (!connection) - return; - s_ip4 = nm_connection_get_setting_ip4_config(connection); - if (!s_ip4) - return; - num = nm_setting_ip_config_get_num_addresses(s_ip4); - if (num == 0) - return; - - priv->acd.announcing = - nm_acd_manager_new(nm_device_get_ip_ifindex(self), hw_addr, hw_addr_len, NULL, NULL); - - for (i = 0; i < num; i++) { - NMIPAddress *ip = nm_setting_ip_config_get_address(s_ip4, i); - in_addr_t addr; + priv->shared4_dnsmasq_state_id = + g_signal_connect(priv->shared4_dnsmasq_manager, + NM_DNS_MASQ_MANAGER_STATE_CHANGED, + G_CALLBACK(_dev_shared4_dnsmasq_state_changed_cb), + self); - if (inet_pton(AF_INET, nm_ip_address_get_address(ip), &addr) == 1) - nm_acd_manager_add_address(priv->acd.announcing, addr); - else - g_warn_if_reached(); - } + _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_SHARED_4, l3cd, FALSE); - nm_acd_manager_announce_addresses(priv->acd.announcing); + return TRUE; } static void activate_stage5_ip_config_result_x(NMDevice *self, int addr_family) { +#if 0 //XXX const int IS_IPv4 = NM_IS_IPv4(addr_family); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); NMActRequest * req; - const char * method; int ip_ifindex; int errsv; gboolean do_announce = FALSE; @@ -11991,6 +11423,7 @@ activate_stage5_ip_config_result_x(NMDevice *self, int addr_family) _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_DONE); check_ip_state(self, FALSE, TRUE); } +#endif } static void @@ -12010,18 +11443,18 @@ activate_stage5_ip_config_result_6(NMDevice *self) : activate_stage5_ip_config_result_6) void -nm_device_activate_schedule_ip_config_result(NMDevice *self, int addr_family, NMIPConfig *config) +nm_device_activate_schedule_ip_config_result(NMDevice *self, int addr_family) { NMDevicePrivate *priv; const int IS_IPv4 = NM_IS_IPv4(addr_family); g_return_if_fail(NM_IS_DEVICE(self)); - g_return_if_fail(!config || (IS_IPv4 && nm_ip_config_get_addr_family(config) == AF_INET)); + g_return_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6)); priv = NM_DEVICE_GET_PRIVATE(self); if (IS_IPv4) { - applied_config_init(&priv->dev_ip_config_4, config); + /* FIXME(l3cfg): surely there is something to do here? */ } else { /* If IP had previously failed, move it back to NM_DEVICE_IP_STATE_CONF since we * clearly now have configuration. @@ -12046,73 +11479,6 @@ nm_device_activate_get_ip_state(NMDevice *self, int addr_family) return NM_DEVICE_GET_PRIVATE(self)->ip_state_x[IS_IPv4]; } -static void -dad6_add_pending_address(NMDevice * self, - NMPlatform * platform, - int ifindex, - const struct in6_addr *address, - NMIP6Config ** dad6_config) -{ - const NMPlatformIP6Address *pl_addr; - - pl_addr = nm_platform_ip6_address_get(platform, ifindex, address); - if (pl_addr && NM_FLAGS_HAS(pl_addr->n_ifa_flags, IFA_F_TENTATIVE) - && !NM_FLAGS_HAS(pl_addr->n_ifa_flags, IFA_F_DADFAILED) - && !NM_FLAGS_HAS(pl_addr->n_ifa_flags, IFA_F_OPTIMISTIC)) { - _LOGt(LOGD_DEVICE, - "IPv6 DAD: pending address %s", - nm_platform_ip6_address_to_string(pl_addr, NULL, 0)); - - if (!*dad6_config) - *dad6_config = nm_device_ip6_config_new(self); - - nm_ip6_config_add_address(*dad6_config, pl_addr); - } -} - -/* - * Returns a NMIP6Config containing NM-configured addresses which - * have the tentative flag, or NULL if none is present. - */ -static NMIP6Config * -dad6_get_pending_addresses(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMIP6Config * confs[] = {(NMIP6Config *) applied_config_get_current(&priv->ac_ip6_config), - (NMIP6Config *) applied_config_get_current(&priv->dhcp6.ip6_config), - priv->con_ip_config_6, - (NMIP6Config *) applied_config_get_current(&priv->dev2_ip_config_6)}; - const NMPlatformIP6Address *addr; - NMIP6Config * dad6_config = NULL; - NMDedupMultiIter ipconf_iter; - guint i; - int ifindex; - NMPlatform * platform; - - ifindex = nm_device_get_ip_ifindex(self); - g_return_val_if_fail(ifindex > 0, NULL); - - platform = nm_device_get_platform(self); - - if (priv->ipv6ll_has) { - dad6_add_pending_address(self, platform, ifindex, &priv->ipv6ll_addr, &dad6_config); - } - - /* We are interested only in addresses that we have explicitly configured, - * not in externally added ones. - */ - for (i = 0; i < G_N_ELEMENTS(confs); i++) { - if (!confs[i]) - continue; - - nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, confs[i], &addr) { - dad6_add_pending_address(self, platform, ifindex, &addr->address, &dad6_config); - } - } - - return dad6_config; -} - /*****************************************************************************/ static void @@ -12151,21 +11517,6 @@ act_request_set(NMDevice *self, NMActRequest *act_request) } } -static void -dnsmasq_cleanup(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (!priv->dnsmasq_manager) - return; - - nm_clear_g_signal_handler(priv->dnsmasq_manager, &priv->dnsmasq_state_id); - - nm_dnsmasq_manager_stop(priv->dnsmasq_manager); - g_object_unref(priv->dnsmasq_manager); - priv->dnsmasq_manager = NULL; -} - gboolean nm_device_is_nm_owned(NMDevice *self) { @@ -12257,26 +11608,14 @@ _cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type) _set_ip_state(self, addr_family, NM_DEVICE_IP_STATE_NONE); - if (nm_clear_g_source(&priv->queued_ip_config_id_x[IS_IPv4])) { - _LOGD(LOGD_DEVICE, - "clearing queued IP%c config change", - nm_utils_addr_family_to_char(addr_family)); - } + _dev_dhcpx_cleanup(self, addr_family, TRUE, FALSE); if (IS_IPv4) { - dhcp4_cleanup(self, cleanup_type, FALSE); - arp_cleanup(self); - dnsmasq_cleanup(self); - ipv4ll_cleanup(self); - g_slist_free_full(priv->acd.dad_list, (GDestroyNotify) nm_acd_manager_free); - priv->acd.dad_list = NULL; + _dev_shared4_cleanup(self); + _dev_ll4_cleanup(self); } else { - g_slist_free_full(priv->dad6_failed_addrs, (GDestroyNotify) nmp_object_unref); - priv->dad6_failed_addrs = NULL; - g_clear_object(&priv->dad6_ip6_config); - dhcp6_cleanup(self, cleanup_type, FALSE); nm_clear_g_source(&priv->linklocal6_timeout_id); - addrconf6_cleanup(self); + _dev_ac6_cleanup(self); } } @@ -12366,37 +11705,6 @@ nm_device_reactivate_ip_config(NMDevice * self, if (priv->ip_state_x[IS_IPv4] == NM_DEVICE_IP_STATE_NONE) return; - g_clear_object(&priv->con_ip_config_x[IS_IPv4]); - g_clear_object(&priv->ext_ip_config_x[IS_IPv4]); - if (IS_IPv4) { - g_clear_object(&priv->dev_ip_config_4.current); - } else { - g_clear_object(&priv->ac_ip6_config.current); - g_clear_object(&priv->dhcp6.ip6_config.current); - } - g_clear_object(&priv->dev2_ip_config_x[IS_IPv4].current); - - if (!IS_IPv4) { - if (priv->ipv6ll_handle && !IN6_IS_ADDR_UNSPECIFIED(&priv->ipv6ll_addr)) - priv->ipv6ll_has = TRUE; - } - - priv->con_ip_config_x[IS_IPv4] = nm_device_ip_config_new(self, addr_family); - - if (IS_IPv4) { - nm_ip4_config_merge_setting(priv->con_ip_config_4, - s_ip_new, - _prop_get_connection_mdns(self), - _prop_get_connection_llmnr(self), - nm_device_get_route_table(self, AF_INET), - nm_device_get_route_metric(self, AF_INET)); - } else { - nm_ip6_config_merge_setting(priv->con_ip_config_6, - s_ip_new, - nm_device_get_route_table(self, AF_INET6), - nm_device_get_route_metric(self, AF_INET6)); - } - method_old = (s_ip_old ? nm_setting_ip_config_get_method(s_ip_old) : NULL) ?: (IS_IPv4 ? NM_SETTING_IP4_CONFIG_METHOD_DISABLED : NM_SETTING_IP6_CONFIG_METHOD_IGNORE); @@ -12415,58 +11723,7 @@ nm_device_reactivate_ip_config(NMDevice * self, return; } - if (s_ip_old && s_ip_new) { - gint64 metric_old, metric_new; - - /* For dynamic IP methods (DHCP, IPv4LL, WWAN) the route metric is - * set at activation/renewal time using the value from static - * configuration. To support runtime change we need to update the - * dynamic configuration in place and tell the DHCP client the new - * value to use for future renewals. - */ - metric_old = nm_setting_ip_config_get_route_metric(s_ip_old); - metric_new = nm_setting_ip_config_get_route_metric(s_ip_new); - - if (metric_old != metric_new) { - if (IS_IPv4) { - if (priv->dev_ip_config_4.orig) { - nm_ip4_config_update_routes_metric((NMIP4Config *) priv->dev_ip_config_4.orig, - nm_device_get_route_metric(self, AF_INET)); - } - if (priv->dev2_ip_config_4.orig) { - nm_ip4_config_update_routes_metric((NMIP4Config *) priv->dev2_ip_config_4.orig, - nm_device_get_route_metric(self, AF_INET)); - } - if (priv->dhcp_data_4.client) { - nm_dhcp_client_set_route_metric(priv->dhcp_data_4.client, - nm_device_get_route_metric(self, AF_INET)); - } - } else { - if (priv->ac_ip6_config.orig) { - nm_ip6_config_update_routes_metric((NMIP6Config *) priv->ac_ip6_config.orig, - nm_device_get_route_metric(self, AF_INET6)); - } - if (priv->dhcp6.ip6_config.orig) { - nm_ip6_config_update_routes_metric((NMIP6Config *) priv->dhcp6.ip6_config.orig, - nm_device_get_route_metric(self, AF_INET6)); - } - if (priv->dev2_ip_config_6.orig) { - nm_ip6_config_update_routes_metric((NMIP6Config *) priv->dev2_ip_config_6.orig, - nm_device_get_route_metric(self, AF_INET6)); - } - if (priv->dhcp_data_6.client) { - nm_dhcp_client_set_route_metric(priv->dhcp_data_6.client, - nm_device_get_route_metric(self, AF_INET6)); - } - } - } - } - - if (nm_device_get_ip_ifindex(self) > 0 && !ip_config_merge_and_apply(self, addr_family, TRUE)) { - _LOGW(LOGD_IPX(IS_IPv4), - "Failed to reapply IPv%c configuration", - nm_utils_addr_family_to_char(addr_family)); - } + _dev_l3_cfg_commit(self, TRUE); } static void @@ -12476,11 +11733,11 @@ _pacrunner_manager_add(NMDevice *self) nm_pacrunner_manager_remove_clear(&priv->pacrunner_conf_id); - priv->pacrunner_conf_id = nm_pacrunner_manager_add(nm_pacrunner_manager_get(), - priv->proxy_config, - nm_device_get_ip_iface(self), - NULL, - NULL); + //XXX priv->pacrunner_conf_id = nm_pacrunner_manager_add(nm_pacrunner_manager_get(), + //XXX priv->proxy_config, + //XXX nm_device_get_ip_iface(self), + //XXX NULL, + //XXX NULL); } static void @@ -12490,7 +11747,6 @@ reactivate_proxy_config(NMDevice *self) if (!priv->pacrunner_conf_id) return; - nm_device_set_proxy_config(self, priv->dhcp4.pac_url); _pacrunner_manager_add(self); } @@ -12711,6 +11967,7 @@ check_and_reapply_connection(NMDevice * self, priv->v4_route_table_initialized = FALSE; priv->v6_route_table_initialized = FALSE; + priv->l3config_merge_flags_has = FALSE; /************************************************************************** * Reapply changes @@ -12970,96 +12227,6 @@ impl_device_get_applied_connection(NMDBusObject * obj, /*****************************************************************************/ -typedef struct { - gint64 timestamp_ms; - bool dirty; -} IP6RoutesTemporaryNotAvailableData; - -static gboolean -_rt6_temporary_not_available_timeout(gpointer user_data) -{ - NMDevice * self = NM_DEVICE(user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - priv->rt6_temporary_not_available_id = 0; - nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); - - return G_SOURCE_REMOVE; -} - -static gboolean -_rt6_temporary_not_available_set(NMDevice *self, GPtrArray *temporary_not_available) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - IP6RoutesTemporaryNotAvailableData *data; - GHashTableIter iter; - gint64 now_ms, oldest_ms; - const gint64 MAX_AGE_MS = 20000; - guint i; - gboolean success = TRUE; - - if (!temporary_not_available || !temporary_not_available->len) { - /* nothing outstanding. Clear tracking the routes. */ - nm_clear_pointer(&priv->rt6_temporary_not_available, g_hash_table_unref); - nm_clear_g_source(&priv->rt6_temporary_not_available_id); - return success; - } - - if (priv->rt6_temporary_not_available) { - g_hash_table_iter_init(&iter, priv->rt6_temporary_not_available); - while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &data)) - data->dirty = TRUE; - } else { - priv->rt6_temporary_not_available = - g_hash_table_new_full((GHashFunc) nmp_object_id_hash, - (GEqualFunc) nmp_object_id_equal, - (GDestroyNotify) nmp_object_unref, - nm_g_slice_free_fcn(IP6RoutesTemporaryNotAvailableData)); - } - - now_ms = nm_utils_get_monotonic_timestamp_msec(); - oldest_ms = now_ms; - - for (i = 0; i < temporary_not_available->len; i++) { - const NMPObject *o = temporary_not_available->pdata[i]; - - data = g_hash_table_lookup(priv->rt6_temporary_not_available, o); - if (data) { - if (!data->dirty) - continue; - data->dirty = FALSE; - nm_assert(data->timestamp_ms > 0 && data->timestamp_ms <= now_ms); - if (now_ms > data->timestamp_ms + MAX_AGE_MS) { - /* timeout. Could not add this address. */ - _LOGW(LOGD_DEVICE, - "failure to add IPv6 route: %s", - nmp_object_to_string(o, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - success = FALSE; - } else - oldest_ms = MIN(data->timestamp_ms, oldest_ms); - continue; - } - - data = g_slice_new0(IP6RoutesTemporaryNotAvailableData); - data->timestamp_ms = now_ms; - g_hash_table_insert(priv->rt6_temporary_not_available, (gpointer) nmp_object_ref(o), data); - } - - g_hash_table_iter_init(&iter, priv->rt6_temporary_not_available); - while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &data)) { - if (data->dirty) - g_hash_table_iter_remove(&iter); - } - - nm_clear_g_source(&priv->rt6_temporary_not_available_id); - priv->rt6_temporary_not_available_id = - g_timeout_add(oldest_ms + MAX_AGE_MS - now_ms, _rt6_temporary_not_available_timeout, self); - - return success; -} - -/*****************************************************************************/ - static void disconnect_cb(NMDevice * self, GDBusMethodInvocation *context, @@ -13412,345 +12579,83 @@ nm_device_queue_activation(NMDevice *self, NMActRequest *req) _LOGI(LOGD_DEVICE, "disconnecting for new activation request."); nm_device_state_changed(self, NM_DEVICE_STATE_DEACTIVATING, - NM_DEVICE_STATE_REASON_NEW_ACTIVATION); - } -} - -/* - * nm_device_is_activating - * - * Return whether or not the device is currently activating itself. - * - */ -gboolean -nm_device_is_activating(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMDeviceState state; - - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - - state = nm_device_get_state(self); - if (state >= NM_DEVICE_STATE_PREPARE && state <= NM_DEVICE_STATE_SECONDARIES) - return TRUE; - - /* There's a small race between the time when stage 1 is scheduled - * and when the device actually sets STATE_PREPARE when the activation - * handler is actually run. If there's an activation handler scheduled - * we're activating anyway. - */ - return priv->activation_source_id_4 != 0; -} - -NMProxyConfig * -nm_device_get_proxy_config(NMDevice *self) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - - return NM_DEVICE_GET_PRIVATE(self)->proxy_config; -} - -static void -nm_device_set_proxy_config(NMDevice *self, const char *pac_url) -{ - NMDevicePrivate *priv; - NMConnection * connection; - NMSettingProxy * s_proxy = NULL; - - g_return_if_fail(NM_IS_DEVICE(self)); - - priv = NM_DEVICE_GET_PRIVATE(self); - - g_clear_object(&priv->proxy_config); - priv->proxy_config = nm_proxy_config_new(); - - if (pac_url) { - nm_proxy_config_set_method(priv->proxy_config, NM_PROXY_CONFIG_METHOD_AUTO); - nm_proxy_config_set_pac_url(priv->proxy_config, pac_url); - _LOGD(LOGD_PROXY, "proxy: PAC url \"%s\"", pac_url); - } else - nm_proxy_config_set_method(priv->proxy_config, NM_PROXY_CONFIG_METHOD_NONE); - - connection = nm_device_get_applied_connection(self); - if (connection) - s_proxy = nm_connection_get_setting_proxy(connection); - - if (s_proxy) - nm_proxy_config_merge_setting(priv->proxy_config, s_proxy); -} - -/* IP Configuration stuff */ -NMDhcpConfig * -nm_device_get_dhcp_config(NMDevice *self, int addr_family) -{ - const int IS_IPv4 = NM_IS_IPv4(addr_family); - - g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - - nm_assert_addr_family(addr_family); - - return NM_DEVICE_GET_PRIVATE(self)->dhcp_data_x[IS_IPv4].config; -} - -NMIP4Config * -nm_device_get_ip4_config(NMDevice *self) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - - return NM_DEVICE_GET_PRIVATE(self)->ip_config_4; -} - -static gboolean -nm_device_set_ip_config(NMDevice * self, - int addr_family, - NMIPConfig *new_config, - 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; - 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); - nm_assert(!new_config - || (new_config && ({ - int ip_ifindex = nm_device_get_ip_ifindex(self); - - (ip_ifindex > 0 && ip_ifindex == nm_ip_config_get_ifindex(new_config)); - }))); - 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=" NM_HASH_OBFUSCATE_PTR_FMT - ", route-table-sync-mode=%d)", - nm_utils_addr_family_to_char(addr_family), - commit, - NM_HASH_OBFUSCATE_PTR(new_config), - (int) route_table_sync_mode); - - /* Always commit to nm-platform to update lifetimes */ - if (commit && new_config) { - _commit_mtu(self, IS_IPv4 ? NM_IP4_CONFIG(new_config) : priv->ip_config_4); - - if (IS_IPv4) { - success = nm_ip4_config_commit(NM_IP4_CONFIG(new_config), - nm_device_get_platform(self), - 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); - } else { - gs_unref_ptrarray GPtrArray *temporary_not_available = NULL; - - success = nm_ip6_config_commit(NM_IP6_CONFIG(new_config), - nm_device_get_platform(self), - route_table_sync_mode, - &temporary_not_available); - - if (!_rt6_temporary_not_available_set(self, temporary_not_available)) - success = FALSE; - } - } - - old_config = priv->ip_config_x[IS_IPv4]; - - if (new_config && old_config) { - /* has_changes is set only on relevant changes, because when the configuration changes, - * this causes a re-read and reset. This should only happen for relevant changes */ - nm_ip_config_replace(old_config, new_config, &has_changes); - if (has_changes) { - _LOGD(LOGD_IPX(IS_IPv4), - "ip%c-config: update IP Config instance (%s)", - nm_utils_addr_family_to_char(addr_family), - nm_dbus_object_get_path(NM_DBUS_OBJECT(old_config))); - } - } else if (new_config /*&& !old_config*/) { - has_changes = TRUE; - priv->ip_config_x[IS_IPv4] = g_object_ref(new_config); - if (!nm_dbus_object_is_exported(NM_DBUS_OBJECT(new_config))) - nm_dbus_object_export(NM_DBUS_OBJECT(new_config)); - - _LOGD(LOGD_IPX(IS_IPv4), - "ip%c-config: set IP Config instance (%s)", - nm_utils_addr_family_to_char(addr_family), - nm_dbus_object_get_path(NM_DBUS_OBJECT(new_config))); - } else if (old_config /*&& !new_config*/) { - has_changes = TRUE; - priv->ip_config_x[IS_IPv4] = NULL; - _LOGD(LOGD_IPX(IS_IPv4), - "ip%c-config: clear IP Config instance (%s)", - nm_utils_addr_family_to_char(addr_family), - nm_dbus_object_get_path(NM_DBUS_OBJECT(old_config))); - if (IS_IPv4) { - /* Device config is invalid if combined config is invalid */ - applied_config_clear(&priv->dev_ip_config_4); - } else - priv->needs_ip6_subnet = FALSE; - } - - if (has_changes) { - if (old_config != priv->ip_config_x[IS_IPv4]) - _notify(self, IS_IPv4 ? PROP_IP4_CONFIG : PROP_IP6_CONFIG); - - g_signal_emit(self, - signals[IS_IPv4 ? IP4_CONFIG_CHANGED : IP6_CONFIG_CHANGED], - 0, - priv->ip_config_x[IS_IPv4], - old_config); - - if (old_config != priv->ip_config_x[IS_IPv4]) - nm_dbus_object_clear_and_unexport(&old_config); - - if (nm_device_sys_iface_state_is_external(self) - && (settings_connection = nm_device_get_settings_connection(self)) - && NM_FLAGS_HAS(nm_settings_connection_get_flags(settings_connection), - NM_SETTINGS_CONNECTION_INT_FLAGS_EXTERNAL) - && nm_active_connection_get_activation_type(NM_ACTIVE_CONNECTION(priv->act_request.obj)) - == NM_ACTIVATION_TYPE_EXTERNAL) { - gs_unref_object NMConnection *new_connection = NULL; - - new_connection = nm_simple_connection_new_clone( - nm_settings_connection_get_connection(settings_connection)); - - nm_connection_add_setting( - new_connection, - IS_IPv4 ? nm_ip4_config_create_setting(priv->ip_config_4) - : nm_ip6_config_create_setting(priv->ip_config_6, - _get_maybe_ipv6_disabled(self))); - - nm_settings_connection_update(settings_connection, - new_connection, - NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY, - NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, - NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, - NM_SETTINGS_CONNECTION_UPDATE_REASON_UPDATE_NON_SECRET, - "update-external", - NULL); - } - - nm_device_queue_recheck_assume(self); - - if (!IS_IPv4) { - if (priv->ndisc) - ndisc_set_router_config(priv->ndisc, self); - } - } - - nm_assert(!old_config || old_config == priv->ip_config_x[IS_IPv4]); - - return success; -} - -static gboolean -_replace_vpn_config_in_list(GSList **plist, GObject *old, GObject *new) -{ - GSList *old_link; - - /* Below, assert that @new is not yet tracked, but still behave - * correctly in any case. Don't complain for missing @old since - * it could have been removed when the parent device became - * unmanaged. */ - - if (old && (old_link = g_slist_find(*plist, old))) { - if (old != new) { - if (new) - old_link->data = g_object_ref(new); - else - *plist = g_slist_delete_link(*plist, old_link); - g_object_unref(old); - } - return TRUE; - } - - if (new) { - if (!g_slist_find(*plist, new)) - *plist = g_slist_append(*plist, g_object_ref(new)); - else - g_return_val_if_reached(TRUE); - return TRUE; + NM_DEVICE_STATE_REASON_NEW_ACTIVATION); } - - return FALSE; } -void -nm_device_replace_vpn4_config(NMDevice *self, NMIP4Config *old, NMIP4Config *config) +/* + * nm_device_is_activating + * + * Return whether or not the device is currently activating itself. + * + */ +gboolean +nm_device_is_activating(NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMDeviceState state; - nm_assert(!old || NM_IS_IP4_CONFIG(old)); - nm_assert(!config || NM_IS_IP4_CONFIG(config)); - nm_assert(!old || nm_ip4_config_get_ifindex(old) == nm_device_get_ip_ifindex(self)); - nm_assert(!config || nm_ip4_config_get_ifindex(config) == nm_device_get_ip_ifindex(self)); + g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - if (!_replace_vpn_config_in_list(&priv->vpn_configs_4, (GObject *) old, (GObject *) config)) - return; + state = nm_device_get_state(self); + if (state >= NM_DEVICE_STATE_PREPARE && state <= NM_DEVICE_STATE_SECONDARIES) + return TRUE; - /* NULL to use existing configs */ - if (!ip_config_merge_and_apply(self, AF_INET, TRUE)) - _LOGW(LOGD_IP4, "failed to set VPN routes for device"); + /* There's a small race between the time when stage 1 is scheduled + * and when the device actually sets STATE_PREPARE when the activation + * handler is actually run. If there's an activation handler scheduled + * we're activating anyway. + */ + return priv->activation_source_id_4 != 0; } -void -nm_device_set_dev2_ip_config(NMDevice *self, int addr_family, NMIPConfig *config) +NMDhcpConfig * +nm_device_get_dhcp_config(NMDevice *self, int addr_family) { - NMDevicePrivate *priv; - const int IS_IPv4 = NM_IS_IPv4(addr_family); + g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - g_return_if_fail(NM_IS_DEVICE(self)); - g_return_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6)); - g_return_if_fail(!config || nm_ip_config_get_addr_family(config) == addr_family); + return NM_DEVICE_GET_PRIVATE(self)->dhcp_data_x[NM_IS_IPv4(addr_family)].config; +} - priv = NM_DEVICE_GET_PRIVATE(self); +const NML3Cfg * +nm_device_get_l3cfg(NMDevice *self) +{ + g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - applied_config_init(&priv->dev2_ip_config_x[IS_IPv4], config); - if (!ip_config_merge_and_apply(self, addr_family, TRUE)) { - _LOGW(LOGD_IP, - "failed to set extra device IPv%c configuration", - nm_utils_addr_family_to_char(addr_family)); - } + return NM_DEVICE_GET_PRIVATE(self)->l3cfg; } -void -nm_device_replace_vpn6_config(NMDevice *self, NMIP6Config *old, NMIP6Config *config) +const NML3ConfigData * +nm_device_get_l3cd(NMDevice *self, gboolean get_commited) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMDevicePrivate *priv; - nm_assert(!old || NM_IS_IP6_CONFIG(old)); - nm_assert(!config || NM_IS_IP6_CONFIG(config)); - nm_assert(!old || nm_ip6_config_get_ifindex(old) == nm_device_get_ip_ifindex(self)); - nm_assert(!config || nm_ip6_config_get_ifindex(config) == nm_device_get_ip_ifindex(self)); + g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - if (!_replace_vpn_config_in_list(&priv->vpn_configs_6, (GObject *) old, (GObject *) config)) - return; + priv = NM_DEVICE_GET_PRIVATE(self); + + if (!priv->l3cfg) + return NULL; - /* NULL to use existing configs */ - if (!ip_config_merge_and_apply(self, AF_INET6, TRUE)) - _LOGW(LOGD_IP6, "failed to set VPN routes for device"); + return nm_l3cfg_get_combined_l3cd(priv->l3cfg, get_commited); } -NMIP6Config * -nm_device_get_ip6_config(NMDevice *self) +void +nm_device_set_dev2_ip_config(NMDevice *self, int addr_family, const NML3ConfigData *l3cd) { - g_return_val_if_fail(NM_IS_DEVICE(self), NULL); + const int IS_IPv4 = NM_IS_IPv4(addr_family); - return NM_DEVICE_GET_PRIVATE(self)->ip_config_6; + _dev_l3_register_l3cds_set_one(self, + IS_IPv4 ? L3_CONFIG_DATA_TYPE_DEV_4 : L3_CONFIG_DATA_TYPE_DEV_6, + l3cd, + FALSE); + _dev_l3_cfg_commit(self, TRUE); } /*****************************************************************************/ static gboolean -dispatcher_cleanup(NMDevice *self) +_dispatcher_cleanup(NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); @@ -13764,7 +12669,7 @@ dispatcher_cleanup(NMDevice *self) } static void -dispatcher_complete_proceed_state(NMDispatcherCallId *call_id, gpointer user_data) +_dispatcher_complete_proceed_state(NMDispatcherCallId *call_id, gpointer user_data) { NMDevice * self = NM_DEVICE(user_data); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); @@ -13784,7 +12689,7 @@ ip_check_pre_up(NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - if (dispatcher_cleanup(self)) + if (_dispatcher_cleanup(self)) nm_assert_not_reached(); priv->dispatcher.post_state = NM_DEVICE_STATE_SECONDARIES; @@ -13792,11 +12697,11 @@ ip_check_pre_up(NMDevice *self) if (!nm_dispatcher_call_device(NM_DISPATCHER_ACTION_PRE_UP, self, NULL, - dispatcher_complete_proceed_state, + _dispatcher_complete_proceed_state, self, &priv->dispatcher.call_id)) { /* Just proceed on errors */ - dispatcher_complete_proceed_state(0, self); + _dispatcher_complete_proceed_state(0, self); } } @@ -13988,17 +12893,21 @@ nm_device_start_ip_check(NMDevice *self) buf[0] = '\0'; if (timeout) { - const NMPObject *gw; + const NMPObject * gw; + const NML3ConfigData *l3cd; - if (priv->ip_config_4 && priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE) { - gw = nm_ip4_config_best_default_route_get(priv->ip_config_4); + l3cd = priv->l3cfg ? nm_l3cfg_get_combined_l3cd(priv->l3cfg, TRUE) : NULL; + if (!l3cd) { + /* pass */ + } else if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE) { + gw = nm_l3_config_data_get_best_default_route(l3cd, AF_INET); if (gw) { _nm_utils_inet4_ntop(NMP_OBJECT_CAST_IP4_ROUTE(gw)->gateway, buf); ping_binary = nm_utils_find_helper("ping", "/usr/bin/ping", NULL); log_domain = LOGD_IP4; } - } else if (priv->ip_config_6 && priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) { - gw = nm_ip6_config_best_default_route_get(priv->ip_config_6); + } else if (priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) { + gw = nm_l3_config_data_get_best_default_route(l3cd, AF_INET6); if (gw) { _nm_utils_inet6_ntop(&NMP_OBJECT_CAST_IP6_ROUTE(gw)->gateway, buf); ping_binary = nm_utils_find_helper("ping6", "/usr/bin/ping6", NULL); @@ -14137,15 +13046,7 @@ nm_device_bring_up(NMDevice *self, gboolean block, gboolean *no_firmware) /* Can only get HW address of some devices when they are up */ nm_device_update_hw_address(self); - /* when the link comes up, we must restore IP configuration if necessary. */ - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE) { - if (!ip_config_merge_and_apply(self, AF_INET, TRUE)) - _LOGW(LOGD_IP4, "failed applying IP4 config after bringing link up"); - } - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) { - if (!ip_config_merge_and_apply(self, AF_INET6, TRUE)) - _LOGW(LOGD_IP6, "failed applying IP6 config after bringing link up"); - } + _dev_l3_cfg_commit(self, TRUE); return TRUE; } @@ -14208,381 +13109,6 @@ nm_device_get_firmware_missing(NMDevice *self) return NM_DEVICE_GET_PRIVATE(self)->firmware_missing; } -static void -intersect_ext_config(NMDevice * self, - AppliedConfig *config, - gboolean intersect_addresses, - gboolean intersect_routes) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMIPConfig * ext; - guint32 penalty; - int family; - - if (!config->orig) - return; - - family = nm_ip_config_get_addr_family(config->orig); - penalty = default_route_metric_penalty_get(self, family); - ext = family == AF_INET ? (NMIPConfig *) priv->ext_ip_config_4 - : (NMIPConfig *) priv->ext_ip_config_6; - - if (config->current) { - nm_ip_config_intersect(config->current, - ext, - intersect_addresses, - intersect_routes, - penalty); - } else { - config->current = nm_ip_config_intersect_alloc(config->orig, - ext, - intersect_addresses, - intersect_routes, - penalty); - } -} - -static gboolean -update_ext_ip_config(NMDevice *self, int addr_family, gboolean intersect_configs) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - int ifindex; - GSList * iter; - gboolean is_up; - - nm_assert_addr_family(addr_family); - - ifindex = nm_device_get_ip_ifindex(self); - if (!ifindex) - return FALSE; - - is_up = nm_platform_link_is_up(nm_device_get_platform(self), ifindex); - - if (NM_IS_IPv4(addr_family)) { - g_clear_object(&priv->ext_ip_config_4); - priv->ext_ip_config_4 = nm_ip4_config_capture(nm_device_get_multi_index(self), - nm_device_get_platform(self), - ifindex); - if (priv->ext_ip_config_4) { - if (intersect_configs) { - /* This function was called upon external changes. Remove the configuration - * (addresses,routes) that is no longer present externally from the internal - * config. This way, we don't re-add addresses that were manually removed - * by the user. */ - if (priv->con_ip_config_4) { - nm_ip4_config_intersect(priv->con_ip_config_4, - priv->ext_ip_config_4, - TRUE, - is_up, - default_route_metric_penalty_get(self, AF_INET)); - } - - intersect_ext_config(self, &priv->dev_ip_config_4, TRUE, is_up); - intersect_ext_config(self, &priv->dev2_ip_config_4, TRUE, is_up); - - for (iter = priv->vpn_configs_4; iter; iter = iter->next) - nm_ip4_config_intersect(iter->data, priv->ext_ip_config_4, TRUE, is_up, 0); - } - - /* Remove parts from ext_ip_config_4 to only contain the information that - * was configured externally -- we already have the same configuration from - * internal origins. */ - if (priv->con_ip_config_4) { - nm_ip4_config_subtract(priv->ext_ip_config_4, - priv->con_ip_config_4, - default_route_metric_penalty_get(self, AF_INET)); - } - if (applied_config_get_current(&priv->dev_ip_config_4)) { - nm_ip_config_subtract((NMIPConfig *) priv->ext_ip_config_4, - applied_config_get_current(&priv->dev_ip_config_4), - default_route_metric_penalty_get(self, AF_INET)); - } - if (applied_config_get_current(&priv->dev2_ip_config_4)) { - nm_ip_config_subtract((NMIPConfig *) priv->ext_ip_config_4, - applied_config_get_current(&priv->dev2_ip_config_4), - default_route_metric_penalty_get(self, AF_INET)); - } - for (iter = priv->vpn_configs_4; iter; iter = iter->next) - nm_ip4_config_subtract(priv->ext_ip_config_4, iter->data, 0); - } - - } else { - nm_assert(!NM_IS_IPv4(addr_family)); - - g_clear_object(&priv->ext_ip_config_6); - g_clear_object(&priv->ext_ip6_config_captured); - priv->ext_ip6_config_captured = - nm_ip6_config_capture(nm_device_get_multi_index(self), - nm_device_get_platform(self), - ifindex, - NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - if (priv->ext_ip6_config_captured) { - priv->ext_ip_config_6 = nm_ip6_config_new_cloned(priv->ext_ip6_config_captured); - - if (intersect_configs) { - /* This function was called upon external changes. Remove the configuration - * (addresses,routes) that is no longer present externally from the internal - * config. This way, we don't re-add addresses that were manually removed - * by the user. */ - if (priv->con_ip_config_6) { - nm_ip6_config_intersect(priv->con_ip_config_6, - priv->ext_ip_config_6, - is_up, - is_up, - default_route_metric_penalty_get(self, AF_INET6)); - } - - intersect_ext_config(self, &priv->ac_ip6_config, is_up, is_up); - intersect_ext_config(self, &priv->dhcp6.ip6_config, is_up, is_up); - intersect_ext_config(self, &priv->dev2_ip_config_6, is_up, is_up); - - for (iter = priv->vpn_configs_6; iter; iter = iter->next) - nm_ip6_config_intersect(iter->data, priv->ext_ip_config_6, is_up, is_up, 0); - - if (is_up && priv->ipv6ll_has - && !nm_ip6_config_lookup_address(priv->ext_ip_config_6, &priv->ipv6ll_addr)) - priv->ipv6ll_has = FALSE; - } - - /* Remove parts from ext_ip_config_6 to only contain the information that - * was configured externally -- we already have the same configuration from - * internal origins. */ - if (priv->con_ip_config_6) { - nm_ip6_config_subtract(priv->ext_ip_config_6, - priv->con_ip_config_6, - default_route_metric_penalty_get(self, AF_INET6)); - } - if (applied_config_get_current(&priv->ac_ip6_config)) { - nm_ip_config_subtract((NMIPConfig *) priv->ext_ip_config_6, - applied_config_get_current(&priv->ac_ip6_config), - default_route_metric_penalty_get(self, AF_INET6)); - } - if (applied_config_get_current(&priv->dhcp6.ip6_config)) { - nm_ip_config_subtract((NMIPConfig *) priv->ext_ip_config_6, - applied_config_get_current(&priv->dhcp6.ip6_config), - default_route_metric_penalty_get(self, AF_INET6)); - } - if (applied_config_get_current(&priv->dev2_ip_config_6)) { - nm_ip_config_subtract((NMIPConfig *) priv->ext_ip_config_6, - applied_config_get_current(&priv->dev2_ip_config_6), - default_route_metric_penalty_get(self, AF_INET6)); - } - for (iter = priv->vpn_configs_6; iter; iter = iter->next) - nm_ip6_config_subtract(priv->ext_ip_config_6, iter->data, 0); - } - } - - return TRUE; -} - -static void -update_ip_config(NMDevice *self, int addr_family) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - nm_assert_addr_family(addr_family); - - if (NM_IS_IPv4(addr_family)) - priv->update_ip_config_completed_v4 = TRUE; - else - priv->update_ip_config_completed_v6 = TRUE; - - if (update_ext_ip_config(self, addr_family, TRUE)) { - if (NM_IS_IPv4(addr_family)) { - if (priv->ext_ip_config_4) - ip_config_merge_and_apply(self, AF_INET, FALSE); - } else { - if (priv->ext_ip6_config_captured) - ip_config_merge_and_apply(self, AF_INET6, FALSE); - } - } -} - -void -nm_device_capture_initial_config(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (!priv->update_ip_config_completed_v4) - update_ip_config(self, AF_INET); - if (!priv->update_ip_config_completed_v6) - update_ip_config(self, AF_INET6); -} - -static gboolean -queued_ip_config_change(NMDevice *self, int addr_family) -{ - NMDevicePrivate *priv; - const int IS_IPv4 = NM_IS_IPv4(addr_family); - - g_return_val_if_fail(NM_IS_DEVICE(self), G_SOURCE_REMOVE); - - priv = NM_DEVICE_GET_PRIVATE(self); - - /* Wait for any queued state changes */ - if (priv->queued_state.id) - return G_SOURCE_CONTINUE; - - /* If a commit is scheduled, this function would potentially interfere with - * it changing IP configurations before they are applied. Postpone the - * update in such case. - */ - if (priv->activation_source_id_x[IS_IPv4] != 0 - && priv->activation_source_func_x[IS_IPv4] - == activate_stage5_ip_config_result_x_fcn(addr_family)) - return G_SOURCE_CONTINUE; - - priv->queued_ip_config_id_x[IS_IPv4] = 0; - - update_ip_config(self, addr_family); - - if (!IS_IPv4) { - /* Check whether we need to complete waiting for link-local. - * We are also called from an idle handler, so no problem doing state transitions - * now. */ - linklocal6_check_complete(self); - } - - if (!IS_IPv4) { - NMPlatform * platform; - GSList * dad6_failed_addrs, *iter; - const NMPlatformLink *pllink; - - dad6_failed_addrs = g_steal_pointer(&priv->dad6_failed_addrs); - - if (priv->state > NM_DEVICE_STATE_DISCONNECTED && priv->state < NM_DEVICE_STATE_DEACTIVATING - && priv->ifindex > 0 && !nm_device_sys_iface_state_is_external(self) - && (platform = nm_device_get_platform(self)) - && (pllink = nm_platform_link_get(platform, priv->ifindex)) - && (pllink->n_ifi_flags & IFF_UP)) { - gboolean need_ipv6ll = FALSE; - NMNDiscConfigMap ndisc_config_changed = NM_NDISC_CONFIG_NONE; - - /* Handle DAD failures */ - for (iter = dad6_failed_addrs; iter; iter = iter->next) { - const NMPObject * obj = iter->data; - const NMPlatformIP6Address *addr; - - if (!nm_ndisc_dad_addr_is_fail_candidate(platform, obj)) - continue; - - addr = NMP_OBJECT_CAST_IP6_ADDRESS(obj); - - _LOGI(LOGD_IP6, - "ipv6: duplicate address check failed for the %s address", - nm_platform_ip6_address_to_string(addr, NULL, 0)); - - if (IN6_IS_ADDR_LINKLOCAL(&addr->address)) - need_ipv6ll = TRUE; - else if (priv->ndisc) - ndisc_config_changed |= nm_ndisc_dad_failed(priv->ndisc, &addr->address, FALSE); - } - - if (ndisc_config_changed != NM_NDISC_CONFIG_NONE) - nm_ndisc_emit_config_change(priv->ndisc, ndisc_config_changed); - - /* If no IPv6 link-local address exists but other addresses do then we - * must add the LL address to remain conformant with RFC 3513 chapter 2.1 - * ("Addressing Model"): "All interfaces are required to have at least - * one link-local unicast address". - */ - if (priv->ip_config_6 && nm_ip6_config_get_num_addresses(priv->ip_config_6)) - need_ipv6ll = TRUE; - if (need_ipv6ll) - check_and_add_ipv6ll_addr(self); - } - - g_slist_free_full(dad6_failed_addrs, (GDestroyNotify) nmp_object_unref); - } - - if (!IS_IPv4) { - /* Check if DAD is still pending */ - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF && priv->dad6_ip6_config - && priv->ext_ip6_config_captured - && !nm_ip6_config_has_any_dad_pending(priv->ext_ip6_config_captured, - priv->dad6_ip6_config)) { - _LOGD(LOGD_DEVICE | LOGD_IP6, "IPv6 DAD terminated"); - g_clear_object(&priv->dad6_ip6_config); - _set_ip_state(self, addr_family, NM_DEVICE_IP_STATE_DONE); - check_ip_state(self, FALSE, TRUE); - if (priv->rt6_temporary_not_available) - nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); - } - } - - set_unmanaged_external_down(self, TRUE); - - return G_SOURCE_REMOVE; -} - -static gboolean -queued_ip4_config_change(gpointer user_data) -{ - return queued_ip_config_change(user_data, AF_INET); -} - -static gboolean -queued_ip6_config_change(gpointer user_data) -{ - return queued_ip_config_change(user_data, AF_INET6); -} - -static void -device_ipx_changed(NMPlatform * platform, - int obj_type_i, - int ifindex, - gconstpointer platform_object, - int change_type_i, - NMDevice * self) -{ - const NMPObjectType obj_type = obj_type_i; - const NMPlatformSignalChangeType change_type = change_type_i; - NMDevicePrivate * priv; - const NMPlatformIP6Address * addr; - - if (nm_device_get_ip_ifindex(self) != ifindex) - return; - - if (!nm_device_is_real(self)) - return; - - if (nm_device_get_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT)) { - /* ignore all platform signals until the link is initialized in platform. */ - return; - } - - priv = NM_DEVICE_GET_PRIVATE(self); - - switch (obj_type) { - case NMP_OBJECT_TYPE_IP4_ADDRESS: - case NMP_OBJECT_TYPE_IP4_ROUTE: - if (!priv->queued_ip_config_id_4) { - priv->queued_ip_config_id_4 = g_idle_add(queued_ip4_config_change, self); - _LOGD(LOGD_DEVICE, "queued IP4 config change"); - } - break; - case NMP_OBJECT_TYPE_IP6_ADDRESS: - addr = platform_object; - - if (priv->state > NM_DEVICE_STATE_DISCONNECTED && priv->state < NM_DEVICE_STATE_DEACTIVATING - && nm_ndisc_dad_addr_is_fail_candidate_event(change_type, addr)) { - priv->dad6_failed_addrs = - g_slist_prepend(priv->dad6_failed_addrs, - (gpointer) nmp_object_ref(NMP_OBJECT_UP_CAST(addr))); - } - - /* fall-through */ - case NMP_OBJECT_TYPE_IP6_ROUTE: - if (!priv->queued_ip_config_id_6) { - priv->queued_ip_config_id_6 = g_idle_add(queued_ip6_config_change, self); - _LOGD(LOGD_DEVICE, "queued IP6 config change"); - } - break; - default: - g_return_if_reached(); - } -} - /*****************************************************************************/ NM_UTILS_FLAGS2STR_DEFINE(nm_unmanaged_flags2str, @@ -14835,12 +13361,6 @@ _set_unmanaged_flags(NMDevice * self, nm_device_set_unmanaged_flags(self, NM_UNMANAGED_USER_SETTINGS, !!unmanaged); } - /* trigger an initial update of IP configuration. */ - nm_assert_se(!nm_clear_g_source(&priv->queued_ip_config_id_4)); - nm_assert_se(!nm_clear_g_source(&priv->queued_ip_config_id_6)); - priv->queued_ip_config_id_4 = g_idle_add(queued_ip4_config_change, self); - priv->queued_ip_config_id_6 = g_idle_add(queued_ip6_config_change, self); - if (!priv->pending_actions) { do_notify_has_pending_actions = TRUE; had_pending_actions = nm_device_has_pending_action(self); @@ -15192,9 +13712,13 @@ nm_device_update_metered(NMDevice *self) /* Try to guess a value using the metered flag in IP configuration */ if (value == NM_METERED_INVALID) { - if (priv->ip_config_4 && priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE - && nm_ip4_config_get_metered(priv->ip_config_4)) - value = NM_METERED_GUESS_YES; + if (priv->l3cfg) { + const NML3ConfigData *l3cd; + + l3cd = nm_l3cfg_get_combined_l3cd(priv->l3cfg, TRUE); + if (l3cd && nm_l3_config_data_get_metered(l3cd)) + value = NM_METERED_GUESS_YES; + } } /* Otherwise, look at connection type. For Bluetooth, we look at the type of @@ -15762,7 +14286,7 @@ _cancel_activation(NMDevice *self) priv->fw_state = FIREWALL_STATE_INITIALIZED; } - dispatcher_cleanup(self); + _dispatcher_cleanup(self); ip_check_gw_ping_cleanup(self); /* Break the activation chain */ @@ -15797,7 +14321,7 @@ _cleanup_generic_pre(NMDevice *self, CleanupType cleanup_type) queued_state_clear(self); - nm_clear_pointer(&priv->shared_ip_handle, nm_netns_shared_ip_release); + _dev_shared4_cleanup(self); for (i = 0; i < 2; i++) nm_clear_pointer(&priv->hostname_resolver_x[i], _hostname_resolver_free); @@ -15816,6 +14340,7 @@ _cleanup_generic_post(NMDevice *self, CleanupType cleanup_type) priv->v4_route_table_initialized = FALSE; priv->v6_route_table_initialized = FALSE; + priv->l3config_merge_flags_has = FALSE; priv->v4_route_table_all_sync_before = FALSE; priv->v6_route_table_all_sync_before = FALSE; @@ -15825,39 +14350,12 @@ _cleanup_generic_post(NMDevice *self, CleanupType cleanup_type) priv->linklocal6_dad_counter = 0; - priv->mtu_force_set_done = FALSE; - - /* Clean up IP configs; this does not actually deconfigure the - * interface; the caller must flush routes and addresses explicitly. - */ - nm_device_set_ip_config(self, AF_INET, NULL, TRUE, NULL); - nm_device_set_ip_config(self, AF_INET6, NULL, TRUE, NULL); - g_clear_object(&priv->proxy_config); - g_clear_object(&priv->con_ip_config_4); - applied_config_clear(&priv->dev_ip_config_4); - applied_config_clear(&priv->dev2_ip_config_4); - g_clear_object(&priv->ext_ip_config_4); - g_clear_object(&priv->ip_config_4); - g_clear_object(&priv->con_ip_config_6); - applied_config_clear(&priv->ac_ip6_config); - g_clear_object(&priv->ext_ip_config_6); - g_clear_object(&priv->ext_ip6_config_captured); - applied_config_clear(&priv->dev2_ip_config_6); - g_clear_object(&priv->ip_config_6); - g_clear_object(&priv->dad6_ip6_config); - priv->ipv6ll_has = FALSE; - memset(&priv->ipv6ll_addr, 0, sizeof(priv->ipv6ll_addr)); - - nm_clear_pointer(&priv->rt6_temporary_not_available, g_hash_table_unref); - nm_clear_g_source(&priv->rt6_temporary_not_available_id); + priv->ipv6ll_has = FALSE; + priv->ipv6ll_addr = nm_ip_addr_zero.addr6; - g_slist_free_full(priv->vpn_configs_4, g_object_unref); - priv->vpn_configs_4 = NULL; - g_slist_free_full(priv->vpn_configs_6, g_object_unref); - priv->vpn_configs_6 = NULL; + priv->mtu_force_set_done = FALSE; - /* We no longer accept the delegations. nm_device_set_ip_config(NULL) - * above disables them. */ + /* We no longer accept the delegations and don't expect the value to be set. */ nm_assert(priv->needs_ip6_subnet == FALSE); if (priv->act_request.obj) { @@ -16027,18 +14525,19 @@ deactivate_reset_hw_addr(NMDevice *self) static char * find_dhcp4_address(NMDevice *self) { - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - const NMPlatformIP4Address *a; - NMDedupMultiIter ipconf_iter; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const NMPObject *obj; - if (!priv->ip_config_4) + if (!priv->l3cds[L3_CONFIG_DATA_TYPE_DHCP_4].d) return NULL; - nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, priv->ip_config_4, &a) { - if (a->addr_source == NM_IP_CONFIG_SOURCE_DHCP) - return nm_utils_inet4_ntop_dup(a->address); - } - return NULL; + obj = nm_l3_config_data_get_first_obj(priv->l3cds[L3_CONFIG_DATA_TYPE_DHCP_4].d, + NMP_OBJECT_TYPE_IP4_ADDRESS, + NULL); + if (!obj) + return NULL; + + return nm_utils_inet4_ntop_dup(NMP_OBJECT_CAST_IP4_ADDRESS(obj)->address); } void @@ -16050,7 +14549,6 @@ nm_device_spawn_iface_helper(NMDevice *self) GError * error = NULL; const char * method; GPtrArray * argv; - gs_free char * dhcp4_address = NULL; char * logging_backend; NMUtilsStableType stable_type; const char * stable_id; @@ -16095,10 +14593,9 @@ nm_device_spawn_iface_helper(NMDevice *self) g_ptr_array_add(argv, g_strdup("--log-domains")); g_ptr_array_add(argv, g_strdup(nm_logging_domains_to_string())); - dhcp4_address = find_dhcp4_address(self); - method = nm_device_get_effective_ip_config_method(self, AF_INET); if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { + char * dhcp4_address; NMSettingIPConfig *s_ip4; s_ip4 = nm_connection_get_setting_ip4_config(connection); @@ -16107,8 +14604,12 @@ nm_device_spawn_iface_helper(NMDevice *self) g_ptr_array_add(argv, g_strdup("--priority4")); g_ptr_array_add(argv, g_strdup_printf("%u", nm_device_get_route_metric(self, AF_INET))); - g_ptr_array_add(argv, g_strdup("--dhcp4")); - g_ptr_array_add(argv, g_strdup(dhcp4_address)); + dhcp4_address = find_dhcp4_address(self); + if (dhcp4_address) { + g_ptr_array_add(argv, g_strdup("--dhcp4")); + g_ptr_array_add(argv, dhcp4_address); + } + if (nm_setting_ip_config_get_may_fail(s_ip4) == FALSE) g_ptr_array_add(argv, g_strdup("--dhcp4-required")); @@ -16158,7 +14659,7 @@ nm_device_spawn_iface_helper(NMDevice *self) g_ptr_array_add(argv, g_strdup("--slaac-required")); g_ptr_array_add(argv, g_strdup("--slaac-tempaddr")); - g_ptr_array_add(argv, g_strdup_printf("%d", priv->ndisc_use_tempaddr)); + g_ptr_array_add(argv, g_strdup_printf("%d", (int) priv->ac6_ip6_privacy)); if (nm_device_get_ip_iface_identifier(self, &iid, FALSE)) { g_ptr_array_add(argv, g_strdup("--iid")); @@ -16209,23 +14710,6 @@ nm_device_spawn_iface_helper(NMDevice *self) /*****************************************************************************/ -static gboolean -ip_config_valid(NMDeviceState state) -{ - return (state == NM_DEVICE_STATE_UNMANAGED) - || (state >= NM_DEVICE_STATE_IP_CHECK && state <= NM_DEVICE_STATE_DEACTIVATING); -} - -static void -notify_ip_properties(NMDevice *self) -{ - _notify(self, PROP_IP_IFACE); - _notify(self, PROP_IP4_CONFIG); - _notify(self, PROP_DHCP4_CONFIG); - _notify(self, PROP_IP6_CONFIG); - _notify(self, PROP_DHCP6_CONFIG); -} - static void ip6_managed_setup(NMDevice *self) { @@ -16364,9 +14848,9 @@ deactivate_dispatcher_complete(NMDispatcherCallId *call_id, gpointer user_data) static void _set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason, gboolean quitting) { - NMDevicePrivate *priv; - NMDeviceState old_state; - gs_unref_object NMActRequest *req = NULL; + gs_unref_object NMActRequest *req = NULL; + NMDevicePrivate * priv; + NMDeviceState old_state; gboolean no_firmware = FALSE; NMSettingsConnection * sett_conn; NMSettingSriov * s_sriov; @@ -16376,8 +14860,7 @@ _set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason, priv = NM_DEVICE_GET_PRIVATE(self); - /* Track re-entry */ - g_warn_if_fail(priv->in_state_changed == FALSE); + g_return_if_fail(priv->in_state_changed == 0); old_state = priv->state; @@ -16414,14 +14897,14 @@ _set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason, * by the device not having any pending action anymore * we add one here that gets removed at the end of the function */ nm_device_add_pending_action(self, NM_PENDING_ACTION_IN_STATE_CHANGE, TRUE); - priv->in_state_changed = TRUE; + priv->in_state_changed++; priv->state = state; priv->state_reason = reason; queued_state_clear(self); - dispatcher_cleanup(self); + _dispatcher_cleanup(self); nm_clear_g_cancellable(&priv->deactivating_cancellable); @@ -16628,9 +15111,7 @@ _set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason, _LOGI(LOGD_DEVICE, "Activation: successful, device activated."); nm_device_update_metered(self); nm_dispatcher_call_device(NM_DISPATCHER_ACTION_UP, self, req, NULL, NULL, NULL); - - if (priv->proxy_config) - _pacrunner_manager_add(self); + _pacrunner_manager_add(self); break; case NM_DEVICE_STATE_FAILED: /* Usually upon failure the activation chain is interrupted in @@ -16690,11 +15171,6 @@ _set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason, fw_change_zone(self); } else nm_device_start_ip_check(self); - - /* IP-related properties are only valid when the device has IP configuration; - * now that it does, ensure their change notifications are emitted. - */ - notify_ip_properties(self); break; } case NM_DEVICE_STATE_SECONDARIES: @@ -16717,18 +15193,13 @@ _set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason, } } - /* IP-related properties are only valid when the device has IP configuration. - * If it no longer does, ensure their change notifications are emitted. - */ - if (ip_config_valid(old_state) && !ip_config_valid(state)) - notify_ip_properties(self); - concheck_now = NM_IN_SET(state, NM_DEVICE_STATE_ACTIVATED, NM_DEVICE_STATE_DISCONNECTED) || old_state >= NM_DEVICE_STATE_ACTIVATED; concheck_update_interval(self, AF_INET, concheck_now); concheck_update_interval(self, AF_INET6, concheck_now); - priv->in_state_changed = FALSE; + priv->in_state_changed--; + nm_device_remove_pending_action(self, NM_PENDING_ACTION_IN_STATE_CHANGE, TRUE); if ((old_state > NM_DEVICE_STATE_UNMANAGED) != (state > NM_DEVICE_STATE_UNMANAGED)) @@ -17790,14 +16261,14 @@ nm_device_get_hostname_from_dns_lookup(NMDevice *self, int addr_family, gboolean * whether it changed from the previous lookup */ ip_config = priv->ip_config_x[IS_IPv4]; if (ip_config) { - const NMPlatformIPAddress *addr; + //XXX const NMPlatformIPAddress *addr; - 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 - : G_SOCKET_FAMILY_IPV6); - } + //XXX addr = nm_ip_config_get_first_address(ip_config); + //XXX if (addr) { + //XXX new_address = g_inet_address_new_from_bytes(addr->address_ptr, + //XXX IS_IPv4 ? G_SOCKET_FAMILY_IPV4 + //XXX : G_SOCKET_FAMILY_IPV6); + //XXX } } if (new_address && resolver->address) { @@ -17912,13 +16383,10 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) nm_utils_str_utf8safe_escape_cp(priv->iface, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL)); break; case PROP_IP_IFACE: - if (ip_config_valid(priv->state)) { - g_value_take_string( - value, - nm_utils_str_utf8safe_escape_cp(nm_device_get_ip_iface(self), - NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL)); - } else - g_value_set_string(value, NULL); + g_value_take_string( + value, + nm_utils_str_utf8safe_escape_cp(nm_device_get_ip_iface(self), + NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL)); break; case PROP_IFINDEX: g_value_set_int(value, priv->ifindex); @@ -17953,24 +16421,16 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) g_value_set_uint(value, priv->mtu); break; case PROP_IP4_CONFIG: - nm_dbus_utils_g_value_set_object_path(value, - ip_config_valid(priv->state) ? priv->ip_config_4 - : NULL); + nm_dbus_utils_g_value_set_object_path(value, priv->ip_config_4); break; case PROP_DHCP4_CONFIG: - nm_dbus_utils_g_value_set_object_path( - value, - ip_config_valid(priv->state) ? priv->dhcp_data_4.config : NULL); + nm_dbus_utils_g_value_set_object_path(value, priv->dhcp_data_4.config); break; case PROP_IP6_CONFIG: - nm_dbus_utils_g_value_set_object_path(value, - ip_config_valid(priv->state) ? priv->ip_config_6 - : NULL); + nm_dbus_utils_g_value_set_object_path(value, priv->ip_config_6); break; case PROP_DHCP6_CONFIG: - nm_dbus_utils_g_value_set_object_path( - value, - ip_config_valid(priv->state) ? priv->dhcp_data_6.config : NULL); + nm_dbus_utils_g_value_set_object_path(value, priv->dhcp_data_6.config); break; case PROP_STATE: g_value_set_uint(value, priv->state); @@ -18281,24 +16741,7 @@ constructed(GObject *object) if (NM_DEVICE_GET_CLASS(self)->get_generic_capabilities) priv->capabilities |= NM_DEVICE_GET_CLASS(self)->get_generic_capabilities(self); - /* Watch for external IP config changes */ platform = nm_device_get_platform(self); - g_signal_connect(platform, - NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, - G_CALLBACK(device_ipx_changed), - self); - g_signal_connect(platform, - NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, - G_CALLBACK(device_ipx_changed), - self); - g_signal_connect(platform, - NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, - G_CALLBACK(device_ipx_changed), - self); - g_signal_connect(platform, - NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, - G_CALLBACK(device_ipx_changed), - self); g_signal_connect(platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK(link_changed_cb), self); priv->manager = g_object_ref(NM_MANAGER_GET); @@ -18350,15 +16793,12 @@ dispose(GObject *object) _parent_set_ifindex(self, 0, FALSE); platform = nm_device_get_platform(self); - g_signal_handlers_disconnect_by_func(platform, G_CALLBACK(device_ipx_changed), self); g_signal_handlers_disconnect_by_func(platform, G_CALLBACK(link_changed_cb), self); - arp_cleanup(self); - nm_clear_g_signal_handler(nm_config_get(), &priv->config_changed_id); nm_clear_g_signal_handler(priv->manager, &priv->ifindex_changed_id); - dispatcher_cleanup(self); + _dispatcher_cleanup(self); nm_pacrunner_manager_remove_clear(&priv->pacrunner_conf_id); @@ -18436,7 +16876,6 @@ finalize(GObject *object) g_free(priv->hw_addr_perm); g_free(priv->hw_addr_initial); g_slist_free(priv->pending_actions); - g_slist_free_full(priv->dad6_failed_addrs, (GDestroyNotify) nmp_object_unref); nm_clear_g_free(&priv->physical_port_id); g_free(priv->udi); g_free(priv->path); @@ -18951,29 +17390,17 @@ nm_device_class_init(NMDeviceClass *klass) G_TYPE_BOOLEAN, 0); - signals[IP4_CONFIG_CHANGED] = g_signal_new(NM_DEVICE_IP4_CONFIG_CHANGED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 2, - G_TYPE_OBJECT, - G_TYPE_OBJECT); - - signals[IP6_CONFIG_CHANGED] = g_signal_new(NM_DEVICE_IP6_CONFIG_CHANGED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 2, - G_TYPE_OBJECT, - G_TYPE_OBJECT); + signals[L3CD_CHANGED] = g_signal_new(NM_DEVICE_L3CD_CHANGED, + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 2, + G_TYPE_POINTER, /* (const NML3ConfigData *l3cd_old) */ + G_TYPE_POINTER /* (const NML3ConfigData *l3cd_new) */); signals[IP6_PREFIX_DELEGATED] = g_signal_new(NM_DEVICE_IP6_PREFIX_DELEGATED, G_OBJECT_CLASS_TYPE(object_class), diff --git a/src/core/devices/nm-device.h b/src/core/devices/nm-device.h index 53211c6f2f..90bcb48ff5 100644 --- a/src/core/devices/nm-device.h +++ b/src/core/devices/nm-device.h @@ -70,8 +70,7 @@ /* Internal signals */ #define NM_DEVICE_DNS_LOOKUP_DONE "dns-lookup-done" -#define NM_DEVICE_IP4_CONFIG_CHANGED "ip4-config-changed" -#define NM_DEVICE_IP6_CONFIG_CHANGED "ip6-config-changed" +#define NM_DEVICE_L3CD_CHANGED "l3cd-changed" #define NM_DEVICE_IP6_PREFIX_DELEGATED "ip6-prefix-delegated" #define NM_DEVICE_IP6_SUBNET_NEEDED "ip6-subnet-needed" #define NM_DEVICE_REMOVED "removed" @@ -343,15 +342,16 @@ typedef struct _NMDeviceClass { NMActStageReturn (*act_stage1_prepare)(NMDevice *self, NMDeviceStateReason *out_failure_reason); NMActStageReturn (*act_stage2_config)(NMDevice *self, NMDeviceStateReason *out_failure_reason); - NMActStageReturn (*act_stage3_ip_config_start)(NMDevice * self, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason); + NMActStageReturn (*act_stage3_ip_config_start)(NMDevice * self, + int addr_family, + const NML3ConfigData **out_l3cd, + NMDeviceStateReason * out_failure_reason); NMActStageReturn (*act_stage4_ip_config_timeout)(NMDevice * self, int addr_family, NMDeviceStateReason *out_failure_reason); - void (*ip4_config_pre_commit)(NMDevice *self, NMIP4Config *config); + //XXX: needs rework to not use NMIP4Config. + void (*ip4_config_pre_commit)(NMDevice *self); /* Async deactivating (in the DEACTIVATING phase) */ void (*deactivate_async)(NMDevice * self, @@ -459,16 +459,11 @@ const char *nm_device_get_permanent_hw_address_full(NMDevice *self, gboolean *out_is_fake); const char *nm_device_get_initial_hw_address(NMDevice *dev); -NMProxyConfig *nm_device_get_proxy_config(NMDevice *dev); - NMDhcpConfig *nm_device_get_dhcp_config(NMDevice *dev, int addr_family); -NMIP4Config * nm_device_get_ip4_config(NMDevice *dev); -void nm_device_replace_vpn4_config(NMDevice *dev, NMIP4Config *old, NMIP4Config *config); -NMIP6Config *nm_device_get_ip6_config(NMDevice *dev); -void nm_device_replace_vpn6_config(NMDevice *dev, NMIP6Config *old, NMIP6Config *config); +const NML3Cfg *nm_device_get_l3cfg(NMDevice *self); -void nm_device_capture_initial_config(NMDevice *dev); +const NML3ConfigData *nm_device_get_l3cd(NMDevice *self, gboolean get_commited); int nm_device_parent_get_ifindex(NMDevice *dev); NMDevice *nm_device_parent_get_device(NMDevice *dev); diff --git a/src/core/devices/ovs/nm-device-ovs-bridge.c b/src/core/devices/ovs/nm-device-ovs-bridge.c index 26a5ba002c..f18102cfe2 100644 --- a/src/core/devices/ovs/nm-device-ovs-bridge.c +++ b/src/core/devices/ovs/nm-device-ovs-bridge.c @@ -67,10 +67,10 @@ get_generic_capabilities(NMDevice *device) } static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) +act_stage3_ip_config_start(NMDevice * device, + int addr_family, + const NML3ConfigData **out_l3cd, + NMDeviceStateReason * out_failure_reason) { return NM_ACT_STAGE_RETURN_IP_FAIL; } diff --git a/src/core/devices/ovs/nm-device-ovs-interface.c b/src/core/devices/ovs/nm-device-ovs-interface.c index 46a612aca7..ad04e9fea7 100644 --- a/src/core/devices/ovs/nm-device-ovs-interface.c +++ b/src/core/devices/ovs/nm-device-ovs-interface.c @@ -189,10 +189,10 @@ set_platform_mtu(NMDevice *device, guint32 mtu) } static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) +act_stage3_ip_config_start(NMDevice * device, + int addr_family, + const NML3ConfigData **out_l3cd, + NMDeviceStateReason * out_failure_reason) { NMDeviceOvsInterface * self = NM_DEVICE_OVS_INTERFACE(device); NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(device); @@ -212,7 +212,7 @@ act_stage3_ip_config_start(NMDevice * device, } return NM_DEVICE_CLASS(nm_device_ovs_interface_parent_class) - ->act_stage3_ip_config_start(device, addr_family, out_config, out_failure_reason); + ->act_stage3_ip_config_start(device, addr_family, out_l3cd, out_failure_reason); } static gboolean diff --git a/src/core/devices/ovs/nm-device-ovs-port.c b/src/core/devices/ovs/nm-device-ovs-port.c index f11c585235..be1a51be8d 100644 --- a/src/core/devices/ovs/nm-device-ovs-port.c +++ b/src/core/devices/ovs/nm-device-ovs-port.c @@ -60,10 +60,10 @@ get_generic_capabilities(NMDevice *device) } static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) +act_stage3_ip_config_start(NMDevice * device, + int addr_family, + const NML3ConfigData **out_l3cd, + NMDeviceStateReason * out_failure_reason) { return NM_ACT_STAGE_RETURN_IP_FAIL; } diff --git a/src/core/devices/team/nm-device-team.c b/src/core/devices/team/nm-device-team.c index 0f1a8c4cec..5fa16790d0 100644 --- a/src/core/devices/team/nm-device-team.c +++ b/src/core/devices/team/nm-device-team.c @@ -22,7 +22,6 @@ #include "nm-config.h" #include "libnm-core-intern/nm-core-internal.h" #include "nm-dbus-manager.h" -#include "nm-ip4-config.h" #include "libnm-std-aux/nm-dbus-compat.h" #define _NMLOG_DEVICE_TYPE NMDeviceTeam diff --git a/src/core/devices/tests/meson.build b/src/core/devices/tests/meson.build index 1bc883706e..871c320629 100644 --- a/src/core/devices/tests/meson.build +++ b/src/core/devices/tests/meson.build @@ -1,7 +1,6 @@ # SPDX-License-Identifier: LGPL-2.1-or-later test_units = [ - 'test-acd', 'test-lldp', ] diff --git a/src/core/devices/tests/test-acd.c b/src/core/devices/tests/test-acd.c deleted file mode 100644 index b4b6516549..0000000000 --- a/src/core/devices/tests/test-acd.c +++ /dev/null @@ -1,259 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2015 Red Hat, Inc. - */ - -#include "src/core/nm-default-daemon.h" - -#include "n-acd/src/n-acd.h" - -#include - -#include "devices/nm-acd-manager.h" -#include "platform/tests/test-common.h" - -#define IFACE_VETH0 "nm-test-veth0" -#define IFACE_VETH1 "nm-test-veth1" - -#define ADDR1 0x01010101 -#define ADDR2 0x02020202 -#define ADDR3 0x03030303 -#define ADDR4 0x04040404 - -/*****************************************************************************/ - -static gboolean -_skip_acd_test_check(void) -{ - NAcd * acd; - NAcdConfig * config; - const guint8 hwaddr[ETH_ALEN] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; - int r; - static int skip = -1; - - if (skip == -1) { - r = n_acd_config_new(&config); - g_assert(r == 0); - - n_acd_config_set_ifindex(config, 1); - n_acd_config_set_transport(config, N_ACD_TRANSPORT_ETHERNET); - n_acd_config_set_mac(config, hwaddr, sizeof(hwaddr)); - - r = n_acd_new(&acd, config); - n_acd_config_free(config); - if (r == 0) - n_acd_unref(acd); - - skip = (r != 0); - } - return skip; -} - -#define _skip_acd_test() \ - ({ \ - gboolean _skip = _skip_acd_test_check(); \ - \ - if (_skip) \ - g_test_skip("Cannot create NAcd. Running under valgind?"); \ - _skip; \ - }) - -/*****************************************************************************/ - -typedef struct { - int ifindex0; - int ifindex1; - const guint8 *hwaddr0; - const guint8 *hwaddr1; - size_t hwaddr0_len; - size_t hwaddr1_len; -} test_fixture; - -static void -fixture_setup(test_fixture *fixture, gconstpointer user_data) -{ - /* create veth pair. */ - fixture->ifindex0 = - nmtstp_link_veth_add(NM_PLATFORM_GET, -1, IFACE_VETH0, IFACE_VETH1)->ifindex; - fixture->ifindex1 = - nmtstp_link_get_typed(NM_PLATFORM_GET, -1, IFACE_VETH1, NM_LINK_TYPE_VETH)->ifindex; - - 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); - fixture->hwaddr1 = - nm_platform_link_get_address(NM_PLATFORM_GET, fixture->ifindex1, &fixture->hwaddr1_len); -} - -typedef struct { - in_addr_t addresses[8]; - in_addr_t peer_addresses[8]; - gboolean expected_result[8]; -} TestInfo; - -static void -acd_manager_probe_terminated(NMAcdManager *acd_manager, gpointer user_data) -{ - g_main_loop_quit(user_data); -} - -static void -test_acd_common(test_fixture *fixture, TestInfo *info) -{ - nm_auto_free_acdmgr NMAcdManager *manager = NULL; - nm_auto_unref_gmainloop GMainLoop *loop = NULL; - int i; - const guint WAIT_TIME_OPTIMISTIC = 50; - guint wait_time; - static const NMAcdCallbacks callbacks = { - .probe_terminated_callback = acd_manager_probe_terminated, - .user_data_destroy = (GDestroyNotify) g_main_loop_unref, - }; - int r; - - if (_skip_acd_test()) - return; - - /* first, try with a short waittime. We hope that this is long enough - * to successfully complete the test. Only if that's not the case, we - * assume the computer is currently busy (high load) and we retry with - * a longer timeout. */ - wait_time = WAIT_TIME_OPTIMISTIC; -again: - - nm_clear_pointer(&loop, g_main_loop_unref); - loop = g_main_loop_new(NULL, FALSE); - - nm_clear_pointer(&manager, nm_acd_manager_free); - manager = nm_acd_manager_new(fixture->ifindex0, - fixture->hwaddr0, - fixture->hwaddr0_len, - &callbacks, - g_main_loop_ref(loop)); - g_assert(manager != NULL); - - for (i = 0; info->addresses[i]; i++) - g_assert(nm_acd_manager_add_address(manager, info->addresses[i])); - - for (i = 0; info->peer_addresses[i]; i++) { - nmtstp_ip4_address_add(NULL, - FALSE, - fixture->ifindex1, - info->peer_addresses[i], - 24, - 0, - 3600, - 1800, - 0, - NULL); - } - - r = nm_acd_manager_start_probe(manager, wait_time); - g_assert_cmpint(r, ==, 0); - - g_assert(nmtst_main_loop_run(loop, 2000)); - - for (i = 0; info->addresses[i]; i++) { - gboolean val; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - val = nm_acd_manager_check_address(manager, info->addresses[i]); - if (val == info->expected_result[i]) - continue; - - if (wait_time == WAIT_TIME_OPTIMISTIC) { - /* probably we just had a glitch and the system took longer than - * expected. Re-verify with a large timeout this time. */ - wait_time = 1000; - goto again; - } - - g_error("expected check for address #%d (%s) to %s, but it didn't", - i, - _nm_utils_inet4_ntop(info->addresses[i], sbuf), - info->expected_result[i] ? "detect no duplicated" : "detect a duplicate"); - } -} - -static void -test_acd_probe_1(test_fixture *fixture, gconstpointer user_data) -{ - TestInfo info = {.addresses = {ADDR1, ADDR2, ADDR3}, - .peer_addresses = {ADDR4}, - .expected_result = {TRUE, TRUE, TRUE}}; - - test_acd_common(fixture, &info); -} - -static void -test_acd_probe_2(test_fixture *fixture, gconstpointer user_data) -{ - TestInfo info = {.addresses = {ADDR1, ADDR2, ADDR3, ADDR4}, - .peer_addresses = {ADDR3, ADDR2}, - .expected_result = {TRUE, FALSE, FALSE, TRUE}}; - - test_acd_common(fixture, &info); -} - -static void -test_acd_announce(test_fixture *fixture, gconstpointer user_data) -{ - nm_auto_free_acdmgr NMAcdManager *manager = NULL; - nm_auto_unref_gmainloop GMainLoop *loop = NULL; - int r; - - if (_skip_acd_test()) - return; - - manager = - nm_acd_manager_new(fixture->ifindex0, fixture->hwaddr0, fixture->hwaddr0_len, NULL, NULL); - g_assert(manager != NULL); - - g_assert(nm_acd_manager_add_address(manager, ADDR1)); - g_assert(nm_acd_manager_add_address(manager, ADDR2)); - - loop = g_main_loop_new(NULL, FALSE); - r = nm_acd_manager_announce_addresses(manager); - g_assert_cmpint(r, ==, 0); - g_assert(!nmtst_main_loop_run(loop, 200)); -} - -static void -fixture_teardown(test_fixture *fixture, gconstpointer user_data) -{ - nm_platform_link_delete(NM_PLATFORM_GET, fixture->ifindex0); - nm_platform_link_delete(NM_PLATFORM_GET, fixture->ifindex1); -} - -NMTstpSetupFunc const _nmtstp_setup_platform_func = nm_linux_platform_setup; - -void -_nmtstp_init_tests(int *argc, char ***argv) -{ - nmtst_init_with_logging(argc, argv, NULL, "ALL"); -} - -void -_nmtstp_setup_tests(void) -{ - g_test_add("/acd/probe/1", - test_fixture, - NULL, - fixture_setup, - test_acd_probe_1, - fixture_teardown); - g_test_add("/acd/probe/2", - test_fixture, - NULL, - fixture_setup, - test_acd_probe_2, - fixture_teardown); - g_test_add("/acd/announce", - test_fixture, - NULL, - fixture_setup, - test_acd_announce, - fixture_teardown); -} diff --git a/src/core/devices/wifi/nm-device-wifi-p2p.c b/src/core/devices/wifi/nm-device-wifi-p2p.c index a8ea2ed7e5..92c6f96269 100644 --- a/src/core/devices/wifi/nm-device-wifi-p2p.c +++ b/src/core/devices/wifi/nm-device-wifi-p2p.c @@ -17,7 +17,6 @@ #include "nm-act-request.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" @@ -555,10 +554,10 @@ remove_all_peers(NMDeviceWifiP2P *self) /*****************************************************************************/ static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) +act_stage3_ip_config_start(NMDevice * device, + int addr_family, + const NML3ConfigData **out_l3cd, + NMDeviceStateReason * out_failure_reason) { gboolean indicate_addressing_running; NMConnection *connection; @@ -582,7 +581,7 @@ act_stage3_ip_config_start(NMDevice * device, TRUE); return NM_DEVICE_CLASS(nm_device_wifi_p2p_parent_class) - ->act_stage3_ip_config_start(device, addr_family, out_config, out_failure_reason); + ->act_stage3_ip_config_start(device, addr_family, out_l3cd, out_failure_reason); } static void diff --git a/src/core/devices/wifi/nm-device-wifi.c b/src/core/devices/wifi/nm-device-wifi.c index dd52186d82..af7b2a2160 100644 --- a/src/core/devices/wifi/nm-device-wifi.c +++ b/src/core/devices/wifi/nm-device-wifi.c @@ -31,7 +31,6 @@ #include "nm-setting-wireless-security.h" #include "nm-setting-8021x.h" #include "nm-setting-ip4-config.h" -#include "nm-ip4-config.h" #include "nm-setting-ip6-config.h" #include "libnm-platform/nm-platform.h" #include "nm-auth-utils.h" @@ -3271,10 +3270,10 @@ out_fail: } static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) +act_stage3_ip_config_start(NMDevice * device, + int addr_family, + const NML3ConfigData **out_l3cd, + NMDeviceStateReason * out_failure_reason) { gboolean indicate_addressing_running; NMConnection *connection; @@ -3297,7 +3296,7 @@ act_stage3_ip_config_start(NMDevice * device, TRUE); return NM_DEVICE_CLASS(nm_device_wifi_parent_class) - ->act_stage3_ip_config_start(device, addr_family, out_config, out_failure_reason); + ->act_stage3_ip_config_start(device, addr_family, out_l3cd, out_failure_reason); } static guint32 diff --git a/src/core/devices/wwan/nm-device-modem.c b/src/core/devices/wwan/nm-device-modem.c index a8d2a161fc..3d49026006 100644 --- a/src/core/devices/wwan/nm-device-modem.c +++ b/src/core/devices/wwan/nm-device-modem.c @@ -8,7 +8,7 @@ #include "nm-device-modem.h" #include "nm-modem.h" -#include "nm-ip4-config.h" +#include "nm-l3-config-data.h" #include "devices/nm-device-private.h" #include "nm-rfkill-manager.h" #include "settings/nm-settings-connection.h" @@ -33,6 +33,7 @@ typedef struct { NMModem * modem; NMDeviceModemCapabilities caps; NMDeviceModemCapabilities current_caps; + NMUtilsIPv6IfaceId iid; char * device_id; char * operator_code; char * apn; @@ -188,35 +189,36 @@ modem_auth_result(NMModem *modem, GError *error, gpointer user_data) } static void -modem_ip4_config_result(NMModem *modem, NMIP4Config *config, GError *error, gpointer user_data) -{ - NMDeviceModem *self = NM_DEVICE_MODEM(user_data); - NMDevice * device = NM_DEVICE(self); +modem_new_config(NMModem * modem, + int addr_family, + const NML3ConfigData * l3cd, + gboolean do_slaac, + const NMUtilsIPv6IfaceId *iid, + GError * error, + gpointer user_data) +{ + NMDeviceModem * self = NM_DEVICE_MODEM(user_data); + NMDeviceModemPrivate * priv = NM_DEVICE_MODEM_GET_PRIVATE(self); + NMDevice * device = NM_DEVICE(self); + NMActStageReturn ret; + NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; + nm_auto_unref_l3cd const NML3ConfigData *l3cd_ignored = NULL; - g_return_if_fail(nm_device_activate_ip4_state_in_conf(device) == TRUE); + if (addr_family == AF_INET) { + g_return_if_fail(nm_device_activate_ip4_state_in_conf(device) == TRUE); - if (error) { - _LOGW(LOGD_MB | LOGD_IP4, "retrieving IPv4 configuration failed: %s", error->message); - nm_device_ip_method_failed(device, AF_INET, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } else { - nm_device_set_dev2_ip_config(device, AF_INET, NM_IP_CONFIG_CAST(config)); - nm_device_activate_schedule_ip_config_result(device, AF_INET, NULL); - } -} + if (error) { + _LOGW(LOGD_MB | LOGD_IP4, "retrieving IPv4 configuration failed: %s", error->message); + nm_device_ip_method_failed(device, + AF_INET, + NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + return; + } -static void -modem_ip6_config_result(NMModem * modem, - NMIP6Config *config, - gboolean do_slaac, - GError * error, - gpointer user_data) -{ - NMDeviceModem * self = NM_DEVICE_MODEM(user_data); - NMDevice * device = NM_DEVICE(self); - NMActStageReturn ret; - NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - gs_unref_object NMIP6Config *ignored = NULL; - gboolean got_config = !!config; + nm_device_set_dev2_ip_config(device, AF_INET, l3cd); + nm_device_activate_schedule_ip_config_result(device, AF_INET); + return; + } g_return_if_fail(nm_device_activate_ip6_state_in_conf(device) == TRUE); @@ -226,15 +228,19 @@ modem_ip6_config_result(NMModem * modem, return; } + if (iid) + priv->iid = *iid; + else + priv->iid.id = 0; + /* Re-enable IPv6 on the interface */ nm_device_sysctl_ip_conf_set(device, AF_INET6, "disable_ipv6", "0"); - if (config) - nm_device_set_dev2_ip_config(device, AF_INET6, NM_IP_CONFIG_CAST(config)); + nm_device_set_dev2_ip_config(device, AF_INET6, l3cd); if (do_slaac == FALSE) { - if (got_config) - nm_device_activate_schedule_ip_config_result(device, AF_INET6, NULL); + if (l3cd) + nm_device_activate_schedule_ip_config_result(device, AF_INET6); else { _LOGW(LOGD_MB | LOGD_IP6, "retrieving IPv6 configuration failed: SLAAC not requested and no addresses"); @@ -246,11 +252,10 @@ modem_ip6_config_result(NMModem * modem, } /* Start SLAAC now that we have a link-local address from the modem */ - ret = - NM_DEVICE_CLASS(nm_device_modem_parent_class) - ->act_stage3_ip_config_start(device, AF_INET6, (gpointer *) &ignored, &failure_reason); + ret = NM_DEVICE_CLASS(nm_device_modem_parent_class) + ->act_stage3_ip_config_start(device, AF_INET6, &l3cd_ignored, &failure_reason); - nm_assert(ignored == NULL); + nm_assert(!l3cd_ignored); switch (ret) { case NM_ACT_STAGE_RETURN_FAILURE: @@ -258,7 +263,7 @@ modem_ip6_config_result(NMModem * modem, break; case NM_ACT_STAGE_RETURN_IP_FAIL: /* all done */ - nm_device_activate_schedule_ip_config_result(device, AF_INET6, NULL); + nm_device_activate_schedule_ip_config_result(device, AF_INET6); break; case NM_ACT_STAGE_RETURN_POSTPONE: /* let SLAAC run */ @@ -602,10 +607,10 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) } static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) +act_stage3_ip_config_start(NMDevice * device, + int addr_family, + const NML3ConfigData **out_l3cd, + NMDeviceStateReason * out_failure_reason) { NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(device); @@ -622,9 +627,9 @@ act_stage3_ip_config_start(NMDevice * device, } static void -ip4_config_pre_commit(NMDevice *device, NMIP4Config *config) +ip4_config_pre_commit(NMDevice *device) { - nm_modem_ip4_pre_commit(NM_DEVICE_MODEM_GET_PRIVATE(device)->modem, device, config); + nm_modem_ip4_pre_commit(NM_DEVICE_MODEM_GET_PRIVATE(device)->modem, device); } static gboolean @@ -632,14 +637,15 @@ get_ip_iface_identifier(NMDevice *device, NMUtilsIPv6IfaceId *out_iid) { NMDeviceModem * self = NM_DEVICE_MODEM(device); NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(self); - gboolean success; g_return_val_if_fail(priv->modem, FALSE); - success = nm_modem_get_iid(priv->modem, out_iid); - if (!success) - success = - NM_DEVICE_CLASS(nm_device_modem_parent_class)->get_ip_iface_identifier(device, out_iid); - return success; + + if (priv->iid.id != 0) { + *out_iid = priv->iid; + return TRUE; + } + + return NM_DEVICE_CLASS(nm_device_modem_parent_class)->get_ip_iface_identifier(device, out_iid); } /*****************************************************************************/ @@ -705,8 +711,7 @@ set_modem(NMDeviceModem *self, NMModem *modem) g_signal_connect(modem, NM_MODEM_PPP_FAILED, G_CALLBACK(ppp_failed), self); g_signal_connect(modem, NM_MODEM_PREPARE_RESULT, G_CALLBACK(modem_prepare_result), self); - g_signal_connect(modem, NM_MODEM_IP4_CONFIG_RESULT, G_CALLBACK(modem_ip4_config_result), self); - g_signal_connect(modem, NM_MODEM_IP6_CONFIG_RESULT, G_CALLBACK(modem_ip6_config_result), self); + g_signal_connect(modem, NM_MODEM_NEW_CONFIG, G_CALLBACK(modem_new_config), self); g_signal_connect(modem, NM_MODEM_AUTH_REQUESTED, G_CALLBACK(modem_auth_requested), self); g_signal_connect(modem, NM_MODEM_AUTH_RESULT, G_CALLBACK(modem_auth_result), self); g_signal_connect(modem, NM_MODEM_STATE_CHANGED, G_CALLBACK(modem_state_cb), self); diff --git a/src/core/devices/wwan/nm-modem-broadband.c b/src/core/devices/wwan/nm-modem-broadband.c index 0872a8a1f9..8535909625 100644 --- a/src/core/devices/wwan/nm-modem-broadband.c +++ b/src/core/devices/wwan/nm-modem-broadband.c @@ -15,8 +15,7 @@ #include "NetworkManagerUtils.h" #include "devices/nm-device-private.h" #include "libnm-platform/nm-platform.h" -#include "nm-ip4-config.h" -#include "nm-ip6-config.h" +#include "nm-l3-config-data.h" #define NM_MODEM_BROADBAND_MODEM "modem" @@ -964,21 +963,23 @@ set_mm_enabled(NMModem *_self, gboolean enabled) /* IPv4 method static */ static gboolean -static_stage3_ip4_done(NMModemBroadband *self) +static_stage3_ip4_done(gpointer user_data) { - GError * error = NULL; - gs_unref_object NMIP4Config *config = NULL; - const char * data_port; - const char * address_string; - const char * gw_string; - guint32 address_network; - guint32 gw = 0; - NMPlatformIP4Address address; - const char ** dns; - guint i; - guint32 ip4_route_table, ip4_route_metric; - NMPlatformIP4Route * r; - guint32 mtu_n; + NMModemBroadband * self = user_data; + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + char sbuf[sizeof(_nm_utils_to_string_buffer)]; + gs_free_error GError *error = NULL; + const char * data_port; + const char * address_string; + const char * gw_string; + guint32 address_network; + guint32 gw = 0; + NMPlatformIP4Address address; + const char ** dns; + int ifindex; + guint i; + NMPlatformIP4Route route; + guint32 mtu_n; g_return_val_if_fail(self->_priv.ipv4_config, FALSE); g_return_val_if_fail(self->_priv.bearer, FALSE); @@ -991,58 +992,72 @@ static_stage3_ip4_done(NMModemBroadband *self) address_string = mm_bearer_ip_config_get_address(self->_priv.ipv4_config); if (!address_string || !nm_utils_parse_inaddr_bin(AF_INET, address_string, NULL, &address_network)) { - error = - g_error_new(NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "(%s) retrieving IP4 configuration failed: invalid address given %s%s%s", - nm_modem_get_uid(NM_MODEM(self)), - NM_PRINT_FMT_QUOTE_STRING(address_string)); + g_set_error(&error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_CONNECTION, + "(%s) retrieving IP4 configuration failed: invalid address given %s%s%s", + nm_modem_get_uid(NM_MODEM(self)), + NM_PRINT_FMT_QUOTE_STRING(address_string)); goto out; } /* Missing gateway not a hard failure */ gw_string = mm_bearer_ip_config_get_gateway(self->_priv.ipv4_config); if (gw_string && !nm_utils_parse_inaddr_bin(AF_INET, gw_string, NULL, &gw)) { - error = - g_error_new(NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "(%s) retrieving IP4 configuration failed: invalid gateway address \"%s\"", - nm_modem_get_uid(NM_MODEM(self)), - gw_string); + g_set_error(&error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_CONNECTION, + "(%s) retrieving IP4 configuration failed: invalid gateway address \"%s\"", + nm_modem_get_uid(NM_MODEM(self)), + gw_string); goto out; } data_port = mm_bearer_get_interface(self->_priv.bearer); g_return_val_if_fail(data_port, FALSE); - config = nm_ip4_config_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), - nm_platform_link_get_ifindex(NM_PLATFORM_GET, data_port)); - - memset(&address, 0, sizeof(address)); - address.address = address_network; - address.peer_address = address_network; - address.plen = mm_bearer_ip_config_get_prefix(self->_priv.ipv4_config); - address.addr_source = NM_IP_CONFIG_SOURCE_WWAN; + + ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, data_port); + if (ifindex <= 0) { + g_set_error(&error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_CONNECTION, + "(%s) data port %s not found", + nm_modem_get_uid(NM_MODEM(self)), + data_port); + goto out; + } + + l3cd = nm_l3_config_data_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), ifindex); + + nm_l3_config_data_set_source(l3cd, NM_IP_CONFIG_SOURCE_WWAN); + + address = (NMPlatformIP4Address){ + .address = address_network, + .peer_address = address_network, + .plen = mm_bearer_ip_config_get_prefix(self->_priv.ipv4_config), + .addr_source = NM_IP_CONFIG_SOURCE_WWAN, + }; if (address.plen <= 32) - nm_ip4_config_add_address(config, &address); + nm_l3_config_data_add_address_4(l3cd, &address); - _LOGI(" address %s/%d", address_string, address.plen); + _LOGI(" address %s", nm_platform_ip4_address_to_string(&address, sbuf, sizeof(sbuf))); - nm_modem_get_route_parameters(NM_MODEM(self), &ip4_route_table, &ip4_route_metric, NULL, NULL); - r = &(NMPlatformIP4Route){ + route = (NMPlatformIP4Route){ .rt_source = NM_IP_CONFIG_SOURCE_WWAN, .gateway = gw, - .table_coerced = nm_platform_route_table_coerce(ip4_route_table), - .metric = ip4_route_metric, + .table_any = TRUE, + .table_coerced = 0, + .metric_any = TRUE, + .metric = 0, }; - nm_ip4_config_add_route(config, r, NULL); + nm_l3_config_data_add_route_4(l3cd, &route); _LOGI(" gateway %s", gw_string); - /* DNS servers */ dns = mm_bearer_ip_config_get_dns(self->_priv.ipv4_config); for (i = 0; dns && dns[i]; i++) { if (nm_utils_parse_inaddr_bin(AF_INET, dns[i], NULL, &address_network) && address_network > 0) { - nm_ip4_config_add_nameserver(config, address_network); + nm_l3_config_data_add_nameserver(l3cd, AF_INET, &address_network); _LOGI(" DNS %s", dns[i]); } } @@ -1050,15 +1065,17 @@ static_stage3_ip4_done(NMModemBroadband *self) #if MM_CHECK_VERSION(1, 4, 0) mtu_n = mm_bearer_ip_config_get_mtu(self->_priv.ipv4_config); if (mtu_n) { - nm_ip4_config_set_mtu(config, mtu_n, NM_IP_CONFIG_SOURCE_WWAN); + nm_l3_config_data_set_mtu(l3cd, mtu_n); _LOGI(" MTU %u", mtu_n); } #endif out: - g_signal_emit_by_name(self, NM_MODEM_IP4_CONFIG_RESULT, config, error); - g_clear_error(&error); - return FALSE; + if (error) + nm_clear_l3cd(&l3cd); + + nm_modem_emit_signal_new_config(NM_MODEM(self), AF_INET, l3cd, FALSE, NULL, error); + return G_SOURCE_REMOVE; } static NMActStageReturn @@ -1072,8 +1089,7 @@ static_stage3_ip4_config_start(NMModem * modem, /* We schedule it in an idle just to follow the same logic as in the * generic modem implementation. */ nm_clear_g_source(&priv->idle_id_ip4); - priv->idle_id_ip4 = g_idle_add((GSourceFunc) static_stage3_ip4_done, self); - + priv->idle_id_ip4 = g_idle_add(static_stage3_ip4_done, self); return NM_ACT_STAGE_RETURN_POSTPONE; } @@ -1081,21 +1097,26 @@ static_stage3_ip4_config_start(NMModem * modem, /* IPv6 method static */ static gboolean -stage3_ip6_done(NMModemBroadband *self) +stage3_ip6_done(gpointer user_data) { - GError * error = NULL; - NMIP6Config * config = NULL; - const char * data_port; - const char * address_string; - NMPlatformIP6Address address; - NMModemIPMethod ip_method; - const char ** dns; - guint i; - - g_return_val_if_fail(self->_priv.ipv6_config, FALSE); + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + char sbuf[sizeof(_nm_utils_to_string_buffer)]; + NMModemBroadband * self = user_data; + gs_free_error GError * error = NULL; + const char * data_port; + const char * address_string; + NMPlatformIP6Address address; + NMModemIPMethod ip_method; + const char ** dns; + guint i; + gboolean do_slaac = TRUE; + int ifindex; + NMUtilsIPv6IfaceId iid_data; + const NMUtilsIPv6IfaceId *iid = NULL; + + g_return_val_if_fail(self->_priv.ipv6_config, G_SOURCE_REMOVE); self->_priv.idle_id_ip6 = 0; - memset(&address, 0, sizeof(address)); ip_method = get_bearer_ip_method(self->_priv.ipv6_config); @@ -1103,93 +1124,112 @@ stage3_ip6_done(NMModemBroadband *self) if (!address_string) { /* DHCP/SLAAC is allowed to skip addresses; other methods require it */ if (ip_method != NM_MODEM_IP_METHOD_AUTO) { - error = g_error_new(NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "(%s) retrieving IPv6 configuration failed: no address given", - nm_modem_get_uid(NM_MODEM(self))); + g_set_error(&error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_CONNECTION, + "(%s) retrieving IPv6 configuration failed: no address given", + nm_modem_get_uid(NM_MODEM(self))); } goto out; } - /* Fail if invalid IP address retrieved */ - if (!inet_pton(AF_INET6, address_string, (void *) &(address.address))) { - error = g_error_new(NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "(%s) retrieving IPv6 configuration failed: invalid address given '%s'", - nm_modem_get_uid(NM_MODEM(self)), - address_string); + address = (NMPlatformIP6Address){}; + + if (!inet_pton(AF_INET6, address_string, &address.address)) { + g_set_error(&error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_CONNECTION, + "(%s) retrieving IPv6 configuration failed: invalid address given '%s'", + nm_modem_get_uid(NM_MODEM(self)), + address_string); goto out; } - _LOGI("IPv6 base configuration:"); - data_port = mm_bearer_get_interface(self->_priv.bearer); - g_return_val_if_fail(data_port, FALSE); + g_return_val_if_fail(data_port, G_SOURCE_REMOVE); + + ifindex = nm_platform_link_get_ifindex(NM_PLATFORM_GET, data_port); + if (ifindex <= 0) { + g_set_error(&error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_CONNECTION, + "(%s) data port %s not found", + nm_modem_get_uid(NM_MODEM(self)), + data_port); + goto out; + } + + _LOGI("IPv6 base configuration:"); - config = nm_ip6_config_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), - nm_platform_link_get_ifindex(NM_PLATFORM_GET, data_port)); + l3cd = nm_l3_config_data_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), ifindex); address.plen = mm_bearer_ip_config_get_prefix(self->_priv.ipv6_config); - if (address.plen <= 128) - nm_ip6_config_add_address(config, &address); + if (address.plen <= 128) { + if (IN6_IS_ADDR_LINKLOCAL(&address.address)) { + iid_data.id = ((guint64 *) (&address.address.s6_addr))[1]; + iid = &iid_data; + } else + do_slaac = FALSE; + nm_l3_config_data_add_address_6(l3cd, &address); + } - _LOGI(" address %s/%d", address_string, address.plen); + _LOGI(" address %s (slaac %s)", + nm_platform_ip6_address_to_string(&address, sbuf, sizeof(sbuf)), + do_slaac ? "enabled" : "disabled"); address_string = mm_bearer_ip_config_get_gateway(self->_priv.ipv6_config); if (address_string) { - guint32 ip6_route_table, ip6_route_metric; - if (inet_pton(AF_INET6, address_string, &address.address) != 1) { - error = - g_error_new(NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "(%s) retrieving IPv6 configuration failed: invalid gateway given '%s'", - nm_modem_get_uid(NM_MODEM(self)), - address_string); + g_set_error(&error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_CONNECTION, + "(%s) retrieving IPv6 configuration failed: invalid gateway given '%s'", + nm_modem_get_uid(NM_MODEM(self)), + address_string); goto out; } - nm_modem_get_route_parameters(NM_MODEM(self), - NULL, - NULL, - &ip6_route_table, - &ip6_route_metric); { const NMPlatformIP6Route r = { .rt_source = NM_IP_CONFIG_SOURCE_WWAN, .gateway = address.address, - .table_coerced = nm_platform_route_table_coerce(ip6_route_table), - .metric = ip6_route_metric, + .table_any = TRUE, + .table_coerced = 0, + .metric_any = TRUE, + .metric = 0, }; _LOGI(" gateway %s", address_string); - nm_ip6_config_add_route(config, &r, NULL); + nm_l3_config_data_add_route_6(l3cd, &r); } } else if (ip_method == NM_MODEM_IP_METHOD_STATIC) { /* Gateway required for the 'static' method */ - error = g_error_new(NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "(%s) retrieving IPv6 configuration failed: missing gateway", - nm_modem_get_uid(NM_MODEM(self))); + g_set_error(&error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_CONNECTION, + "(%s) retrieving IPv6 configuration failed: missing gateway", + nm_modem_get_uid(NM_MODEM(self))); goto out; } - /* DNS servers */ dns = mm_bearer_ip_config_get_dns(self->_priv.ipv6_config); for (i = 0; dns && dns[i]; i++) { struct in6_addr addr; if (inet_pton(AF_INET6, dns[i], &addr)) { - nm_ip6_config_add_nameserver(config, &addr); + nm_l3_config_data_add_nameserver(l3cd, AF_INET6, &addr); _LOGI(" DNS %s", dns[i]); } } out: - nm_modem_emit_ip6_config_result(NM_MODEM(self), config, error); - g_clear_object(&config); - g_clear_error(&error); - return FALSE; + if (error) { + nm_clear_l3cd(&l3cd); + do_slaac = FALSE; + iid = NULL; + } + nm_modem_emit_signal_new_config(NM_MODEM(self), AF_INET6, l3cd, do_slaac, iid, error); + return G_SOURCE_REMOVE; } static NMActStageReturn @@ -1201,7 +1241,7 @@ stage3_ip6_config_request(NMModem *modem, NMDeviceStateReason *out_failure_reaso /* We schedule it in an idle just to follow the same logic as in the * generic modem implementation. */ nm_clear_g_source(&priv->idle_id_ip6); - priv->idle_id_ip6 = g_idle_add((GSourceFunc) stage3_ip6_done, self); + priv->idle_id_ip6 = g_idle_add(stage3_ip6_done, self); return NM_ACT_STAGE_RETURN_POSTPONE; } diff --git a/src/core/devices/wwan/nm-modem-ofono.c b/src/core/devices/wwan/nm-modem-ofono.c index 78ad7b6820..d31325d1f1 100644 --- a/src/core/devices/wwan/nm-modem-ofono.c +++ b/src/core/devices/wwan/nm-modem-ofono.c @@ -11,7 +11,7 @@ #include "devices/nm-device-private.h" #include "nm-modem.h" #include "libnm-platform/nm-platform.h" -#include "nm-ip4-config.h" +#include "nm-l3-config-data.h" #define VARIANT_IS_OF_TYPE_BOOLEAN(v) \ ((v) != NULL && (g_variant_is_of_type((v), G_VARIANT_TYPE_BOOLEAN))) @@ -47,7 +47,7 @@ typedef struct { gboolean modem_online; gboolean gprs_attached; - NMIP4Config *ip4_config; + NML3ConfigData *l3cd_4; } NMModemOfonoPrivate; struct _NMModemOfono { @@ -240,7 +240,7 @@ deactivate_cleanup(NMModem *modem, NMDevice *device, gboolean stop_ppp_manager) /* TODO: cancel SimpleConnect() if any */ - g_clear_object(&priv->ip4_config); + nm_clear_l3cd(&priv->l3cd_4); NM_MODEM_CLASS(nm_modem_ofono_parent_class) ->deactivate_cleanup(modem, device, stop_ppp_manager); @@ -734,13 +734,13 @@ 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; + char sbuf[sizeof(_nm_utils_to_string_buffer)]; + NMPlatformIP4Address address; gboolean ret = FALSE; const char * interface; const char * s; - const char ** array, **iter; + const char ** array; guint32 address_network, gateway_network; - guint32 ip4_route_table, ip4_route_metric; int ifindex; GError * error = NULL; @@ -773,12 +773,13 @@ handle_settings(GVariant *v_dict, gpointer user_data) } ifindex = nm_modem_get_ip_ifindex(NM_MODEM(self)); - nm_assert(ifindex > 0); + g_return_if_fail(ifindex > 0); - /* TODO: verify handling of ip4_config; check other places it's used... */ - g_clear_object(&priv->ip4_config); + /* TODO: verify handling of l3cd_4; check other places it's used... */ + nm_clear_l3cd(&priv->l3cd_4); - priv->ip4_config = nm_ip4_config_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), ifindex); + priv->l3cd_4 = nm_l3_config_data_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), ifindex); + nm_l3_config_data_set_source(priv->l3cd_4, NM_IP_CONFIG_SOURCE_WWAN); if (!g_variant_lookup(v_dict, "Address", "&s", &s)) { _LOGW("Settings 'Address' missing"); @@ -788,10 +789,12 @@ handle_settings(GVariant *v_dict, gpointer user_data) _LOGW("can't convert 'Address' %s to addr", s ?: ""); goto out; } - memset(&addr, 0, sizeof(addr)); - addr.ifindex = ifindex; - addr.address = address_network; - addr.addr_source = NM_IP_CONFIG_SOURCE_WWAN; + + address = (NMPlatformIP4Address){ + .ifindex = ifindex, + .address = address_network, + .addr_source = NM_IP_CONFIG_SOURCE_WWAN, + }; if (!g_variant_lookup(v_dict, "Netmask", "&s", &s)) { _LOGW("Settings 'Netmask' missing"); @@ -801,10 +804,10 @@ handle_settings(GVariant *v_dict, gpointer user_data) _LOGW("invalid 'Netmask': %s", s ?: ""); goto out; } - addr.plen = nm_utils_ip4_netmask_to_prefix(address_network); + address.plen = nm_utils_ip4_netmask_to_prefix(address_network); - _LOGI("Address: %s", nm_platform_ip4_address_to_string(&addr, NULL, 0)); - nm_ip4_config_add_address(priv->ip4_config, &addr); + _LOGI("Address: %s", nm_platform_ip4_address_to_string(&address, sbuf, sizeof(sbuf))); + nm_l3_config_data_add_address_4(priv->l3cd_4, &address); if (!g_variant_lookup(v_dict, "Gateway", "&s", &s) || !s) { _LOGW("Settings 'Gateway' missing"); @@ -814,17 +817,18 @@ handle_settings(GVariant *v_dict, gpointer user_data) _LOGW("invalid 'Gateway': %s", s); goto out; } - nm_modem_get_route_parameters(NM_MODEM(self), &ip4_route_table, &ip4_route_metric, NULL, NULL); { const NMPlatformIP4Route r = { .rt_source = NM_IP_CONFIG_SOURCE_WWAN, .gateway = gateway_network, - .table_coerced = nm_platform_route_table_coerce(ip4_route_table), - .metric = ip4_route_metric, + .table_any = TRUE, + .table_coerced = 0, + .metric_any = TRUE, + .metric = 0, }; _LOGI("Gateway: %s", s); - nm_ip4_config_add_route(priv->ip4_config, &r, NULL); + nm_l3_config_data_add_route_4(priv->l3cd_4, &r); } if (!g_variant_lookup(v_dict, "DomainNameServers", "^a&s", &array)) { @@ -832,52 +836,49 @@ handle_settings(GVariant *v_dict, gpointer user_data) goto out; } if (array) { - for (iter = array; *iter; iter++) { - if (nm_utils_parse_inaddr_bin(AF_INET, *iter, NULL, &address_network) - && address_network) { - _LOGI("DNS: %s", *iter); - nm_ip4_config_add_nameserver(priv->ip4_config, address_network); - } else { - _LOGW("invalid NameServer: %s", *iter); + gs_free const char **array_free = array; + gboolean any_good = FALSE; + + for (; array[0]; array++) { + if (!nm_utils_parse_inaddr_bin(AF_INET, *array, NULL, &address_network) + || !address_network) { + _LOGW("invalid NameServer: %s", *array); + continue; } + any_good = TRUE; + _LOGI("DNS: %s", *array); + nm_l3_config_data_add_nameserver(priv->l3cd_4, AF_INET, &address_network); } - - if (iter == array) { + if (!any_good) { _LOGW("Settings: 'DomainNameServers': none specified"); - g_free(array); goto out; } - g_free(array); } if (g_variant_lookup(v_dict, "MessageProxy", "&s", &s)) { _LOGI("MessageProxy: %s", s); if (s && nm_utils_parse_inaddr_bin(AF_INET, s, NULL, &address_network)) { - nm_modem_get_route_parameters(NM_MODEM(self), - &ip4_route_table, - &ip4_route_metric, - NULL, - NULL); - - { - const NMPlatformIP4Route mms_route = { - .network = address_network, - .plen = 32, - .gateway = gateway_network, - .table_coerced = nm_platform_route_table_coerce(ip4_route_table), - .metric = ip4_route_metric, - }; - - nm_ip4_config_add_route(priv->ip4_config, &mms_route, NULL); - } - } else { + const NMPlatformIP4Route mms_route = { + .network = address_network, + .plen = 32, + .gateway = gateway_network, + .table_any = TRUE, + .table_coerced = 0, + .metric_any = TRUE, + .metric = 0, + }; + + nm_l3_config_data_add_route_4(priv->l3cd_4, &mms_route); + } else _LOGW("invalid MessageProxy: %s", s); - } } ret = TRUE; out: + if (priv->l3cd_4) + nm_l3_config_data_seal(priv->l3cd_4); + if (nm_modem_get_state(NM_MODEM(self)) != NM_MODEM_STATE_CONNECTED) { _LOGI("emitting PREPARE_RESULT: %s", ret ? "TRUE" : "FALSE"); nm_modem_emit_prepare_result(NM_MODEM(self), @@ -917,20 +918,19 @@ static_stage3_ip4_config_start(NMModem * modem, NMActRequest * req, NMDeviceStateReason *out_failure_reason) { - NMModemOfono * self = NM_MODEM_OFONO(modem); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - GError * error = NULL; + NMModemOfono * self = NM_MODEM_OFONO(modem); + NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - if (!priv->ip4_config) { + if (!priv->l3cd_4) { _LOGD("IP4 config not ready(?)"); return NM_ACT_STAGE_RETURN_FAILURE; } _LOGD("IP4 config is done; setting modem_state -> CONNECTED"); - g_signal_emit_by_name(self, NM_MODEM_IP4_CONFIG_RESULT, priv->ip4_config, error); - /* Signal listener takes ownership of the IP4Config */ - priv->ip4_config = NULL; + nm_modem_emit_signal_new_config(NM_MODEM(self), AF_INET, priv->l3cd_4, FALSE, NULL, NULL); + + nm_clear_l3cd(&priv->l3cd_4); nm_modem_set_state(NM_MODEM(self), NM_MODEM_STATE_CONNECTED, @@ -1040,7 +1040,7 @@ context_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) * clear it so that we can gate getting the IP config from oFono * on whether or not we have already received them */ - g_clear_object(&priv->ip4_config); + nm_clear_l3cd(&priv->l3cd_4); /* We need to directly query ConnectionContextinteface to get the current * property values */ @@ -1258,7 +1258,7 @@ dispose(GObject *object) priv->connect_properties = NULL; } - g_clear_object(&priv->ip4_config); + nm_clear_l3cd(&priv->l3cd_4); if (priv->modem_proxy) { g_signal_handlers_disconnect_by_data(priv->modem_proxy, self); diff --git a/src/core/devices/wwan/nm-modem.c b/src/core/devices/wwan/nm-modem.c index 15baa677ca..397c2f580b 100644 --- a/src/core/devices/wwan/nm-modem.c +++ b/src/core/devices/wwan/nm-modem.c @@ -20,8 +20,7 @@ #include "devices/nm-device-private.h" #include "nm-netns.h" #include "nm-act-request.h" -#include "nm-ip4-config.h" -#include "nm-ip6-config.h" +#include "nm-l3-config-data.h" #include "ppp/nm-ppp-manager-call.h" #include "ppp/nm-ppp-status.h" @@ -45,8 +44,7 @@ enum { PPP_STATS, PPP_FAILED, PREPARE_RESULT, - IP4_CONFIG_RESULT, - IP6_CONFIG_RESULT, + NEW_CONFIG, AUTH_REQUESTED, AUTH_RESULT, REMOVED, @@ -67,18 +65,17 @@ typedef struct _NMModemPrivate { * We should rework the code that it's not necessary */ char *ip_iface; - int ip_ifindex; - NMModemIPMethod ip4_method; - NMModemIPMethod ip6_method; - NMUtilsIPv6IfaceId iid; - NMModemState state; - NMModemState prev_state; /* revert to this state if enable/disable fails */ - char * device_id; - char * sim_id; - NMModemIPType ip_types; - char * sim_operator_id; - char * operator_code; - char * apn; + int ip_ifindex; + NMModemIPMethod ip4_method; + NMModemIPMethod ip6_method; + NMModemState state; + NMModemState prev_state; /* revert to this state if enable/disable fails */ + char * device_id; + char * sim_id; + NMModemIPType ip_types; + char * sim_operator_id; + char * operator_code; + char * apn; NMPPPManager *ppp_manager; @@ -88,11 +85,6 @@ typedef struct _NMModemPrivate { guint mm_ip_timeout; - guint32 ip4_route_table; - guint32 ip4_route_metric; - guint32 ip6_route_table; - guint32 ip6_route_metric; - /* PPP stats */ guint32 in_bytes; guint32 out_bytes; @@ -180,6 +172,41 @@ nm_modem_state_to_string(NMModemState state) /*****************************************************************************/ +void +nm_modem_emit_signal_new_config(NMModem * self, + int addr_family, + const NML3ConfigData * l3cd, + gboolean do_slaac, + const NMUtilsIPv6IfaceId *iid, + GError * error) +{ + nm_assert(NM_IS_MODEM(self)); + nm_assert_addr_family(addr_family); + nm_assert(!l3cd || NM_IS_L3_CONFIG_DATA(l3cd)); + nm_assert(!do_slaac || addr_family == AF_INET6); + nm_assert(!iid || addr_family == AF_INET6); + nm_assert(!error || (!l3cd && !do_slaac && !iid)); + + if (error) { + do_slaac = FALSE; + l3cd = NULL; + iid = NULL; + goto out_emit; + } + + if (addr_family == AF_INET6) { + do_slaac = !!do_slaac; + } else { + iid = NULL; + do_slaac = FALSE; + } + if (l3cd) + nm_l3_config_data_seal(l3cd); + +out_emit: + g_signal_emit(self, signals[NEW_CONFIG], 0, addr_family, l3cd, do_slaac, iid, error); +} + gboolean nm_modem_is_claimed(NMModem *self) { @@ -523,66 +550,73 @@ ppp_ifindex_set(NMPPPManager *ppp_manager, int ifindex, const char *iface, gpoin } static void -ppp_ip4_config(NMPPPManager *ppp_manager, NMIP4Config *config, gpointer user_data) +ppp_new_config(NMPPPManager * ppp_manager, + int addr_family, + const NML3ConfigData * l3cd, + const NMUtilsIPv6IfaceId *iid, + gpointer user_data) { - NMModem *self = NM_MODEM(user_data); - guint32 i, num; - guint32 bad_dns1 = htonl(0x0A0B0C0D); - guint32 good_dns1 = htonl(0x04020201); /* GTE nameserver */ - guint32 bad_dns2 = htonl(0x0A0B0C0E); - guint32 good_dns2 = htonl(0x04020202); /* GTE nameserver */ - gboolean dns_workaround = FALSE; - - /* Work around a PPP bug (#1732) which causes many mobile broadband - * providers to return 10.11.12.13 and 10.11.12.14 for the DNS servers. - * Apparently fixed in ppp-2.4.5 but we've had some reports that this is - * not the case. - * - * http://git.ozlabs.org/?p=ppp.git;a=commitdiff_plain;h=2e09ef6886bbf00bc5a9a641110f801e372ffde6 - * http://git.ozlabs.org/?p=ppp.git;a=commitdiff_plain;h=f8191bf07df374f119a07910a79217c7618f113e - */ - - num = nm_ip4_config_get_num_nameservers(config); - if (num == 2) { - gboolean found1 = FALSE, found2 = FALSE; + nm_auto_unref_l3cd_init NML3ConfigData *l3cd_modified = NULL; + NMModem * self = NM_MODEM(user_data); + gboolean do_slaac = FALSE; - for (i = 0; i < num; i++) { - guint32 ns = nm_ip4_config_get_nameserver(config, i); + nm_assert_addr_family(addr_family); - if (ns == bad_dns1) - found1 = TRUE; - else if (ns == bad_dns2) - found2 = TRUE; + if (addr_family == AF_INET6) { + if (!l3cd) + do_slaac = TRUE; + else { + do_slaac = !!nm_l3_config_data_get_first_obj(l3cd, + NMP_OBJECT_TYPE_IP6_ADDRESS, + nmp_object_ip6_address_is_not_link_local); + } + } else { + nm_assert(!iid); + iid = NULL; + + if (l3cd) { + const in_addr_t bad_dns1 = htonl(0x0A0B0C0D); + const in_addr_t good_dns1 = htonl(0x04020201); /* GTE nameserver */ + const in_addr_t bad_dns2 = htonl(0x0A0B0C0E); + const in_addr_t good_dns2 = htonl(0x04020202); /* GTE nameserver */ + gboolean dns_workaround = FALSE; + const in_addr_t *addrs; + guint num; + + /* Work around a PPP bug (#1732) which causes many mobile broadband + * providers to return 10.11.12.13 and 10.11.12.14 for the DNS servers. + * Apparently fixed in ppp-2.4.5 but we've had some reports that this is + * not the case. + * + * http://git.ozlabs.org/?p=ppp.git;a=commitdiff_plain;h=2e09ef6886bbf00bc5a9a641110f801e372ffde6 + * http://git.ozlabs.org/?p=ppp.git;a=commitdiff_plain;h=f8191bf07df374f119a07910a79217c7618f113e + */ + + addrs = nm_l3_config_data_get_nameservers(l3cd, AF_INET, &num); + if (num == 0) + dns_workaround = TRUE; + else if (num == 2) { + /* Be somewhat conservative about substitutions; the "bad" nameservers + * could actually be valid in some cases, so only substitute if ppp + * returns *only* the two bad nameservers. + */ + dns_workaround = (addrs[0] == bad_dns1 && addrs[1] == bad_dns2) + || (addrs[1] == bad_dns1 && addrs[0] == bad_dns2); + } else + dns_workaround = FALSE; + + if (dns_workaround) { + _LOGW("compensating for invalid PPP-provided nameservers"); + l3cd_modified = nm_l3_config_data_new_clone(l3cd, 0); + nm_l3_config_data_clear_nameservers(l3cd_modified, AF_INET); + nm_l3_config_data_add_nameserver(l3cd_modified, AF_INET, &good_dns1); + nm_l3_config_data_add_nameserver(l3cd_modified, AF_INET, &good_dns2); + l3cd = nm_l3_config_data_seal(l3cd_modified); + } } - - /* Be somewhat conservative about substitutions; the "bad" nameservers - * could actually be valid in some cases, so only substitute if ppp - * returns *only* the two bad nameservers. - */ - dns_workaround = (found1 && found2); - } - - if (!num || dns_workaround) { - _LOGW("compensating for invalid PPP-provided nameservers"); - nm_ip4_config_reset_nameservers(config); - nm_ip4_config_add_nameserver(config, good_dns1); - nm_ip4_config_add_nameserver(config, good_dns2); } - g_signal_emit(self, signals[IP4_CONFIG_RESULT], 0, config, NULL); -} - -static void -ppp_ip6_config(NMPPPManager * ppp_manager, - const NMUtilsIPv6IfaceId *iid, - NMIP6Config * config, - gpointer user_data) -{ - NMModem *self = NM_MODEM(user_data); - - NM_MODEM_GET_PRIVATE(self)->iid = *iid; - - nm_modem_emit_ip6_config_result(self, config, NULL); + nm_modem_emit_signal_new_config(self, addr_family, l3cd, do_slaac, iid, NULL); } static void @@ -679,14 +713,6 @@ ppp_stage3_ip_config_start(NMModem * self, priv->ppp_manager = nm_ppp_manager_create(priv->data_port, &error); - if (priv->ppp_manager) { - nm_ppp_manager_set_route_parameters(priv->ppp_manager, - priv->ip4_route_table, - priv->ip4_route_metric, - priv->ip6_route_table, - priv->ip6_route_metric); - } - if (!priv->ppp_manager || !nm_ppp_manager_start(priv->ppp_manager, req, @@ -710,12 +736,8 @@ ppp_stage3_ip_config_start(NMModem * self, G_CALLBACK(ppp_ifindex_set), self); g_signal_connect(priv->ppp_manager, - NM_PPP_MANAGER_SIGNAL_IP4_CONFIG, - G_CALLBACK(ppp_ip4_config), - self); - g_signal_connect(priv->ppp_manager, - NM_PPP_MANAGER_SIGNAL_IP6_CONFIG, - G_CALLBACK(ppp_ip6_config), + NM_PPP_MANAGER_SIGNAL_NEW_CONFIG, + G_CALLBACK(ppp_new_config), self); g_signal_connect(priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_STATS, G_CALLBACK(ppp_stats), self); @@ -748,8 +770,6 @@ nm_modem_stage3_ip4_config_start(NMModem * self, connection = nm_act_request_get_applied_connection(req); g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE); - nm_modem_set_route_parameters_from_device(self, device); - method = nm_utils_get_ip_config_method(connection, AF_INET); /* Only Disabled and Auto methods make sense for WWAN */ @@ -786,9 +806,11 @@ nm_modem_stage3_ip4_config_start(NMModem * self, } void -nm_modem_ip4_pre_commit(NMModem *modem, NMDevice *device, NMIP4Config *config) +nm_modem_ip4_pre_commit(NMModem *modem, NMDevice *device) { - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(modem); + //XXX +#if 0 + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (modem); /* If the modem has an ethernet-type data interface (ie, not PPP and thus * not point-to-point) and IP config has a /32 prefix, then we assume that @@ -805,40 +827,11 @@ nm_modem_ip4_pre_commit(NMModem *modem, NMDevice *device, NMIP4Config *config) IFF_NOARP, TRUE); } +#endif } /*****************************************************************************/ -void -nm_modem_emit_ip6_config_result(NMModem *self, NMIP6Config *config, GError *error) -{ - NMModemPrivate * priv = NM_MODEM_GET_PRIVATE(self); - NMDedupMultiIter ipconf_iter; - const NMPlatformIP6Address *addr; - gboolean do_slaac = TRUE; - - if (error) { - g_signal_emit(self, signals[IP6_CONFIG_RESULT], 0, NULL, FALSE, error); - return; - } - - if (config) { - /* If the IPv6 configuration only included a Link-Local address, then - * we have to run SLAAC to get the full IPv6 configuration. - */ - nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, config, &addr) { - if (IN6_IS_ADDR_LINKLOCAL(&addr->address)) { - if (!priv->iid.id) - priv->iid.id = ((guint64 *) (&addr->address.s6_addr))[1]; - } else - do_slaac = FALSE; - } - } - g_assert(config || do_slaac); - - g_signal_emit(self, signals[IP6_CONFIG_RESULT], 0, config, do_slaac, NULL); -} - static NMActStageReturn stage3_ip6_config_request(NMModem *self, NMDeviceStateReason *out_failure_reason) { @@ -865,8 +858,6 @@ nm_modem_stage3_ip6_config_start(NMModem * self, connection = nm_act_request_get_applied_connection(req); g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE); - nm_modem_set_route_parameters_from_device(self, device); - method = nm_utils_get_ip_config_method(connection, AF_INET6); /* Only Ignore, Disabled and Auto methods make sense for WWAN */ @@ -1539,82 +1530,6 @@ nm_modem_owns_port(NMModem *self, const char *iface) return NM_IN_STRSET(iface, priv->ip_iface, priv->data_port, priv->control_port); } -gboolean -nm_modem_get_iid(NMModem *self, NMUtilsIPv6IfaceId *out_iid) -{ - g_return_val_if_fail(NM_IS_MODEM(self), FALSE); - - *out_iid = NM_MODEM_GET_PRIVATE(self)->iid; - return TRUE; -} - -/*****************************************************************************/ - -void -nm_modem_get_route_parameters(NMModem *self, - guint32 *out_ip4_route_table, - guint32 *out_ip4_route_metric, - guint32 *out_ip6_route_table, - guint32 *out_ip6_route_metric) -{ - NMModemPrivate *priv; - - g_return_if_fail(NM_IS_MODEM(self)); - - priv = NM_MODEM_GET_PRIVATE(self); - NM_SET_OUT(out_ip4_route_table, priv->ip4_route_table); - NM_SET_OUT(out_ip4_route_metric, priv->ip4_route_metric); - NM_SET_OUT(out_ip6_route_table, priv->ip6_route_table); - NM_SET_OUT(out_ip6_route_metric, priv->ip6_route_metric); -} - -void -nm_modem_set_route_parameters(NMModem *self, - guint32 ip4_route_table, - guint32 ip4_route_metric, - guint32 ip6_route_table, - guint32 ip6_route_metric) -{ - NMModemPrivate *priv; - - g_return_if_fail(NM_IS_MODEM(self)); - - priv = NM_MODEM_GET_PRIVATE(self); - if (priv->ip4_route_table != ip4_route_table || priv->ip4_route_metric != ip4_route_metric - || priv->ip6_route_table != ip6_route_table || priv->ip6_route_metric != ip6_route_metric) { - priv->ip4_route_table = ip4_route_table; - priv->ip4_route_metric = ip4_route_metric; - priv->ip6_route_table = ip6_route_table; - priv->ip6_route_metric = ip6_route_metric; - - _LOGT("route-parameters: table-v4: %u, metric-v4: %u, table-v6: %u, metric-v6: %u", - priv->ip4_route_table, - priv->ip4_route_metric, - priv->ip6_route_table, - priv->ip6_route_metric); - } - - if (priv->ppp_manager) { - nm_ppp_manager_set_route_parameters(priv->ppp_manager, - priv->ip4_route_table, - priv->ip4_route_metric, - priv->ip6_route_table, - priv->ip6_route_metric); - } -} - -void -nm_modem_set_route_parameters_from_device(NMModem *self, NMDevice *device) -{ - g_return_if_fail(NM_IS_DEVICE(device)); - - nm_modem_set_route_parameters(self, - nm_device_get_route_table(device, AF_INET), - nm_device_get_route_metric(device, AF_INET), - nm_device_get_route_table(device, AF_INET6), - nm_device_get_route_metric(device, AF_INET6)); -} - /*****************************************************************************/ void @@ -1767,11 +1682,7 @@ nm_modem_init(NMModem *self) self->_priv = G_TYPE_INSTANCE_GET_PRIVATE(self, NM_TYPE_MODEM, NMModemPrivate); priv = self->_priv; - priv->ip_ifindex = -1; - priv->ip4_route_table = RT_TABLE_MAIN; - priv->ip4_route_metric = 700; - priv->ip6_route_table = RT_TABLE_MAIN; - priv->ip6_route_metric = 700; + priv->ip_ifindex = -1; } static void @@ -1945,43 +1856,27 @@ nm_modem_class_init(NMModemClass *klass) 1, G_TYPE_UINT); - signals[IP4_CONFIG_RESULT] = g_signal_new(NM_MODEM_IP4_CONFIG_RESULT, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 2, - G_TYPE_OBJECT, - G_TYPE_POINTER); - - /** - * NMModem::ip6-config-result: - * @modem: the #NMModem on which the signal is emitted - * @config: the #NMIP6Config to apply to the modem's data port - * @do_slaac: %TRUE if IPv6 SLAAC should be started - * @error: a #GError if any error occurred during IP configuration - * - * This signal is emitted when IPv6 configuration has completed or failed. - * If @error is set the configuration failed. If @config is set, then + /* + * This signal is emitted when IP configuration has completed or failed. + * If @error is set the configuration failed. If @l3cd is set, then * the details should be applied to the data port before any further - * configuration (like SLAAC) is done. @do_slaac indicates whether SLAAC - * should be started after applying @config to the data port. + * configuration (like SLAAC) is done. @do_slaac indicates whether SLAAC + * should be started after applying @l3cd to the data port. */ - signals[IP6_CONFIG_RESULT] = g_signal_new(NM_MODEM_IP6_CONFIG_RESULT, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 3, - G_TYPE_OBJECT, - G_TYPE_BOOLEAN, - G_TYPE_POINTER); + signals[NEW_CONFIG] = g_signal_new(NM_MODEM_NEW_CONFIG, + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 3, + G_TYPE_INT, /* int addr_family */ + G_TYPE_POINTER, /* const NML3ConfigData *l3cd */ + G_TYPE_BOOLEAN, /* gboolean do_slaac */ + G_TYPE_POINTER, /* const NMUtilsIPv6IfaceId *iid */ + G_TYPE_POINTER); /* GError *error */ signals[PREPARE_RESULT] = g_signal_new(NM_MODEM_PREPARE_RESULT, G_OBJECT_CLASS_TYPE(object_class), diff --git a/src/core/devices/wwan/nm-modem.h b/src/core/devices/wwan/nm-modem.h index 87162cfca7..95f66a8d6e 100644 --- a/src/core/devices/wwan/nm-modem.h +++ b/src/core/devices/wwan/nm-modem.h @@ -32,15 +32,14 @@ #define NM_MODEM_APN "apn" /* Signals */ -#define NM_MODEM_PPP_STATS "ppp-stats" -#define NM_MODEM_PPP_FAILED "ppp-failed" -#define NM_MODEM_PREPARE_RESULT "prepare-result" -#define NM_MODEM_IP4_CONFIG_RESULT "ip4-config-result" -#define NM_MODEM_IP6_CONFIG_RESULT "ip6-config-result" -#define NM_MODEM_AUTH_REQUESTED "auth-requested" -#define NM_MODEM_AUTH_RESULT "auth-result" -#define NM_MODEM_REMOVED "removed" -#define NM_MODEM_STATE_CHANGED "state-changed" +#define NM_MODEM_PPP_STATS "ppp-stats" +#define NM_MODEM_PPP_FAILED "ppp-failed" +#define NM_MODEM_PREPARE_RESULT "prepare-result" +#define NM_MODEM_NEW_CONFIG "new-config" +#define NM_MODEM_AUTH_REQUESTED "auth-requested" +#define NM_MODEM_AUTH_RESULT "auth-result" +#define NM_MODEM_REMOVED "removed" +#define NM_MODEM_STATE_CHANGED "state-changed" typedef enum { NM_MODEM_IP_METHOD_UNKNOWN = 0, @@ -161,7 +160,6 @@ const char *nm_modem_get_driver(NMModem *modem); const char *nm_modem_get_device_id(NMModem *modem); const char *nm_modem_get_sim_id(NMModem *modem); const char *nm_modem_get_sim_operator_id(NMModem *modem); -gboolean nm_modem_get_iid(NMModem *modem, NMUtilsIPv6IfaceId *out_iid); const char *nm_modem_get_operator_code(NMModem *modem); const char *nm_modem_get_apn(NMModem *modem); @@ -188,20 +186,6 @@ gboolean nm_modem_complete_connection(NMModem * self, NMConnection *const *existing_connections, GError ** error); -void nm_modem_get_route_parameters(NMModem *self, - guint32 *out_ip4_route_table, - guint32 *out_ip4_route_metric, - guint32 *out_ip6_route_table, - guint32 *out_ip6_route_metric); - -void nm_modem_set_route_parameters(NMModem *self, - guint32 ip4_route_table, - guint32 ip4_route_metric, - guint32 ip6_route_table, - guint32 ip6_route_metric); - -void nm_modem_set_route_parameters_from_device(NMModem *modem, NMDevice *device); - NMActStageReturn nm_modem_act_stage1_prepare(NMModem * modem, NMActRequest * req, NMDeviceStateReason *out_failure_reason); @@ -217,7 +201,7 @@ NMActStageReturn nm_modem_stage3_ip6_config_start(NMModem * modem, NMDevice * device, NMDeviceStateReason *out_failure_reason); -void nm_modem_ip4_pre_commit(NMModem *modem, NMDevice *device, NMIP4Config *config); +void nm_modem_ip4_pre_commit(NMModem *modem, NMDevice *device); void nm_modem_get_secrets(NMModem * modem, const char *setting_name, @@ -256,7 +240,13 @@ void nm_modem_emit_ppp_failed(NMModem *self, NMDeviceStateReason reason); GArray *nm_modem_get_connection_ip_type(NMModem *self, NMConnection *connection, GError **error); /* For subclasses */ -void nm_modem_emit_ip6_config_result(NMModem *self, NMIP6Config *config, GError *error); + +void nm_modem_emit_signal_new_config(NMModem * self, + int addr_family, + const NML3ConfigData * l3cd, + gboolean do_slaac, + const NMUtilsIPv6IfaceId *iid, + GError * error); const char *nm_modem_ip_type_to_string(NMModemIPType ip_type); diff --git a/src/core/dhcp/nm-dhcp-client.c b/src/core/dhcp/nm-dhcp-client.c index f35091d167..a274e2907b 100644 --- a/src/core/dhcp/nm-dhcp-client.c +++ b/src/core/dhcp/nm-dhcp-client.c @@ -20,6 +20,7 @@ #include "NetworkManagerUtils.h" #include "nm-utils.h" +#include "nm-l3-config-data.h" #include "nm-dhcp-utils.h" #include "nm-dhcp-options.h" #include "libnm-platform/nm-platform.h" @@ -41,8 +42,6 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMDhcpClient, PROP_IFACE, PROP_IFINDEX, PROP_MULTI_IDX, - PROP_ROUTE_METRIC, - PROP_ROUTE_TABLE, PROP_TIMEOUT, PROP_UUID, PROP_IAID, @@ -70,8 +69,6 @@ typedef struct _NMDhcpClientPrivate { guint watch_id; int addr_family; int ifindex; - guint32 route_table; - guint32 route_metric; guint32 timeout; guint32 iaid; NMDhcpState state; @@ -155,44 +152,6 @@ nm_dhcp_client_get_broadcast_hw_addr(NMDhcpClient *self) return NM_DHCP_CLIENT_GET_PRIVATE(self)->bcast_hwaddr; } -guint32 -nm_dhcp_client_get_route_table(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), RT_TABLE_MAIN); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->route_table; -} - -void -nm_dhcp_client_set_route_table(NMDhcpClient *self, guint32 route_table) -{ - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - if (route_table != priv->route_table) { - priv->route_table = route_table; - _notify(self, PROP_ROUTE_TABLE); - } -} - -guint32 -nm_dhcp_client_get_route_metric(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), G_MAXUINT32); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->route_metric; -} - -void -nm_dhcp_client_set_route_metric(NMDhcpClient *self, guint32 route_metric) -{ - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - if (route_metric != priv->route_metric) { - priv->route_metric = route_metric; - _notify(self, PROP_ROUTE_METRIC); - } -} - guint32 nm_dhcp_client_get_timeout(NMDhcpClient *self) { @@ -436,20 +395,22 @@ stop(NMDhcpClient *self, gboolean release) } void -nm_dhcp_client_set_state(NMDhcpClient *self, - NMDhcpState new_state, - NMIPConfig * ip_config, - GHashTable * options) +nm_dhcp_client_set_state(NMDhcpClient *self, NMDhcpState new_state, NML3ConfigData *l3cd) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + GHashTable * options; + + g_return_if_fail(NM_IS_DHCP_CLIENT(self)); if (NM_IN_SET(new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED)) { - g_return_if_fail(NM_IS_IP_CONFIG_ADDR_FAMILY(ip_config, priv->addr_family)); - g_return_if_fail(options); - } else { - g_return_if_fail(!ip_config); - g_return_if_fail(!options); - } + g_return_if_fail(NM_IS_L3_CONFIG_DATA(l3cd)); + g_return_if_fail( + nm_l3_config_data_get_dhcp_lease(l3cd, nm_dhcp_client_get_addr_family(self))); + } else + g_return_if_fail(!l3cd); + + if (l3cd) + nm_l3_config_data_seal(l3cd); if (new_state >= NM_DHCP_STATE_BOUND) timeout_cleanup(self); @@ -465,22 +426,31 @@ nm_dhcp_client_set_state(NMDhcpClient *self, && !NM_IN_SET(new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED)) return; - if (_LOGD_ENABLED()) { - gs_free const char **keys = NULL; - guint i, nkeys; + options = + l3cd ? nm_dhcp_lease_get_options(nm_l3_config_data_get_dhcp_lease(l3cd, priv->addr_family)) + : NULL; - keys = nm_utils_strdict_get_keys(options, TRUE, &nkeys); - for (i = 0; i < nkeys; i++) { - _LOGD("option %-20s => '%s'", keys[i], (char *) g_hash_table_lookup(options, keys[i])); - } - } + if (_LOGD_ENABLED()) { + if (options) { + gs_free const char **keys = NULL; + guint nkeys; + guint i; + + keys = nm_utils_strdict_get_keys(options, TRUE, &nkeys); + for (i = 0; i < nkeys; i++) { + _LOGD("option %-20s => '%s'", + keys[i], + (char *) g_hash_table_lookup(options, keys[i])); + } - if (_LOGT_ENABLED() && priv->addr_family == AF_INET6) { - gs_free char *event_id = NULL; + if (priv->addr_family == AF_INET6) { + gs_free char *event_id = NULL; - event_id = nm_dhcp_utils_get_dhcp6_event_id(options); - if (event_id) - _LOGT("event-id: \"%s\"", event_id); + event_id = nm_dhcp_utils_get_dhcp6_event_id(options); + if (event_id) + _LOGT("event-id: \"%s\"", event_id); + } + } } if (_LOGI_ENABLED()) { @@ -497,7 +467,7 @@ nm_dhcp_client_set_state(NMDhcpClient *self, } priv->state = new_state; - g_signal_emit(G_OBJECT(self), signals[SIGNAL_STATE_CHANGED], 0, new_state, ip_config, options); + g_signal_emit(G_OBJECT(self), signals[SIGNAL_STATE_CHANGED], 0, new_state, l3cd); } static gboolean @@ -508,7 +478,7 @@ transaction_timeout(gpointer user_data) priv->timeout_id = 0; _LOGW("request timed out"); - nm_dhcp_client_set_state(self, NM_DHCP_STATE_TIMEOUT, NULL, NULL); + nm_dhcp_client_set_state(self, NM_DHCP_STATE_TIMEOUT, NULL); return G_SOURCE_REMOVE; } @@ -534,7 +504,7 @@ daemon_watch_cb(GPid pid, int status, gpointer user_data) priv->pid = -1; - nm_dhcp_client_set_state(self, NM_DHCP_STATE_TERMINATED, NULL, NULL); + nm_dhcp_client_set_state(self, NM_DHCP_STATE_TERMINATED, NULL); } void @@ -750,7 +720,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_TERMINATED, NULL, NULL); + nm_dhcp_client_set_state(self, NM_DHCP_STATE_TERMINATED, NULL); } /*****************************************************************************/ @@ -874,12 +844,11 @@ nm_dhcp_client_handle_event(gpointer unused, const char * reason, NMDhcpClient *self) { - NMDhcpClientPrivate *priv; - guint32 old_state; - guint32 new_state; - gs_unref_hashtable GHashTable *str_options = NULL; - gs_unref_object NMIPConfig *ip_config = NULL; - NMPlatformIP6Address prefix = { + NMDhcpClientPrivate * priv; + guint32 old_state; + guint32 new_state; + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + NMPlatformIP6Address prefix = { 0, }; @@ -907,9 +876,10 @@ nm_dhcp_client_handle_event(gpointer unused, return TRUE; if (NM_IN_SET(new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED)) { - GVariantIter iter; - const char * name; - GVariant * value; + gs_unref_hashtable GHashTable *str_options = NULL; + GVariantIter iter; + const char * name; + GVariant * value; /* Copy options */ str_options = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_free); @@ -922,24 +892,27 @@ nm_dhcp_client_handle_event(gpointer unused, /* Create the IP config */ if (g_hash_table_size(str_options) > 0) { if (priv->addr_family == AF_INET) { - ip_config = NM_IP_CONFIG_CAST( - nm_dhcp_utils_ip4_config_from_options(nm_dhcp_client_get_multi_idx(self), - priv->ifindex, - priv->iface, - str_options, - priv->route_table, - priv->route_metric)); + l3cd = nm_dhcp_utils_ip4_config_from_options(nm_dhcp_client_get_multi_idx(self), + priv->ifindex, + priv->iface, + str_options); } else { - prefix = nm_dhcp_utils_ip6_prefix_from_options(str_options); - ip_config = NM_IP_CONFIG_CAST(nm_dhcp_utils_ip6_config_from_options( + prefix = nm_dhcp_utils_ip6_prefix_from_options(str_options); + l3cd = 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))); + NM_FLAGS_HAS(priv->client_flags, NM_DHCP_CLIENT_FLAGS_INFO_ONLY)); } } else g_warn_if_reached(); + + if (l3cd) { + nm_l3_config_data_set_dhcp_lease_from_options(l3cd, + priv->addr_family, + g_steal_pointer(&str_options)); + } } if (!IN6_IS_ADDR_UNSPECIFIED(&prefix.address)) { @@ -947,17 +920,16 @@ nm_dhcp_client_handle_event(gpointer unused, * of the DHCP client instance. Instead, we just signal the prefix * to the device. */ nm_dhcp_client_emit_ipv6_prefix_delegated(self, &prefix); - } else { - /* Fail if no valid IP config was received */ - if (NM_IN_SET(new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED) && !ip_config) { - _LOGW("client bound but IP config not received"); - new_state = NM_DHCP_STATE_FAIL; - nm_clear_pointer(&str_options, g_hash_table_unref); - } + return TRUE; + } - nm_dhcp_client_set_state(self, new_state, ip_config, str_options); + /* Fail if no valid IP config was received */ + if (NM_IN_SET(new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED) && !l3cd) { + _LOGW("client bound but IP config not received"); + new_state = NM_DHCP_STATE_FAIL; } + nm_dhcp_client_set_state(self, new_state, l3cd); return TRUE; } @@ -1028,12 +1000,6 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) case PROP_HOSTNAME: g_value_set_string(value, priv->hostname); break; - case PROP_ROUTE_METRIC: - g_value_set_uint(value, priv->route_metric); - break; - case PROP_ROUTE_TABLE: - g_value_set_uint(value, priv->route_table); - break; case PROP_TIMEOUT: g_value_set_uint(value, priv->timeout); break; @@ -1116,12 +1082,6 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps /* construct-only */ priv->mud_url = g_value_dup_string(value); break; - case PROP_ROUTE_TABLE: - priv->route_table = g_value_get_uint(value); - break; - case PROP_ROUTE_METRIC: - priv->route_metric = g_value_get_uint(value); - break; case PROP_TIMEOUT: /* construct-only */ priv->timeout = g_value_get_uint(value); @@ -1324,24 +1284,6 @@ nm_dhcp_client_class_init(NMDhcpClientClass *client_class) NULL, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_ROUTE_TABLE] = - g_param_spec_uint(NM_DHCP_CLIENT_ROUTE_TABLE, - "", - "", - 0, - G_MAXUINT32, - RT_TABLE_MAIN, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_ROUTE_METRIC] = - g_param_spec_uint(NM_DHCP_CLIENT_ROUTE_METRIC, - "", - "", - 0, - G_MAXUINT32, - 0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - G_STATIC_ASSERT_EXPR(G_MAXINT32 == NM_DHCP_TIMEOUT_INFINITY); obj_properties[PROP_TIMEOUT] = g_param_spec_uint(NM_DHCP_CLIENT_TIMEOUT, @@ -1385,10 +1327,9 @@ nm_dhcp_client_class_init(NMDhcpClientClass *client_class) NULL, NULL, G_TYPE_NONE, - 3, + 2, G_TYPE_UINT, - G_TYPE_OBJECT, - G_TYPE_HASH_TABLE); + G_TYPE_POINTER /* NML3ConfigData */); signals[SIGNAL_PREFIX_DELEGATED] = g_signal_new(NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED, G_OBJECT_CLASS_TYPE(object_class), diff --git a/src/core/dhcp/nm-dhcp-client.h b/src/core/dhcp/nm-dhcp-client.h index 3fe1b34ec9..fccbf7d560 100644 --- a/src/core/dhcp/nm-dhcp-client.h +++ b/src/core/dhcp/nm-dhcp-client.h @@ -8,8 +8,6 @@ #include "nm-setting-ip4-config.h" #include "nm-setting-ip6-config.h" -#include "nm-ip4-config.h" -#include "nm-ip6-config.h" #include "nm-dhcp-utils.h" #define NM_DHCP_TIMEOUT_DEFAULT ((guint32) 45) /* default DHCP timeout, in seconds */ @@ -34,8 +32,6 @@ #define NM_DHCP_CLIENT_MULTI_IDX "multi-idx" #define NM_DHCP_CLIENT_HOSTNAME "hostname" #define NM_DHCP_CLIENT_MUD_URL "mud-url" -#define NM_DHCP_CLIENT_ROUTE_METRIC "route-metric" -#define NM_DHCP_CLIENT_ROUTE_TABLE "route-table" #define NM_DHCP_CLIENT_TIMEOUT "timeout" #define NM_DHCP_CLIENT_UUID "uuid" #define NM_DHCP_CLIENT_IAID "iaid" @@ -133,14 +129,6 @@ 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); - -guint32 nm_dhcp_client_get_route_metric(NMDhcpClient *self); - -void nm_dhcp_client_set_route_metric(NMDhcpClient *self, guint32 route_metric); - guint32 nm_dhcp_client_get_timeout(NMDhcpClient *self); guint32 nm_dhcp_client_get_iaid(NMDhcpClient *self); @@ -189,10 +177,7 @@ void nm_dhcp_client_watch_child(NMDhcpClient *self, pid_t pid); void nm_dhcp_client_stop_watch_child(NMDhcpClient *self, pid_t pid); -void nm_dhcp_client_set_state(NMDhcpClient *self, - NMDhcpState new_state, - NMIPConfig * ip_config, - GHashTable * options); /* str:str hash */ +void nm_dhcp_client_set_state(NMDhcpClient *self, NMDhcpState new_state, NML3ConfigData *l3cd); gboolean nm_dhcp_client_handle_event(gpointer unused, const char * iface, diff --git a/src/core/dhcp/nm-dhcp-dhclient-utils.c b/src/core/dhcp/nm-dhcp-dhclient-utils.c index 4284a852a5..6f1df27225 100644 --- a/src/core/dhcp/nm-dhcp-dhclient-utils.c +++ b/src/core/dhcp/nm-dhcp-dhclient-utils.c @@ -15,7 +15,6 @@ #include "libnm-glib-aux/nm-dedup-multi.h" #include "nm-dhcp-utils.h" -#include "nm-ip4-config.h" #include "nm-utils.h" #include "libnm-platform/nm-platform.h" #include "NetworkManagerUtils.h" diff --git a/src/core/dhcp/nm-dhcp-manager.c b/src/core/dhcp/nm-dhcp-manager.c index 44b8ede2c0..f62e411d01 100644 --- a/src/core/dhcp/nm-dhcp-manager.c +++ b/src/core/dhcp/nm-dhcp-manager.c @@ -45,11 +45,10 @@ G_DEFINE_TYPE(NMDhcpManager, nm_dhcp_manager, G_TYPE_OBJECT) /*****************************************************************************/ -static void client_state_changed(NMDhcpClient * client, - NMDhcpState state, - GObject * ip_config, - GVariant * options, - NMDhcpManager *self); +static void client_state_changed(NMDhcpClient * client, + NMDhcpState state, + NML3ConfigData *l3cd, + NMDhcpManager * self); /*****************************************************************************/ @@ -186,11 +185,10 @@ remove_client_unref(NMDhcpManager *self, NMDhcpClient *client) } static void -client_state_changed(NMDhcpClient * client, - NMDhcpState state, - GObject * ip_config, - GVariant * options, - NMDhcpManager *self) +client_state_changed(NMDhcpClient * client, + NMDhcpState state, + NML3ConfigData *l3cd, + NMDhcpManager * self) { if (state >= NM_DHCP_STATE_TIMEOUT) remove_client_unref(self, client); @@ -205,8 +203,6 @@ client_start(NMDhcpManager * self, GBytes * hwaddr, GBytes * bcast_hwaddr, const char * uuid, - guint32 route_table, - guint32 route_metric, const struct in6_addr * ipv6_ll_addr, GBytes * dhcp_client_id, gboolean enforce_duid, @@ -323,10 +319,6 @@ client_start(NMDhcpManager * self, hostname, NM_DHCP_CLIENT_MUD_URL, mud_url, - NM_DHCP_CLIENT_ROUTE_TABLE, - (guint) route_table, - NM_DHCP_CLIENT_ROUTE_METRIC, - (guint) route_metric, NM_DHCP_CLIENT_TIMEOUT, (guint) timeout, NM_DHCP_CLIENT_HOSTNAME_FLAGS, @@ -402,8 +394,6 @@ nm_dhcp_manager_start_ip4(NMDhcpManager * self, GBytes * hwaddr, GBytes * bcast_hwaddr, const char * uuid, - guint32 route_table, - guint32 route_metric, NMDhcpClientFlags client_flags, gboolean send_hostname, const char * dhcp_hostname, @@ -463,8 +453,6 @@ nm_dhcp_manager_start_ip4(NMDhcpManager * self, hwaddr, bcast_hwaddr, uuid, - route_table, - route_metric, NULL, dhcp_client_id, FALSE, @@ -492,8 +480,6 @@ nm_dhcp_manager_start_ip6(NMDhcpManager * self, int ifindex, const struct in6_addr * ll_addr, const char * uuid, - guint32 route_table, - guint32 route_metric, NMDhcpClientFlags client_flags, gboolean send_hostname, const char * dhcp_hostname, @@ -530,8 +516,6 @@ nm_dhcp_manager_start_ip6(NMDhcpManager * self, NULL, NULL, uuid, - route_table, - route_metric, ll_addr, duid, enforce_duid, diff --git a/src/core/dhcp/nm-dhcp-manager.h b/src/core/dhcp/nm-dhcp-manager.h index ce160437a5..ab44158cee 100644 --- a/src/core/dhcp/nm-dhcp-manager.h +++ b/src/core/dhcp/nm-dhcp-manager.h @@ -8,7 +8,6 @@ #define __NETWORKMANAGER_DHCP_MANAGER_H__ #include "nm-dhcp-client.h" -#include "nm-ip4-config.h" #include "nm-dhcp-config.h" #define NM_TYPE_DHCP_MANAGER (nm_dhcp_manager_get_type()) @@ -39,8 +38,6 @@ NMDhcpClient *nm_dhcp_manager_start_ip4(NMDhcpManager * manager, GBytes * hwaddr, GBytes * bcast_hwaddr, const char * uuid, - guint32 route_table, - guint32 route_metric, NMDhcpClientFlags client_flags, gboolean send_hostname, const char * dhcp_hostname, @@ -61,8 +58,6 @@ NMDhcpClient *nm_dhcp_manager_start_ip6(NMDhcpManager * manager, int ifindex, const struct in6_addr * ll_addr, const char * uuid, - guint32 route_table, - guint32 route_metric, NMDhcpClientFlags client_flags, gboolean send_hostname, const char * dhcp_hostname, diff --git a/src/core/dhcp/nm-dhcp-nettools.c b/src/core/dhcp/nm-dhcp-nettools.c index fe71f587a4..699324fca4 100644 --- a/src/core/dhcp/nm-dhcp-nettools.c +++ b/src/core/dhcp/nm-dhcp-nettools.c @@ -17,6 +17,7 @@ #include "libnm-std-aux/unaligned.h" #include "libnm-glib-aux/nm-str-buf.h" +#include "nm-l3-config-data.h" #include "nm-utils.h" #include "nm-config.h" #include "nm-dhcp-utils.h" @@ -151,7 +152,7 @@ lease_option_consume_route(const uint8_t **datap, static gboolean lease_parse_address(NDhcp4ClientLease *lease, - NMIP4Config * ip4_config, + NML3ConfigData * l3cd, GHashTable * options, GError ** error) { @@ -256,23 +257,23 @@ lease_parse_address(NDhcp4ClientLease *lease, a_next_server.s_addr); } - nm_ip4_config_add_address(ip4_config, - &((const NMPlatformIP4Address){ - .address = a_address.s_addr, - .peer_address = a_address.s_addr, - .plen = a_plen, - .addr_source = NM_IP_CONFIG_SOURCE_DHCP, - .timestamp = a_timestamp, - .lifetime = a_lifetime, - .preferred = a_lifetime, - })); + nm_l3_config_data_add_address_4(l3cd, + &((const NMPlatformIP4Address){ + .address = a_address.s_addr, + .peer_address = a_address.s_addr, + .plen = a_plen, + .addr_source = NM_IP_CONFIG_SOURCE_DHCP, + .timestamp = a_timestamp, + .lifetime = a_lifetime, + .preferred = a_lifetime, + })); return TRUE; } static void lease_parse_address_list(NDhcp4ClientLease * lease, - NMIP4Config * ip4_config, + NML3ConfigData * l3cd, NMDhcpOptionDhcp4Options option, GHashTable * options, NMStrBuf * sbuf) @@ -304,13 +305,13 @@ lease_parse_address_list(NDhcp4ClientLease * lease, * See https://github.com/systemd/systemd/issues/4524. */ continue; } - nm_ip4_config_add_nameserver(ip4_config, addr); + nm_l3_config_data_add_nameserver(l3cd, AF_INET, &addr); break; case NM_DHCP_OPTION_DHCP4_NIS_SERVERS: - nm_ip4_config_add_nis_server(ip4_config, addr); + nm_l3_config_data_add_nis_server(l3cd, addr); break; case NM_DHCP_OPTION_DHCP4_NETBIOS_NAMESERVER: - nm_ip4_config_add_wins(ip4_config, addr); + nm_l3_config_data_add_wins(l3cd, addr); break; case NM_DHCP_OPTION_DHCP4_NTP_SERVER: break; @@ -324,10 +325,8 @@ lease_parse_address_list(NDhcp4ClientLease * lease, static void lease_parse_routes(NDhcp4ClientLease *lease, - NMIP4Config * ip4_config, + NML3ConfigData * l3cd, GHashTable * options, - guint32 route_table, - guint32 route_metric, NMStrBuf * sbuf) { char dest_str[NM_UTILS_INET_ADDRSTRLEN]; @@ -336,9 +335,9 @@ lease_parse_routes(NDhcp4ClientLease *lease, in_addr_t gateway; uint8_t plen; guint32 m; - gboolean has_router_from_classless = FALSE; - gboolean has_classless = FALSE; - guint32 default_route_metric = route_metric; + gboolean has_router_from_classless = FALSE; + gboolean has_classless = FALSE; + guint32 default_route_metric_offset = 0; const guint8 *l_data; gsize l_data_len; int r; @@ -367,26 +366,22 @@ lease_parse_routes(NDhcp4ClientLease *lease, if (plen == 0) { /* if there are multiple default routes, we add them with differing * metrics. */ - m = default_route_metric; - if (default_route_metric < G_MAXUINT32) - default_route_metric++; - + m = default_route_metric_offset++; has_router_from_classless = TRUE; - } else { - m = route_metric; - } - - nm_ip4_config_add_route( - ip4_config, - &((const NMPlatformIP4Route){ - .network = dest, - .plen = plen, - .gateway = gateway, - .rt_source = NM_IP_CONFIG_SOURCE_DHCP, - .metric = m, - .table_coerced = nm_platform_route_table_coerce(route_table), - }), - NULL); + } else + m = 0; + + nm_l3_config_data_add_route_4(l3cd, + &((const NMPlatformIP4Route){ + .network = dest, + .plen = plen, + .gateway = gateway, + .rt_source = NM_IP_CONFIG_SOURCE_DHCP, + .table_any = TRUE, + .table_coerced = 0, + .metric_any = TRUE, + .metric = m, + })); } has_classless = TRUE; @@ -419,17 +414,17 @@ lease_parse_routes(NDhcp4ClientLease *lease, continue; } - nm_ip4_config_add_route( - ip4_config, - &((const NMPlatformIP4Route){ - .network = dest, - .plen = plen, - .gateway = gateway, - .rt_source = NM_IP_CONFIG_SOURCE_DHCP, - .metric = route_metric, - .table_coerced = nm_platform_route_table_coerce(route_table), - }), - NULL); + nm_l3_config_data_add_route_4(l3cd, + &((const NMPlatformIP4Route){ + .network = dest, + .plen = plen, + .gateway = gateway, + .rt_source = NM_IP_CONFIG_SOURCE_DHCP, + .table_any = TRUE, + .table_coerced = 0, + .metric_any = TRUE, + .metric = 0, + })); } nm_dhcp_option_add_option(options, @@ -463,19 +458,17 @@ lease_parse_routes(NDhcp4ClientLease *lease, /* if there are multiple default routes, we add them with differing * metrics. */ - m = default_route_metric; - if (default_route_metric < G_MAXUINT32) - default_route_metric++; - - nm_ip4_config_add_route( - ip4_config, - &((const NMPlatformIP4Route){ - .rt_source = NM_IP_CONFIG_SOURCE_DHCP, - .gateway = gateway, - .table_coerced = nm_platform_route_table_coerce(route_table), - .metric = m, - }), - NULL); + m = default_route_metric_offset++; + + nm_l3_config_data_add_route_4(l3cd, + &((const NMPlatformIP4Route){ + .rt_source = NM_IP_CONFIG_SOURCE_DHCP, + .gateway = gateway, + .table_any = TRUE, + .table_coerced = 0, + .metric_any = TRUE, + .metric = m, + })); } nm_dhcp_option_add_option(options, @@ -486,7 +479,7 @@ lease_parse_routes(NDhcp4ClientLease *lease, } static void -lease_parse_search_domains(NDhcp4ClientLease *lease, NMIP4Config *ip4_config, GHashTable *options) +lease_parse_search_domains(NDhcp4ClientLease *lease, NML3ConfigData *l3cd, GHashTable *options) { gs_strfreev char **domains = NULL; const guint8 * l_data; @@ -504,7 +497,7 @@ lease_parse_search_domains(NDhcp4ClientLease *lease, NMIP4Config *ip4_config, GH return; for (i = 0; domains[i]; i++) - nm_ip4_config_add_search(ip4_config, domains[i]); + nm_l3_config_data_add_search(l3cd, AF_INET, domains[i]); nm_dhcp_option_take_option(options, AF_INET, @@ -539,34 +532,33 @@ lease_parse_private_options(NDhcp4ClientLease *lease, GHashTable *options) } } -static NMIP4Config * +static NML3ConfigData * lease_to_ip4_config(NMDedupMultiIndex *multi_idx, const char * iface, int ifindex, NDhcp4ClientLease *lease, - guint32 route_table, - guint32 route_metric, - GHashTable ** out_options, GError ** error) { - nm_auto_str_buf NMStrBuf sbuf = NM_STR_BUF_INIT(0, FALSE); - gs_unref_object NMIP4Config *ip4_config = NULL; - gs_unref_hashtable GHashTable *options = NULL; + nm_auto_str_buf NMStrBuf sbuf = NM_STR_BUF_INIT(0, FALSE); + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + gs_unref_hashtable GHashTable *options = NULL; const guint8 * l_data; gsize l_data_len; const char * v_str; guint16 v_u16; - gboolean v_bool; in_addr_t v_inaddr; struct in_addr v_inaddr_s; int r; g_return_val_if_fail(lease != NULL, NULL); - ip4_config = nm_ip4_config_new(multi_idx, ifindex); - options = nm_dhcp_option_create_options_dict(); + l3cd = nm_l3_config_data_new(multi_idx, ifindex); - if (!lease_parse_address(lease, ip4_config, options, error)) + nm_l3_config_data_set_source(l3cd, NM_IP_CONFIG_SOURCE_DHCP); + + options = nm_dhcp_option_create_options_dict(); + + if (!lease_parse_address(lease, l3cd, options, error)) return NULL; r = n_dhcp4_client_lease_get_server_identifier(lease, &v_inaddr_s); @@ -585,13 +577,9 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, v_inaddr); } - lease_parse_routes(lease, ip4_config, options, route_table, route_metric, &sbuf); + lease_parse_routes(lease, l3cd, options, &sbuf); - lease_parse_address_list(lease, - ip4_config, - NM_DHCP_OPTION_DHCP4_DOMAIN_NAME_SERVER, - options, - &sbuf); + lease_parse_address_list(lease, l3cd, NM_DHCP_OPTION_DHCP4_DOMAIN_NAME_SERVER, options, &sbuf); r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_DOMAIN_NAME, &l_data, &l_data_len); if (r == 0 && nm_dhcp_lease_data_parse_cstr(l_data, l_data_len, &l_data_len)) { @@ -616,7 +604,7 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, nm_str_buf_append_required_delimiter(&sbuf, ' '); nm_str_buf_append(&sbuf, s); - nm_ip4_config_add_domain(ip4_config, s); + nm_l3_config_data_add_domain(l3cd, AF_INET, s); } } @@ -628,18 +616,17 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, } } - lease_parse_search_domains(lease, ip4_config, options); + lease_parse_search_domains(lease, l3cd, options); r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_INTERFACE_MTU, &l_data, &l_data_len); if (r == 0 && nm_dhcp_lease_data_parse_mtu(l_data, l_data_len, &v_u16)) { nm_dhcp_option_add_option_u64(options, AF_INET, NM_DHCP_OPTION_DHCP4_INTERFACE_MTU, v_u16); - nm_ip4_config_set_mtu(ip4_config, v_u16, NM_IP_CONFIG_SOURCE_DHCP); + nm_l3_config_data_set_mtu(l3cd, v_u16); } r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_VENDOR_SPECIFIC, &l_data, &l_data_len); - v_bool = - (r == 0) && memmem(l_data, l_data_len, "ANDROID_METERED", NM_STRLEN("ANDROID_METERED")); - nm_ip4_config_set_metered(ip4_config, v_bool); + if ((r == 0) && memmem(l_data, l_data_len, "ANDROID_METERED", NM_STRLEN("ANDROID_METERED"))) + nm_l3_config_data_set_metered(l3cd, TRUE); r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_HOST_NAME, &l_data, &l_data_len); if (r == 0) { @@ -650,7 +637,7 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, } } - lease_parse_address_list(lease, ip4_config, NM_DHCP_OPTION_DHCP4_NTP_SERVER, options, &sbuf); + lease_parse_address_list(lease, l3cd, NM_DHCP_OPTION_DHCP4_NTP_SERVER, options, &sbuf); r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_ROOT_PATH, &l_data, &l_data_len); if (r == 0 && nm_dhcp_lease_data_parse_cstr(l_data, l_data_len, &l_data_len)) { @@ -681,11 +668,17 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, * We reject NUL characters inside the string (except trailing NULs). * Otherwise, we allow any encoding and backslash-escape the result to * UTF-8. */ - nm_dhcp_option_add_option_utf8safe_escape(options, - AF_INET, - NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY, - l_data, - l_data_len); + gs_free char *to_free = NULL; + const char * escaped; + + escaped = 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_PRIVATE_PROXY_AUTODISCOVERY, + escaped ?: ""); + + nm_l3_config_data_set_proxy_method(l3cd, NM_PROXY_CONFIG_METHOD_AUTO); + nm_l3_config_data_set_proxy_pac_url(l3cd, escaped ?: ""); } r = _client_lease_query(lease, NM_DHCP_OPTION_DHCP4_NIS_DOMAIN, &l_data, &l_data_len); @@ -697,21 +690,20 @@ 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_l3_config_data_set_nis_domain(l3cd, v_str ?: ""); } - lease_parse_address_list(lease, ip4_config, NM_DHCP_OPTION_DHCP4_NIS_SERVERS, options, &sbuf); + lease_parse_address_list(lease, l3cd, NM_DHCP_OPTION_DHCP4_NIS_SERVERS, options, &sbuf); - lease_parse_address_list(lease, - ip4_config, - NM_DHCP_OPTION_DHCP4_NETBIOS_NAMESERVER, - options, - &sbuf); + lease_parse_address_list(lease, l3cd, NM_DHCP_OPTION_DHCP4_NETBIOS_NAMESERVER, options, &sbuf); lease_parse_private_options(lease, options); - NM_SET_OUT(out_options, g_steal_pointer(&options)); - return g_steal_pointer(&ip4_config); + nm_dhcp_option_add_requests_to_options(options, AF_INET); + + nm_l3_config_data_set_dhcp_lease_from_options(l3cd, AF_INET, g_steal_pointer(&options)); + + return g_steal_pointer(&l3cd); } /*****************************************************************************/ @@ -743,36 +735,30 @@ lease_save(NMDhcpNettools *self, NDhcp4ClientLease *lease, const char *lease_fil static void bound4_handle(NMDhcpNettools *self, NDhcp4ClientLease *lease, gboolean extended) { - NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); - const char * iface = nm_dhcp_client_get_iface(NM_DHCP_CLIENT(self)); - gs_unref_object NMIP4Config *ip4_config = NULL; - gs_unref_hashtable GHashTable *options = NULL; - GError * error = NULL; + NMDhcpNettoolsPrivate * priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); + const char * iface = nm_dhcp_client_get_iface(NM_DHCP_CLIENT(self)); + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + GError * error = NULL; _LOGT("lease available (%s)", extended ? "extended" : "new"); - ip4_config = lease_to_ip4_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_route_table(NM_DHCP_CLIENT(self)), - nm_dhcp_client_get_route_metric(NM_DHCP_CLIENT(self)), - &options, - &error); - if (!ip4_config) { - _LOGW("%s", error->message); + l3cd = lease_to_ip4_config(nm_dhcp_client_get_multi_idx(NM_DHCP_CLIENT(self)), + iface, + nm_dhcp_client_get_ifindex(NM_DHCP_CLIENT(self)), + lease, + &error); + if (!l3cd) { + _LOGW("failure to parse lease: %s", error->message); g_clear_error(&error); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL, NULL); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL); return; } - nm_dhcp_option_add_requests_to_options(options, AF_INET); lease_save(self, lease, priv->lease_file); nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), extended ? NM_DHCP_STATE_EXTENDED : NM_DHCP_STATE_BOUND, - NM_IP_CONFIG_CAST(ip4_config), - options); + l3cd); } static void @@ -807,10 +793,10 @@ dhcp4_event_handle(NMDhcpNettools *self, NDhcp4ClientEvent *event) break; case N_DHCP4_CLIENT_EVENT_RETRACTED: case N_DHCP4_CLIENT_EVENT_EXPIRED: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_EXPIRE, NULL, NULL); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_EXPIRE, NULL); break; case N_DHCP4_CLIENT_EVENT_CANCELLED: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL, NULL); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL); break; case N_DHCP4_CLIENT_EVENT_GRANTED: priv->lease = n_dhcp4_client_lease_ref(event->granted.lease); @@ -862,13 +848,12 @@ dhcp4_event_cb(int fd, GIOCondition condition, gpointer user_data) */ _LOGE("error %d dispatching events", r); nm_clear_g_source_inst(&priv->event_source); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL, NULL); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL); return G_SOURCE_REMOVE; } - while (!n_dhcp4_client_pop_event(priv->client, &event) && event) { + while (!n_dhcp4_client_pop_event(priv->client, &event) && event) dhcp4_event_handle(self, event); - } return G_SOURCE_CONTINUE; } @@ -1007,7 +992,7 @@ decline(NMDhcpClient *client, const char *error_message, GError **error) g_return_val_if_fail(priv->lease, FALSE); - _LOGT("dhcp4-client: decline"); + _LOGT("dhcp4-client: decline (%s)", error_message); r = n_dhcp4_client_lease_decline(priv->lease, error_message); if (r) { diff --git a/src/core/dhcp/nm-dhcp-systemd.c b/src/core/dhcp/nm-dhcp-systemd.c index c789aaee0f..01184f0442 100644 --- a/src/core/dhcp/nm-dhcp-systemd.c +++ b/src/core/dhcp/nm-dhcp-systemd.c @@ -17,6 +17,7 @@ #include "libnm-std-aux/unaligned.h" #include "nm-utils.h" +#include "nm-l3-config-data.h" #include "nm-dhcp-utils.h" #include "nm-dhcp-options.h" #include "nm-core-utils.h" @@ -70,18 +71,15 @@ G_DEFINE_TYPE(NMDhcpSystemd, nm_dhcp_systemd, NM_TYPE_DHCP_CLIENT) /*****************************************************************************/ -static NMIP4Config * +static NML3ConfigData * lease_to_ip4_config(NMDedupMultiIndex *multi_idx, const char * iface, int ifindex, sd_dhcp_lease * lease, - guint32 route_table, - guint32 route_metric, - GHashTable ** out_options, GError ** error) { - gs_unref_object NMIP4Config *ip4_config = NULL; - gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + gs_unref_hashtable GHashTable *options = NULL; const struct in_addr * addr_list; char addr_str[NM_UTILS_INET_ADDRSTRLEN]; const char * s; @@ -92,7 +90,6 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, 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; @@ -133,9 +130,11 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, return NULL; } - ip4_config = nm_ip4_config_new(multi_idx, ifindex); + l3cd = nm_l3_config_data_new(multi_idx, ifindex); - options = out_options ? nm_dhcp_option_create_options_dict() : NULL; + nm_l3_config_data_set_source(l3cd, NM_IP_CONFIG_SOURCE_DHCP); + + options = nm_dhcp_option_create_options_dict(); _nm_utils_inet4_ntop(a_address.s_addr, addr_str); nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NM_IP_ADDRESS, addr_str); @@ -160,16 +159,16 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NM_NEXT_SERVER, addr_str); } - nm_ip4_config_add_address(ip4_config, - &((const NMPlatformIP4Address){ - .address = a_address.s_addr, - .peer_address = a_address.s_addr, - .plen = a_plen, - .addr_source = NM_IP_CONFIG_SOURCE_DHCP, - .timestamp = ts, - .lifetime = a_lifetime, - .preferred = a_lifetime, - })); + nm_l3_config_data_add_address_4(l3cd, + &((const NMPlatformIP4Address){ + .address = a_address.s_addr, + .peer_address = a_address.s_addr, + .plen = a_plen, + .addr_source = NM_IP_CONFIG_SOURCE_DHCP, + .timestamp = ts, + .lifetime = a_lifetime, + .preferred = a_lifetime, + })); if (sd_dhcp_lease_get_server_identifier(lease, &server_id) >= 0) { _nm_utils_inet4_ntop(server_id.s_addr, addr_str); @@ -193,7 +192,7 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, * See https://github.com/systemd/systemd/issues/4524. */ continue; } - nm_ip4_config_add_nameserver(ip4_config, addr_list[i].s_addr); + nm_l3_config_data_add_nameserver(l3cd, AF_INET, &addr_list[i].s_addr); } nm_dhcp_option_add_option(options, AF_INET, @@ -206,7 +205,7 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, nm_gstring_prepare(&str); for (i = 0; i < num; i++) { g_string_append(nm_gstring_add_space_delimiter(str), search_domains[i]); - nm_ip4_config_add_search(ip4_config, search_domains[i]); + nm_l3_config_data_add_search(l3cd, AF_INET, search_domains[i]); } nm_dhcp_option_add_option(options, AF_INET, @@ -224,7 +223,7 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, * As systemd escapes such characters, split them at \\032. */ domains = g_strsplit(s, "\\032", 0); for (d = domains; *d; d++) - nm_ip4_config_add_domain(ip4_config, *d); + nm_l3_config_data_add_domain(l3cd, AF_INET, *d); } if (sd_dhcp_lease_get_hostname(lease, &s) >= 0) { @@ -233,9 +232,9 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, num = sd_dhcp_lease_get_routes(lease, &routes); if (num > 0) { - nm_auto_free_gstring GString *str_classless = NULL; - nm_auto_free_gstring GString *str_static = NULL; - guint32 default_route_metric = route_metric; + nm_auto_free_gstring GString *str_classless = NULL; + nm_auto_free_gstring GString *str_static = NULL; + guint32 default_route_metric_offset = 0; for (i = 0; i < num; i++) { switch (sd_dhcp_route_get_option(routes[i])) { @@ -307,25 +306,22 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, if (r_plen == 0) { /* if there are multiple default routes, we add them with differing * metrics. */ - m = default_route_metric; - if (default_route_metric < G_MAXUINT32) - default_route_metric++; - + m = default_route_metric_offset++; has_router_from_classless = TRUE; } else - m = route_metric; - - nm_ip4_config_add_route( - ip4_config, - &((const NMPlatformIP4Route){ - .network = network_net, - .plen = r_plen, - .gateway = r_gateway.s_addr, - .rt_source = NM_IP_CONFIG_SOURCE_DHCP, - .metric = m, - .table_coerced = nm_platform_route_table_coerce(route_table), - }), - NULL); + m = 0; + + nm_l3_config_data_add_route_4(l3cd, + &((const NMPlatformIP4Route){ + .network = network_net, + .plen = r_plen, + .gateway = r_gateway.s_addr, + .rt_source = NM_IP_CONFIG_SOURCE_DHCP, + .metric_any = TRUE, + .metric = m, + .table_any = TRUE, + .table_coerced = 0, + })); } if (str_classless && str_classless->len > 0) @@ -342,7 +338,7 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, num = sd_dhcp_lease_get_router(lease, &a_router); if (num > 0) { - guint32 default_route_metric = route_metric; + guint32 default_route_metric_offset = 0; nm_gstring_prepare(&str); for (i = 0; i < num; i++) { @@ -368,26 +364,24 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, /* if there are multiple default routes, we add them with differing * metrics. */ - m = default_route_metric; - if (default_route_metric < G_MAXUINT32) - default_route_metric++; - - nm_ip4_config_add_route( - ip4_config, - &((const NMPlatformIP4Route){ - .rt_source = NM_IP_CONFIG_SOURCE_DHCP, - .gateway = a_router[i].s_addr, - .table_coerced = nm_platform_route_table_coerce(route_table), - .metric = m, - }), - NULL); + m = default_route_metric_offset++; + + nm_l3_config_data_add_route_4(l3cd, + &((const NMPlatformIP4Route){ + .rt_source = NM_IP_CONFIG_SOURCE_DHCP, + .gateway = a_router[i].s_addr, + .table_any = TRUE, + .table_coerced = 0, + .metric_any = TRUE, + .metric = m, + })); } nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_ROUTER, str->str); } if (sd_dhcp_lease_get_mtu(lease, &mtu) >= 0 && mtu) { nm_dhcp_option_add_option_u64(options, AF_INET, NM_DHCP_OPTION_DHCP4_INTERFACE_MTU, mtu); - nm_ip4_config_set_mtu(ip4_config, mtu, NM_IP_CONFIG_SOURCE_DHCP); + nm_l3_config_data_set_mtu(l3cd, mtu); } num = sd_dhcp_lease_get_ntp(lease, &addr_list); @@ -422,9 +416,10 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NEW_TZDB_TIMEZONE, s); } - if (sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len) >= 0) - metered = !!memmem(data, data_len, "ANDROID_METERED", NM_STRLEN("ANDROID_METERED")); - nm_ip4_config_set_metered(ip4_config, metered); + if (sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len) >= 0) { + if (!!memmem(data, data_len, "ANDROID_METERED", NM_STRLEN("ANDROID_METERED"))) + nm_l3_config_data_set_metered(l3cd, TRUE); + } num = nm_sd_dhcp_lease_get_private_options(lease, &private_options); if (num > 0) { @@ -436,12 +431,18 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, 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); + gs_free char *to_free = NULL; + const char * escaped; + + escaped = + 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_PRIVATE_PROXY_AUTODISCOVERY, + escaped ?: ""); + + nm_l3_config_data_set_proxy_method(l3cd, NM_PROXY_CONFIG_METHOD_AUTO); + nm_l3_config_data_set_proxy_pac_url(l3cd, escaped ?: ""); } continue; } @@ -458,8 +459,12 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, nm_dhcp_option_take_option(options, AF_INET, code, option_string); } } - NM_SET_OUT(out_options, g_steal_pointer(&options)); - return g_steal_pointer(&ip4_config); + + nm_dhcp_option_add_requests_to_options(options, AF_INET); + + nm_l3_config_data_set_dhcp_lease_from_options(l3cd, AF_INET, g_steal_pointer(&options)); + + return g_steal_pointer(&l3cd); } /*****************************************************************************/ @@ -467,43 +472,38 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, static void bound4_handle(NMDhcpSystemd *self, gboolean extended) { - NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self); - const char * iface = nm_dhcp_client_get_iface(NM_DHCP_CLIENT(self)); - gs_unref_object NMIP4Config *ip4_config = NULL; - gs_unref_hashtable GHashTable *options = NULL; - sd_dhcp_lease * lease = NULL; - GError * error = NULL; + NMDhcpSystemdPrivate * priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self); + const char * iface = nm_dhcp_client_get_iface(NM_DHCP_CLIENT(self)); + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + gs_unref_hashtable GHashTable *options = NULL; + sd_dhcp_lease * lease = NULL; + GError * error = NULL; if (sd_dhcp_client_get_lease(priv->client4, &lease) < 0 || !lease) { _LOGW("no lease!"); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL, NULL); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL); return; } _LOGD("lease available"); - ip4_config = lease_to_ip4_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_route_table(NM_DHCP_CLIENT(self)), - nm_dhcp_client_get_route_metric(NM_DHCP_CLIENT(self)), - &options, - &error); - if (!ip4_config) { + l3cd = lease_to_ip4_config(nm_dhcp_client_get_multi_idx(NM_DHCP_CLIENT(self)), + iface, + nm_dhcp_client_get_ifindex(NM_DHCP_CLIENT(self)), + lease, + &error); + if (!l3cd) { _LOGW("%s", error->message); g_clear_error(&error); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL, NULL); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL); return; } - nm_dhcp_option_add_requests_to_options(options, AF_INET); dhcp_lease_save(lease, priv->lease_file); nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), extended ? NM_DHCP_STATE_EXTENDED : NM_DHCP_STATE_BOUND, - NM_IP_CONFIG_CAST(ip4_config), - options); + l3cd); } static int @@ -522,10 +522,10 @@ dhcp_event_cb(sd_dhcp_client *client, int event, gpointer user_data) switch (event) { case SD_DHCP_CLIENT_EVENT_EXPIRED: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_EXPIRE, NULL, NULL); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_EXPIRE, NULL); break; case SD_DHCP_CLIENT_EVENT_STOP: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_FAIL, NULL, NULL); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_FAIL, NULL); break; case SD_DHCP_CLIENT_EVENT_RENEW: case SD_DHCP_CLIENT_EVENT_IP_CHANGE: @@ -759,32 +759,34 @@ ip4_start(NMDhcpClient *client, const char *last_ip4_address, GError **error) return TRUE; } -static NMIP6Config * +static NML3ConfigData * lease_to_ip6_config(NMDedupMultiIndex *multi_idx, const char * iface, int ifindex, sd_dhcp6_lease * lease, gboolean info_only, - GHashTable ** out_options, gint32 ts, GError ** error) { - gs_unref_object NMIP6Config *ip6_config = NULL; - gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + gs_unref_hashtable GHashTable *options = NULL; struct in6_addr tmp_addr; const struct in6_addr * dns; uint32_t lft_pref, lft_valid; char addr_str[NM_UTILS_INET_ADDRSTRLEN]; char ** domains; const char * s; - nm_auto_free_gstring GString *str = NULL; + nm_auto_free_gstring GString *str = NULL; + gboolean has_any_addresses = FALSE; int num, i; nm_assert(lease); - ip6_config = nm_ip6_config_new(multi_idx, ifindex); + l3cd = nm_l3_config_data_new(multi_idx, ifindex); - options = out_options ? nm_dhcp_option_create_options_dict() : NULL; + nm_l3_config_data_set_source(l3cd, NM_IP_CONFIG_SOURCE_DHCP); + + options = nm_dhcp_option_create_options_dict(); sd_dhcp6_lease_reset_address_iter(lease); nm_gstring_prepare(&str); @@ -798,15 +800,19 @@ lease_to_ip6_config(NMDedupMultiIndex *multi_idx, .addr_source = NM_IP_CONFIG_SOURCE_DHCP, }; - nm_ip6_config_add_address(ip6_config, &address); + nm_l3_config_data_add_address_6(l3cd, &address); _nm_utils_inet6_ntop(&tmp_addr, addr_str); g_string_append(nm_gstring_add_space_delimiter(str), addr_str); - }; - if (str->len) + + has_any_addresses = TRUE; + } + + if (str->len) { nm_dhcp_option_add_option(options, AF_INET6, NM_DHCP_OPTION_DHCP6_NM_IP_ADDRESS, str->str); + } - if (!info_only && nm_ip6_config_get_num_addresses(ip6_config) == 0) { + if (!info_only && !has_any_addresses) { g_set_error_literal(error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, @@ -820,7 +826,7 @@ lease_to_ip6_config(NMDedupMultiIndex *multi_idx, for (i = 0; i < num; i++) { _nm_utils_inet6_ntop(&dns[i], addr_str); g_string_append(nm_gstring_add_space_delimiter(str), addr_str); - nm_ip6_config_add_nameserver(ip6_config, &dns[i]); + nm_l3_config_data_add_nameserver(l3cd, AF_INET6, &dns[i]); } nm_dhcp_option_add_option(options, AF_INET6, NM_DHCP_OPTION_DHCP6_DNS_SERVERS, str->str); } @@ -830,7 +836,7 @@ lease_to_ip6_config(NMDedupMultiIndex *multi_idx, nm_gstring_prepare(&str); for (i = 0; i < num; i++) { g_string_append(nm_gstring_add_space_delimiter(str), domains[i]); - nm_ip6_config_add_search(ip6_config, domains[i]); + nm_l3_config_data_add_search(l3cd, AF_INET6, domains[i]); } nm_dhcp_option_add_option(options, AF_INET6, NM_DHCP_OPTION_DHCP6_DOMAIN_LIST, str->str); } @@ -839,51 +845,46 @@ lease_to_ip6_config(NMDedupMultiIndex *multi_idx, nm_dhcp_option_add_option(options, AF_INET6, NM_DHCP_OPTION_DHCP6_FQDN, s); } - NM_SET_OUT(out_options, g_steal_pointer(&options)); - return g_steal_pointer(&ip6_config); + nm_l3_config_data_set_dhcp_lease_from_options(l3cd, AF_INET6, g_steal_pointer(&options)); + + return g_steal_pointer(&l3cd); } static void bound6_handle(NMDhcpSystemd *self) { - NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self); - const gint32 ts = nm_utils_get_monotonic_timestamp_sec(); - const char * iface = nm_dhcp_client_get_iface(NM_DHCP_CLIENT(self)); - gs_unref_object NMIP6Config *ip6_config = NULL; - gs_unref_hashtable GHashTable *options = NULL; - gs_free_error GError *error = NULL; - NMPlatformIP6Address prefix = {0}; - sd_dhcp6_lease * lease = NULL; + NMDhcpSystemdPrivate * priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self); + const gint32 ts = nm_utils_get_monotonic_timestamp_sec(); + const char * iface = nm_dhcp_client_get_iface(NM_DHCP_CLIENT(self)); + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + gs_free_error GError *error = NULL; + NMPlatformIP6Address prefix = {0}; + sd_dhcp6_lease * lease = NULL; if (sd_dhcp6_client_get_lease(priv->client6, &lease) < 0 || !lease) { _LOGW(" no lease!"); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL, NULL); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL); return; } _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_FLAGS_HAS(nm_dhcp_client_get_client_flags(NM_DHCP_CLIENT(self)), - NM_DHCP_CLIENT_FLAGS_INFO_ONLY), - &options, - ts, - &error); - - if (!ip6_config) { + l3cd = 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), + ts, + &error); + + if (!l3cd) { _LOGW("%s", error->message); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL, NULL); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL); return; } - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), - NM_DHCP_STATE_BOUND, - NM_IP_CONFIG_CAST(ip6_config), - options); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_BOUND, l3cd); sd_dhcp6_lease_reset_pd_prefix_iter(lease); while (!sd_dhcp6_lease_get_pd(lease, @@ -908,11 +909,11 @@ dhcp6_event_cb(sd_dhcp6_client *client, int event, gpointer user_data) switch (event) { case SD_DHCP6_CLIENT_EVENT_RETRANS_MAX: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_TIMEOUT, NULL, NULL); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_TIMEOUT, NULL); break; case SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE: case SD_DHCP6_CLIENT_EVENT_STOP: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_FAIL, NULL, NULL); + nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_FAIL, NULL); break; case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE: case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST: diff --git a/src/core/dhcp/nm-dhcp-utils.c b/src/core/dhcp/nm-dhcp-utils.c index 7fd18b0a72..379baae25a 100644 --- a/src/core/dhcp/nm-dhcp-utils.c +++ b/src/core/dhcp/nm-dhcp-utils.c @@ -14,6 +14,7 @@ #include "libnm-systemd-shared/nm-sd-utils-shared.h" #include "nm-dhcp-utils.h" +#include "nm-l3-config-data.h" #include "nm-utils.h" #include "nm-config.h" #include "NetworkManagerUtils.h" @@ -24,12 +25,10 @@ /*****************************************************************************/ static gboolean -ip4_process_dhcpcd_rfc3442_routes(const char * iface, - const char * str, - guint32 route_table, - guint32 route_metric, - NMIP4Config *ip4_config, - guint32 * gwaddr) +ip4_process_dhcpcd_rfc3442_routes(const char * iface, + const char * str, + NML3ConfigData *l3cd, + guint32 * gwaddr) { gs_free const char **routes = NULL; const char ** r; @@ -45,10 +44,9 @@ ip4_process_dhcpcd_rfc3442_routes(const char * iface, } for (r = routes; *r; r += 2) { - char * slash; - NMPlatformIP4Route route; - int rt_cidr = 32; - guint32 rt_addr, rt_route; + char * slash; + int rt_cidr = 32; + guint32 rt_addr, rt_route; slash = strchr(*r, '/'); if (slash) { @@ -89,14 +87,18 @@ ip4_process_dhcpcd_rfc3442_routes(const char * iface, *r, rt_cidr, *(r + 1)); - memset(&route, 0, sizeof(route)); - route.network = nm_utils_ip4_address_clear_host_address(rt_addr, rt_cidr); - route.plen = rt_cidr; - route.gateway = rt_route; - route.rt_source = NM_IP_CONFIG_SOURCE_DHCP; - route.metric = route_metric; - route.table_coerced = nm_platform_route_table_coerce(route_table); - nm_ip4_config_add_route(ip4_config, &route, NULL); + + nm_l3_config_data_add_route_4( + l3cd, + &((const NMPlatformIP4Route){ + .network = nm_utils_ip4_address_clear_host_address(rt_addr, rt_cidr), + .plen = rt_cidr, + .gateway = rt_route, + .rt_source = NM_IP_CONFIG_SOURCE_DHCP, + .metric_any = TRUE, + .table_any = TRUE, + + })); } } @@ -153,12 +155,10 @@ process_dhclient_rfc3442_route(const char *const **p_octets, NMPlatformIP4Route } static gboolean -ip4_process_dhclient_rfc3442_routes(const char * iface, - const char * str, - guint32 route_table, - guint32 route_metric, - NMIP4Config *ip4_config, - guint32 * gwaddr) +ip4_process_dhclient_rfc3442_routes(const char * iface, + const char * str, + NML3ConfigData *l3cd, + guint32 * gwaddr) { gs_free const char **octets = NULL; const char *const * o; @@ -189,9 +189,12 @@ ip4_process_dhclient_rfc3442_routes(const char * iface, /* normal route */ route.rt_source = NM_IP_CONFIG_SOURCE_DHCP; - route.metric = route_metric; - route.table_coerced = nm_platform_route_table_coerce(route_table); - nm_ip4_config_add_route(ip4_config, &route, NULL); + route.table_any = TRUE; + route.table_coerced = 0; + route.metric_any = TRUE; + route.metric = 0; + + nm_l3_config_data_add_route_4(l3cd, &route); _LOG2I(LOGD_DHCP4, iface, @@ -206,17 +209,15 @@ ip4_process_dhclient_rfc3442_routes(const char * iface, } static gboolean -ip4_process_classless_routes(const char * iface, - GHashTable * options, - guint32 route_table, - guint32 route_metric, - NMIP4Config *ip4_config, - guint32 * gwaddr) +ip4_process_classless_routes(const char * iface, + GHashTable * options, + NML3ConfigData *l3cd, + guint32 * gwaddr) { const char *str, *p; g_return_val_if_fail(options != NULL, FALSE); - g_return_val_if_fail(ip4_config != NULL, FALSE); + g_return_val_if_fail(l3cd != NULL, FALSE); *gwaddr = 0; @@ -265,28 +266,14 @@ ip4_process_classless_routes(const char * iface, if (strchr(str, '/')) { /* dhcpcd format */ - return ip4_process_dhcpcd_rfc3442_routes(iface, - str, - route_table, - route_metric, - ip4_config, - gwaddr); + return ip4_process_dhcpcd_rfc3442_routes(iface, str, l3cd, gwaddr); } - return ip4_process_dhclient_rfc3442_routes(iface, - str, - route_table, - route_metric, - ip4_config, - gwaddr); + return ip4_process_dhclient_rfc3442_routes(iface, str, l3cd, gwaddr); } static void -process_classful_routes(const char * iface, - GHashTable * options, - guint32 route_table, - guint32 route_metric, - NMIP4Config *ip4_config) +process_classful_routes(const char *iface, GHashTable *options, NML3ConfigData *l3cd) { gs_free const char **searches = NULL; const char ** s; @@ -320,8 +307,10 @@ process_classful_routes(const char * iface, // FIXME: ensure the IP address and route are sane - memset(&route, 0, sizeof(route)); - route.network = rt_addr; + route = (NMPlatformIP4Route){ + .network = rt_addr, + }; + /* RFC 2132, updated by RFC 3442: * The Static Routes option (option 33) does not provide a subnet mask * for each route - it is assumed that the subnet mask is implicit in @@ -333,12 +322,15 @@ process_classful_routes(const char * iface, } route.gateway = rt_route; route.rt_source = NM_IP_CONFIG_SOURCE_DHCP; - route.metric = route_metric; - route.table_coerced = nm_platform_route_table_coerce(route_table); + route.table_any = TRUE; + route.table_coerced = 0; + route.metric_any = TRUE; + route.metric = 0; route.network = nm_utils_ip4_address_clear_host_address(route.network, route.plen); - nm_ip4_config_add_route(ip4_config, &route, NULL); + nm_l3_config_data_add_route_4(l3cd, &route); + _LOG2I(LOGD_DHCP, iface, " static route %s", @@ -347,7 +339,7 @@ process_classful_routes(const char * iface, } static void -process_domain_search(const char *iface, const char *str, GFunc add_func, gpointer user_data) +process_domain_search(int addr_family, const char *iface, const char *str, NML3ConfigData *l3cd) { gs_free const char **searches = NULL; gs_free char * unescaped = NULL; @@ -356,7 +348,7 @@ process_domain_search(const char *iface, const char *str, GFunc add_func, gpoint int i; g_return_if_fail(str != NULL); - g_return_if_fail(add_func != NULL); + nm_assert(l3cd); unescaped = g_strdup(str); @@ -379,46 +371,44 @@ process_domain_search(const char *iface, const char *str, GFunc add_func, gpoint searches = nm_utils_strsplit_set(unescaped, " "); for (s = searches; searches && *s; s++) { _LOG2I(LOGD_DHCP, iface, " domain search '%s'", *s); - add_func((gpointer) *s, user_data); + nm_l3_config_data_add_search(l3cd, addr_family, *s); } } -static void -ip4_add_domain_search(gpointer data, gpointer user_data) -{ - nm_ip4_config_add_search(NM_IP4_CONFIG(user_data), (const char *) data); -} - -NMIP4Config * +NML3ConfigData * nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, int ifindex, const char * iface, - GHashTable * options, - guint32 route_table, - guint32 route_metric) + GHashTable * options) { - gs_unref_object NMIP4Config *ip4_config = NULL; - guint32 tmp_addr; - in_addr_t addr; - NMPlatformIP4Address address; - char * str = NULL; - gboolean gateway_has = FALSE; - guint32 gateway = 0; - guint8 plen = 0; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + guint32 tmp_addr; + in_addr_t addr; + NMPlatformIP4Address address; + char * str = NULL; + gboolean gateway_has = FALSE; + guint32 gateway = 0; + guint8 plen = 0; + char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + guint32 now; g_return_val_if_fail(options != NULL, NULL); - ip4_config = nm_ip4_config_new(multi_idx, ifindex); - memset(&address, 0, sizeof(address)); - address.timestamp = nm_utils_get_monotonic_timestamp_sec(); + l3cd = nm_l3_config_data_new(multi_idx, ifindex); + nm_l3_config_data_set_source(l3cd, NM_IP_CONFIG_SOURCE_DHCP); + + now = nm_utils_get_monotonic_timestamp_sec(); + + address = (NMPlatformIP4Address){ + .timestamp = now, + }; str = g_hash_table_lookup(options, "ip_address"); - if (str && (inet_pton(AF_INET, str, &addr) > 0)) - _LOG2I(LOGD_DHCP4, iface, " address %s", str); - else + if (!str || !nm_utils_parse_inaddr_bin(AF_INET, str, NULL, &addr)) return NULL; + _LOG2I(LOGD_DHCP4, iface, " address %s", str); + str = g_hash_table_lookup(options, "subnet_mask"); if (str && (inet_pton(AF_INET, str, &tmp_addr) > 0)) { plen = nm_utils_ip4_netmask_to_prefix(tmp_addr); @@ -433,13 +423,8 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, /* Routes: if the server returns classless static routes, we MUST ignore * the 'static_routes' option. */ - if (!ip4_process_classless_routes(iface, - options, - route_table, - route_metric, - ip4_config, - &gateway)) - process_classful_routes(iface, options, route_table, route_metric, ip4_config); + if (!ip4_process_classless_routes(iface, options, l3cd, &gateway)) + process_classful_routes(iface, options, l3cd); if (gateway) { _LOG2I(LOGD_DHCP4, iface, " gateway %s", _nm_utils_inet4_ntop(gateway, sbuf)); @@ -450,10 +435,10 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, */ str = g_hash_table_lookup(options, "routers"); if (str) { - gs_free const char **routers = nm_utils_strsplit_set(str, " "); - const char ** s; + char **routers = g_strsplit(str, " ", 0); + char **s; - for (s = routers; routers && *s; s++) { + for (s = routers; *s; s++) { /* FIXME: how to handle multiple routers? */ if (inet_pton(AF_INET, *s, &gateway) > 0) { _LOG2I(LOGD_DHCP4, iface, " gateway %s", *s); @@ -462,6 +447,7 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, } else _LOG2W(LOGD_DHCP4, iface, "ignoring invalid gateway '%s'", *s); } + g_strfreev(routers); } } @@ -469,11 +455,13 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, const NMPlatformIP4Route r = { .rt_source = NM_IP_CONFIG_SOURCE_DHCP, .gateway = gateway, - .table_coerced = nm_platform_route_table_coerce(route_table), - .metric = route_metric, + .table_any = TRUE, + .table_coerced = 0, + .metric_any = TRUE, + .metric = 0, }; - nm_ip4_config_add_route(ip4_config, &r, NULL); + nm_l3_config_data_add_route_4(l3cd, &r); } str = g_hash_table_lookup(options, "dhcp_lease_time"); @@ -483,7 +471,8 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, } address.addr_source = NM_IP_CONFIG_SOURCE_DHCP; - nm_ip4_config_add_address(ip4_config, &address); + + nm_l3_config_data_add_address_4(l3cd, &address); str = g_hash_table_lookup(options, "host_name"); if (str) @@ -497,7 +486,7 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, for (s = dns; dns && *s; s++) { if (inet_pton(AF_INET, *s, &tmp_addr) > 0) { if (tmp_addr) { - nm_ip4_config_add_nameserver(ip4_config, tmp_addr); + nm_l3_config_data_add_nameserver(l3cd, AF_INET, &tmp_addr); _LOG2I(LOGD_DHCP4, iface, " nameserver '%s'", *s); } } else @@ -512,13 +501,13 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, for (s = domains; domains && *s; s++) { _LOG2I(LOGD_DHCP4, iface, " domain name '%s'", *s); - nm_ip4_config_add_domain(ip4_config, *s); + nm_l3_config_data_add_domain(l3cd, AF_INET, *s); } } str = g_hash_table_lookup(options, "domain_search"); if (str) - process_domain_search(iface, str, ip4_add_domain_search, ip4_config); + process_domain_search(AF_INET, iface, str, l3cd); str = g_hash_table_lookup(options, "netbios_name_servers"); if (str) { @@ -528,7 +517,7 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, for (s = nbns; nbns && *s; s++) { if (inet_pton(AF_INET, *s, &tmp_addr) > 0) { if (tmp_addr) { - nm_ip4_config_add_wins(ip4_config, tmp_addr); + nm_l3_config_data_add_wins(l3cd, tmp_addr); _LOG2I(LOGD_DHCP4, iface, " wins '%s'", *s); } } else @@ -546,13 +535,13 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, return NULL; if (int_mtu > 576) - nm_ip4_config_set_mtu(ip4_config, int_mtu, NM_IP_CONFIG_SOURCE_DHCP); + nm_l3_config_data_set_mtu(l3cd, int_mtu); } str = g_hash_table_lookup(options, "nis_domain"); if (str) { _LOG2I(LOGD_DHCP4, iface, " NIS domain '%s'", str); - nm_ip4_config_set_nis_domain(ip4_config, str); + nm_l3_config_data_add_domain(l3cd, AF_INET, str); } str = g_hash_table_lookup(options, "nis_servers"); @@ -563,7 +552,7 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, for (s = nis; nis && *s; s++) { if (inet_pton(AF_INET, *s, &tmp_addr) > 0) { if (tmp_addr) { - nm_ip4_config_add_nis_server(ip4_config, tmp_addr); + nm_l3_config_data_add_nis_server(l3cd, tmp_addr); _LOG2I(LOGD_DHCP4, iface, " nis '%s'", *s); } } else @@ -572,19 +561,20 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, } str = g_hash_table_lookup(options, "vendor_encapsulated_options"); - nm_ip4_config_set_metered(ip4_config, str && strstr(str, "ANDROID_METERED")); + if (str && strstr(str, "ANDROID_METERED")) + nm_l3_config_data_set_metered(l3cd, TRUE); - return g_steal_pointer(&ip4_config); + str = g_hash_table_lookup(options, "wpad"); + if (str) { + nm_l3_config_data_set_proxy_method(l3cd, NM_PROXY_CONFIG_METHOD_AUTO); + nm_l3_config_data_set_proxy_pac_url(l3cd, str); + } + + return g_steal_pointer(&l3cd); } /*****************************************************************************/ -static void -ip6_add_domain_search(gpointer data, gpointer user_data) -{ - nm_ip6_config_add_search(NM_IP6_CONFIG(user_data), (const char *) data); -} - NMPlatformIP6Address nm_dhcp_utils_ip6_prefix_from_options(GHashTable *options) { @@ -635,25 +625,30 @@ nm_dhcp_utils_ip6_prefix_from_options(GHashTable *options) return address; } -NMIP6Config * +NML3ConfigData * nm_dhcp_utils_ip6_config_from_options(NMDedupMultiIndex *multi_idx, int ifindex, const char * iface, GHashTable * options, gboolean info_only) { - gs_unref_object NMIP6Config *ip6_config = NULL; - struct in6_addr tmp_addr; - NMPlatformIP6Address address; - char * str = NULL; + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + struct in6_addr tmp_addr; + NMPlatformIP6Address address; + char * str = NULL; + guint32 now; g_return_val_if_fail(options != NULL, NULL); - memset(&address, 0, sizeof(address)); - address.plen = 128; - address.timestamp = nm_utils_get_monotonic_timestamp_sec(); + now = nm_utils_get_monotonic_timestamp_sec(); - ip6_config = nm_ip6_config_new(multi_idx, ifindex); + address = (NMPlatformIP6Address){ + .plen = 128, + .timestamp = now, + }; + + l3cd = nm_l3_config_data_new(multi_idx, ifindex); + nm_l3_config_data_set_source(l3cd, NM_IP_CONFIG_SOURCE_DHCP); str = g_hash_table_lookup(options, "max_life"); if (str) { @@ -676,7 +671,7 @@ nm_dhcp_utils_ip6_config_from_options(NMDedupMultiIndex *multi_idx, address.address = tmp_addr; address.addr_source = NM_IP_CONFIG_SOURCE_DHCP; - nm_ip6_config_add_address(ip6_config, &address); + nm_l3_config_data_add_address_6(l3cd, &address); _LOG2I(LOGD_DHCP6, iface, " address %s", str); } else if (info_only == FALSE) { /* No address in Managed mode is a hard error */ @@ -695,7 +690,7 @@ nm_dhcp_utils_ip6_config_from_options(NMDedupMultiIndex *multi_idx, for (s = dns; dns && *s; s++) { if (inet_pton(AF_INET6, *s, &tmp_addr) > 0) { if (!IN6_IS_ADDR_UNSPECIFIED(&tmp_addr)) { - nm_ip6_config_add_nameserver(ip6_config, &tmp_addr); + nm_l3_config_data_add_nameserver(l3cd, AF_INET6, &tmp_addr); _LOG2I(LOGD_DHCP6, iface, " nameserver '%s'", *s); } } else @@ -705,9 +700,9 @@ nm_dhcp_utils_ip6_config_from_options(NMDedupMultiIndex *multi_idx, str = g_hash_table_lookup(options, "dhcp6_domain_search"); if (str) - process_domain_search(iface, str, ip6_add_domain_search, ip6_config); + process_domain_search(AF_INET6, iface, str, l3cd); - return g_steal_pointer(&ip6_config); + return g_steal_pointer(&l3cd); } char * @@ -838,6 +833,65 @@ nm_dhcp_utils_get_dhcp6_event_id(GHashTable *lease) return g_strdup_printf("%s|%s", iaid, start); } +gboolean +nm_dhcp_utils_merge_new_dhcp6_lease(const NML3ConfigData * l3cd_old, + const NML3ConfigData * l3cd_new, + const NML3ConfigData **out_l3cd_merged) +{ + nm_auto_unref_l3cd_init NML3ConfigData *l3cd_merged = NULL; + const NMPlatformIP6Address * addr; + NMDhcpLease * lease_old; + NMDhcpLease * lease_new; + NMDedupMultiIter iter; + const char * start; + const char * iaid; + + nm_assert(out_l3cd_merged); + nm_assert(!*out_l3cd_merged); + + if (!l3cd_old) + return FALSE; + if (!l3cd_new) + return FALSE; + + lease_new = nm_l3_config_data_get_dhcp_lease(l3cd_new, AF_INET6); + if (!lease_new) + return FALSE; + + lease_old = nm_l3_config_data_get_dhcp_lease(l3cd_old, AF_INET6); + if (!lease_old) + return FALSE; + + start = nm_dhcp_lease_lookup_option(lease_new, "life_starts"); + if (!start) + return FALSE; + iaid = nm_dhcp_lease_lookup_option(lease_new, "iaid"); + if (!iaid) + return FALSE; + + if (!nm_streq0(start, nm_dhcp_lease_lookup_option(lease_old, "life_starts"))) + return FALSE; + if (!nm_streq0(iaid, nm_dhcp_lease_lookup_option(lease_old, "iaid"))) + return FALSE; + + /* If the server sends multiple IPv6 addresses, we receive a state + * changed event for each of them. Use the event ID to merge IPv6 + * addresses from the same transaction into a single configuration. + **/ + + l3cd_merged = nm_l3_config_data_new_clone(l3cd_old, -1); + + nm_l3_config_data_iter_ip6_address_for_each (&iter, l3cd_new, &addr) + nm_l3_config_data_add_address_6(l3cd_merged, addr); + + /* Note that we keep the original NMDhcpLease. All we take from the new lease are the + * addresses. Maybe this is not right?? */ + nm_l3_config_data_set_dhcp_lease(l3cd_merged, AF_INET6, lease_old); + + *out_l3cd_merged = nm_l3_config_data_ref_and_seal(g_steal_pointer(&l3cd_merged)); + return TRUE; +} + /*****************************************************************************/ gboolean diff --git a/src/core/dhcp/nm-dhcp-utils.h b/src/core/dhcp/nm-dhcp-utils.h index 69715f90fe..bee10de3f6 100644 --- a/src/core/dhcp/nm-dhcp-utils.h +++ b/src/core/dhcp/nm-dhcp-utils.h @@ -8,21 +8,18 @@ #include -#include "nm-ip4-config.h" -#include "nm-ip6-config.h" - -NMIP4Config *nm_dhcp_utils_ip4_config_from_options(struct _NMDedupMultiIndex *multi_idx, - int ifindex, - const char * iface, - GHashTable * options, - guint32 route_table, - guint32 route_metric); - -NMIP6Config *nm_dhcp_utils_ip6_config_from_options(struct _NMDedupMultiIndex *multi_idx, - int ifindex, - const char * iface, - GHashTable * options, - gboolean info_only); +#include "nm-l3-config-data.h" + +NML3ConfigData *nm_dhcp_utils_ip4_config_from_options(struct _NMDedupMultiIndex *multi_idx, + int ifindex, + const char * iface, + GHashTable * options); + +NML3ConfigData *nm_dhcp_utils_ip6_config_from_options(struct _NMDedupMultiIndex *multi_idx, + int ifindex, + const char * iface, + GHashTable * options, + gboolean info_only); NMPlatformIP6Address nm_dhcp_utils_ip6_prefix_from_options(GHashTable *options); @@ -38,6 +35,10 @@ gboolean nm_dhcp_utils_get_leasefile_path(int addr_family, char *nm_dhcp_utils_get_dhcp6_event_id(GHashTable *lease); +gboolean nm_dhcp_utils_merge_new_dhcp6_lease(const NML3ConfigData * l3cd_old, + const NML3ConfigData * l3cd_new, + const NML3ConfigData **out_l3cd_merged); + /*****************************************************************************/ static inline gboolean diff --git a/src/core/dhcp/tests/test-dhcp-dhclient.c b/src/core/dhcp/tests/test-dhcp-dhclient.c index e9a6209644..803933ff04 100644 --- a/src/core/dhcp/tests/test-dhcp-dhclient.c +++ b/src/core/dhcp/tests/test-dhcp-dhclient.c @@ -15,7 +15,6 @@ #include "dhcp/nm-dhcp-dhclient-utils.h" #include "dhcp/nm-dhcp-utils.h" #include "nm-utils.h" -#include "nm-ip4-config.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 4d47e7e283..0fab5c15ad 100644 --- a/src/core/dhcp/tests/test-dhcp-utils.c +++ b/src/core/dhcp/tests/test-dhcp-utils.c @@ -20,20 +20,18 @@ /*****************************************************************************/ -static NMIP4Config * -_ip4_config_from_options(int ifindex, const char *iface, GHashTable *options, guint32 route_metric) +static const NML3ConfigData * +_ip4_config_from_options(int ifindex, const char *iface, GHashTable *options) { nm_auto_unref_dedup_multi_index NMDedupMultiIndex *multi_idx = nm_dedup_multi_index_new(); - NMIP4Config * config; - - config = nm_dhcp_utils_ip4_config_from_options(multi_idx, - ifindex, - iface, - options, - RT_TABLE_MAIN, - route_metric); - g_assert(config); - return config; + NML3ConfigData * l3cd; + + l3cd = nm_dhcp_utils_ip4_config_from_options(multi_idx, ifindex, iface, options); + g_assert(NM_IS_L3_CONFIG_DATA(l3cd)); + g_assert(!nm_l3_config_data_is_sealed(l3cd)); + if (nmtst_get_rand_bool()) + nm_l3_config_data_seal(l3cd); + return l3cd; } typedef struct { @@ -74,58 +72,57 @@ static const Option generic_options[] = { static void test_generic_options(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const NMPlatformIP4Address * address; - const NMPlatformIP4Route * route; - guint32 tmp; - const char * expected_addr = "192.168.1.106"; - const char * expected_gw = "192.168.1.1"; - const char * expected_dns1 = "216.254.95.2"; - const char * expected_dns2 = "216.231.41.2"; - const char * expected_search1 = "foobar.com"; - const char * expected_search2 = "blah.foobar.com"; - const char * expected_route1_dest = "10.1.1.5"; - const char * expected_route1_gw = "10.1.1.1"; - const char * expected_route2_dest = "100.99.88.56"; - const char * expected_route2_gw = "10.1.1.1"; - - options = fill_table(generic_options, NULL); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - - /* IP4 address */ - g_assert_cmpint(nm_ip4_config_get_num_addresses(ip4_config), ==, 1); - address = _nmtst_ip4_config_get_address(ip4_config, 0); + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const NMPlatformIP4Address * address; + const NMPlatformIP4Route * route; + guint32 tmp; + const char * expected_addr = "192.168.1.106"; + const char * expected_gw = "192.168.1.1"; + const char * expected_dns1 = "216.254.95.2"; + const char * expected_dns2 = "216.231.41.2"; + const char * expected_search1 = "foobar.com"; + const char * expected_search2 = "blah.foobar.com"; + const char * expected_route1_dest = "10.1.1.5"; + const char * expected_route1_gw = "10.1.1.1"; + const char * expected_route2_dest = "100.99.88.56"; + const char * expected_route2_gw = "10.1.1.1"; + const char *const * strarr; + const in_addr_t * ia_arr; + guint u; + + options = fill_table(generic_options, NULL); + l3cd = _ip4_config_from_options(1, "eth0", options); + + g_assert_cmpint(nm_l3_config_data_get_num_addresses(l3cd, AF_INET), ==, 1); + address = nmtst_l3_config_data_get_address_at_4(l3cd, 0); g_assert(inet_pton(AF_INET, expected_addr, &tmp) > 0); g_assert(address->address == tmp); g_assert(address->peer_address == tmp); g_assert_cmpint(address->plen, ==, 24); - /* Gateway */ - g_assert(inet_pton(AF_INET, expected_gw, &tmp) > 0); - g_assert(nmtst_ip4_config_get_gateway(ip4_config) == tmp); + nmtst_assert_ip_address(AF_INET, + nmtst_l3_config_data_get_best_gateway(l3cd, AF_INET), + expected_gw); - g_assert_cmpint(nm_ip4_config_get_num_wins(ip4_config), ==, 0); + g_assert(!nm_l3_config_data_get_wins(l3cd, &u)); + g_assert_cmpint(u, ==, 0); - g_assert_cmpint(nm_ip4_config_get_mtu(ip4_config), ==, 987); + g_assert_cmpint(nm_l3_config_data_get_mtu(l3cd), ==, 987); - /* Domain searches */ - g_assert_cmpint(nm_ip4_config_get_num_searches(ip4_config), ==, 2); - g_assert_cmpstr(nm_ip4_config_get_search(ip4_config, 0), ==, expected_search1); - g_assert_cmpstr(nm_ip4_config_get_search(ip4_config, 1), ==, expected_search2); + strarr = nm_l3_config_data_get_searches(l3cd, AF_INET, &u); + g_assert_cmpint(u, ==, 2); + g_assert_cmpstr(strarr[0], ==, expected_search1); + g_assert_cmpstr(strarr[1], ==, expected_search2); - /* DNS servers */ - g_assert_cmpint(nm_ip4_config_get_num_nameservers(ip4_config), ==, 2); - g_assert(inet_pton(AF_INET, expected_dns1, &tmp) > 0); - g_assert(nm_ip4_config_get_nameserver(ip4_config, 0) == tmp); - g_assert(inet_pton(AF_INET, expected_dns2, &tmp) > 0); - g_assert(nm_ip4_config_get_nameserver(ip4_config, 1) == tmp); + ia_arr = nm_l3_config_data_get_nameservers(l3cd, AF_INET, &u); + g_assert_cmpint(u, ==, 2); + nmtst_assert_ip4_address(ia_arr[0], expected_dns1); + nmtst_assert_ip4_address(ia_arr[1], expected_dns2); - /* Routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 3); + g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 3); - /* Route #1 */ - route = _nmtst_ip4_config_get_route(ip4_config, 0); + route = nmtst_l3_config_data_get_route_at_4(l3cd, 0); g_assert(inet_pton(AF_INET, expected_route1_dest, &tmp) > 0); g_assert(route->network == tmp); g_assert(inet_pton(AF_INET, expected_route1_gw, &tmp) > 0); @@ -133,69 +130,63 @@ test_generic_options(void) g_assert_cmpint(route->plen, ==, 32); g_assert_cmpint(route->metric, ==, 0); - /* Route #2 */ - route = _nmtst_ip4_config_get_route(ip4_config, 1); + route = nmtst_l3_config_data_get_route_at_4(l3cd, 1); g_assert(route->network == nmtst_inet4_from_string(expected_route2_dest)); g_assert(route->gateway == nmtst_inet4_from_string(expected_route2_gw)); g_assert_cmpint(route->plen, ==, 32); g_assert_cmpint(route->metric, ==, 0); - route = _nmtst_ip4_config_get_route(ip4_config, 2); + route = nmtst_l3_config_data_get_route_at_4(l3cd, 2); g_assert(route->network == nmtst_inet4_from_string("0.0.0.0")); g_assert(route->gateway == nmtst_inet4_from_string("192.168.1.1")); g_assert_cmpint(route->plen, ==, 0); g_assert_cmpint(route->metric, ==, 0); - - g_hash_table_destroy(options); } static void test_wins_options(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const NMPlatformIP4Address * address; - guint32 tmp; - const char * expected_wins1 = "63.12.199.5"; - const char * expected_wins2 = "150.4.88.120"; - static const Option data[] = {{"netbios_name_servers", "63.12.199.5 150.4.88.120"}, + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const NMPlatformIP4Address * address; + const char * expected_wins1 = "63.12.199.5"; + const char * expected_wins2 = "150.4.88.120"; + static const Option data[] = {{"netbios_name_servers", "63.12.199.5 150.4.88.120"}, {NULL, NULL}}; + const in_addr_t * ia_arr; + guint u; - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + options = fill_table(generic_options, NULL); + options = fill_table(data, options); + l3cd = _ip4_config_from_options(1, "eth0", options); - /* IP4 address */ - g_assert_cmpint(nm_ip4_config_get_num_addresses(ip4_config), ==, 1); - address = _nmtst_ip4_config_get_address(ip4_config, 0); + g_assert_cmpint(nm_l3_config_data_get_num_addresses(l3cd, AF_INET), ==, 1); + address = nmtst_l3_config_data_get_address_at_4(l3cd, 0); g_assert(address); - g_assert_cmpint(nm_ip4_config_get_num_wins(ip4_config), ==, 2); - g_assert(inet_pton(AF_INET, expected_wins1, &tmp) > 0); - g_assert(nm_ip4_config_get_wins(ip4_config, 0) == tmp); - g_assert(inet_pton(AF_INET, expected_wins2, &tmp) > 0); - g_assert(nm_ip4_config_get_wins(ip4_config, 1) == tmp); - g_hash_table_destroy(options); + ia_arr = nm_l3_config_data_get_wins(l3cd, &u); + g_assert_cmpint(u, ==, 2); + nmtst_assert_ip4_address(ia_arr[0], expected_wins1); + nmtst_assert_ip4_address(ia_arr[1], expected_wins2); } static void test_vendor_option_metered(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; static const Option data[] = {{"vendor_encapsulated_options", "ANDROID_METERED"}, {NULL, NULL}}; - options = fill_table(generic_options, NULL); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - g_assert(nm_ip4_config_get_metered(ip4_config) == FALSE); - g_hash_table_destroy(options); - g_clear_object(&ip4_config); - - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - g_assert(nm_ip4_config_get_metered(ip4_config) == TRUE); - g_hash_table_destroy(options); + options = fill_table(generic_options, NULL); + l3cd = _ip4_config_from_options(1, "eth0", options); + g_assert(nm_l3_config_data_get_metered(l3cd) == NM_TERNARY_DEFAULT); + nm_clear_pointer(&options, g_hash_table_destroy); + nm_clear_l3cd(&l3cd); + + options = fill_table(generic_options, NULL); + options = fill_table(data, options); + l3cd = _ip4_config_from_options(1, "eth0", options); + g_assert(nm_l3_config_data_get_metered(l3cd) == TRUE); } static void @@ -252,18 +243,18 @@ test_parse_search_list(void) } static void -ip4_test_route(NMIP4Config *ip4_config, - guint route_num, - const char * expected_dest, - const char * expected_gw, - guint expected_prefix) +ip4_test_route(const NML3ConfigData *l3cd, + guint route_num, + const char * expected_dest, + const char * expected_gw, + guint expected_prefix) { const NMPlatformIP4Route *route; guint32 tmp; g_assert(expected_prefix <= 32); - route = _nmtst_ip4_config_get_route(ip4_config, route_num); + route = nmtst_l3_config_data_get_route_at_4(l3cd, route_num); g_assert(inet_pton(AF_INET, expected_dest, &tmp) > 0); g_assert(route->network == tmp); g_assert(inet_pton(AF_INET, expected_gw, &tmp) > 0); @@ -272,110 +263,105 @@ ip4_test_route(NMIP4Config *ip4_config, g_assert_cmpint(route->metric, ==, 0); } -static void -ip4_test_gateway(NMIP4Config *ip4_config, const char *expected_gw) -{ - guint32 tmp; - - g_assert_cmpint(nm_ip4_config_get_num_addresses(ip4_config), ==, 1); - g_assert(inet_pton(AF_INET, expected_gw, &tmp) > 0); - g_assert(nmtst_ip4_config_get_gateway(ip4_config) == tmp); -} +#define ip4_test_gateway(l3cd, expected_gw) \ + G_STMT_START \ + { \ + const NML3ConfigData *_l3cd = (l3cd); \ + \ + g_assert_cmpint(nm_l3_config_data_get_num_addresses(_l3cd, AF_INET), ==, 1); \ + nmtst_assert_ip_address(AF_INET, \ + nmtst_l3_config_data_get_best_gateway(_l3cd, AF_INET), \ + expected_gw); \ + } \ + G_STMT_END static void test_classless_static_routes_1(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "192.168.10.0"; - const char * expected_route1_gw = "192.168.1.1"; - const char * expected_route2_dest = "10.0.0.0"; - const char * expected_route2_gw = "10.17.66.41"; - static const Option data[] = { + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const char * expected_route1_dest = "192.168.10.0"; + const char * expected_route1_gw = "192.168.1.1"; + const char * expected_route2_dest = "10.0.0.0"; + const char * expected_route2_gw = "10.17.66.41"; + static const Option data[] = { /* dhclient custom format */ {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 8 10 10 17 66 41"}, {NULL, NULL}}; - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + options = fill_table(generic_options, NULL); + options = fill_table(data, options); + l3cd = _ip4_config_from_options(1, "eth0", options); /* IP4 routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 3); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); - ip4_test_route(ip4_config, 1, expected_route2_dest, expected_route2_gw, 8); - ip4_test_route(ip4_config, 2, "0.0.0.0", "192.168.1.1", 0); - - g_hash_table_destroy(options); + g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 3); + ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 24); + ip4_test_route(l3cd, 1, expected_route2_dest, expected_route2_gw, 8); + ip4_test_route(l3cd, 2, "0.0.0.0", "192.168.1.1", 0); } static void test_classless_static_routes_2(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "192.168.10.0"; - const char * expected_route1_gw = "192.168.1.1"; - const char * expected_route2_dest = "10.0.0.0"; - const char * expected_route2_gw = "10.17.66.41"; - static const Option data[] = { + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const char * expected_route1_dest = "192.168.10.0"; + const char * expected_route1_gw = "192.168.1.1"; + const char * expected_route2_dest = "10.0.0.0"; + const char * expected_route2_gw = "10.17.66.41"; + static const Option data[] = { /* dhcpcd format */ {"classless_static_routes", "192.168.10.0/24 192.168.1.1 10.0.0.0/8 10.17.66.41"}, {NULL, NULL}}; - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + options = fill_table(generic_options, NULL); + options = fill_table(data, options); + l3cd = _ip4_config_from_options(1, "eth0", options); /* IP4 routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 3); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); - ip4_test_route(ip4_config, 1, expected_route2_dest, expected_route2_gw, 8); - ip4_test_route(ip4_config, 2, "0.0.0.0", expected_route1_gw, 0); - - g_hash_table_destroy(options); + g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 3); + ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 24); + ip4_test_route(l3cd, 1, expected_route2_dest, expected_route2_gw, 8); + ip4_test_route(l3cd, 2, "0.0.0.0", expected_route1_gw, 0); } static void test_fedora_dhclient_classless_static_routes(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "129.210.177.128"; - const char * expected_route1_gw = "192.168.0.113"; - const char * expected_route2_dest = "2.0.0.0"; - const char * expected_route2_gw = "10.34.255.6"; - const char * expected_gateway = "192.168.0.113"; - static const Option data[] = { + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const char * expected_route1_dest = "129.210.177.128"; + const char * expected_route1_gw = "192.168.0.113"; + const char * expected_route2_dest = "2.0.0.0"; + const char * expected_route2_gw = "10.34.255.6"; + const char * expected_gateway = "192.168.0.113"; + static const Option data[] = { /* Fedora dhclient format */ {"classless_static_routes", "0 192.168.0.113 25.129.210.177.132 192.168.0.113 7.2 10.34.255.6"}, {NULL, NULL}}; - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + options = fill_table(generic_options, NULL); + options = fill_table(data, options); + l3cd = _ip4_config_from_options(1, "eth0", options); /* IP4 routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 3); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 25); - ip4_test_route(ip4_config, 1, expected_route2_dest, expected_route2_gw, 7); - ip4_test_route(ip4_config, 2, "0.0.0.0", expected_route1_gw, 0); + g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 3); + ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 25); + ip4_test_route(l3cd, 1, expected_route2_dest, expected_route2_gw, 7); + ip4_test_route(l3cd, 2, "0.0.0.0", expected_route1_gw, 0); - /* Gateway */ - ip4_test_gateway(ip4_config, expected_gateway); - - g_hash_table_destroy(options); + ip4_test_gateway(l3cd, expected_gateway); } static void test_dhclient_invalid_classless_routes_1(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "192.168.10.0"; - const char * expected_route1_gw = "192.168.1.1"; - static const Option data[] = { + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const char * expected_route1_dest = "192.168.10.0"; + const char * expected_route1_gw = "192.168.1.1"; + static const Option data[] = { /* dhclient format */ {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 45 10 17 66 41"}, {NULL, NULL}}; @@ -384,27 +370,25 @@ test_dhclient_invalid_classless_routes_1(void) options = fill_table(data, options); NMTST_EXPECT_NM_WARN("*ignoring invalid classless static routes*"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + l3cd = _ip4_config_from_options(1, "eth0", options); g_test_assert_expected_messages(); /* IP4 routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 2); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); - ip4_test_route(ip4_config, 1, "0.0.0.0", expected_route1_gw, 0); - - g_hash_table_destroy(options); + g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 2); + ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 24); + ip4_test_route(l3cd, 1, "0.0.0.0", expected_route1_gw, 0); } static void test_dhcpcd_invalid_classless_routes_1(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "10.1.1.5"; - const char * expected_route1_gw = "10.1.1.1"; - const char * expected_route2_dest = "100.99.88.56"; - const char * expected_route2_gw = "10.1.1.1"; - static const Option data[] = { + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const char * expected_route1_dest = "10.1.1.5"; + const char * expected_route1_gw = "10.1.1.1"; + const char * expected_route2_dest = "100.99.88.56"; + const char * expected_route2_gw = "10.1.1.1"; + static const Option data[] = { /* dhcpcd format */ {"classless_static_routes", "192.168.10.0/24 192.168.1.1 10.0.adfadf/44 10.17.66.41"}, {NULL, NULL}}; @@ -413,30 +397,28 @@ test_dhcpcd_invalid_classless_routes_1(void) options = fill_table(data, options); NMTST_EXPECT_NM_WARN("*ignoring invalid classless static routes*"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + l3cd = _ip4_config_from_options(1, "eth0", options); g_test_assert_expected_messages(); /* Test falling back to old-style static routes if the classless static * routes are invalid. */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 3); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 32); - ip4_test_route(ip4_config, 1, expected_route2_dest, expected_route2_gw, 32); - ip4_test_route(ip4_config, 2, "0.0.0.0", "192.168.1.1", 0); - - g_hash_table_destroy(options); + g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 3); + ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 32); + ip4_test_route(l3cd, 1, expected_route2_dest, expected_route2_gw, 32); + ip4_test_route(l3cd, 2, "0.0.0.0", "192.168.1.1", 0); } static void test_dhclient_invalid_classless_routes_2(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "10.1.1.5"; - const char * expected_route1_gw = "10.1.1.1"; - const char * expected_route2_dest = "100.99.88.56"; - const char * expected_route2_gw = "10.1.1.1"; - static const Option data[] = { + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const char * expected_route1_dest = "10.1.1.5"; + const char * expected_route1_gw = "10.1.1.1"; + const char * expected_route2_dest = "100.99.88.56"; + const char * expected_route2_gw = "10.1.1.1"; + static const Option data[] = { {"rfc3442_classless_static_routes", "45 10 17 66 41 24 192 168 10 192 168 1 1"}, {NULL, NULL}}; @@ -444,30 +426,28 @@ test_dhclient_invalid_classless_routes_2(void) options = fill_table(data, options); NMTST_EXPECT_NM_WARN("*ignoring invalid classless static routes*"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + l3cd = _ip4_config_from_options(1, "eth0", options); g_test_assert_expected_messages(); /* Test falling back to old-style static routes if the classless static * routes are invalid. */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 3); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 32); - ip4_test_route(ip4_config, 1, expected_route2_dest, expected_route2_gw, 32); - ip4_test_route(ip4_config, 2, "0.0.0.0", "192.168.1.1", 0); - - g_hash_table_destroy(options); + g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 3); + ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 32); + ip4_test_route(l3cd, 1, expected_route2_dest, expected_route2_gw, 32); + ip4_test_route(l3cd, 2, "0.0.0.0", "192.168.1.1", 0); } static void test_dhcpcd_invalid_classless_routes_2(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "10.1.1.5"; - const char * expected_route1_gw = "10.1.1.1"; - const char * expected_route2_dest = "100.99.88.56"; - const char * expected_route2_gw = "10.1.1.1"; - static const Option data[] = { + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const char * expected_route1_dest = "10.1.1.5"; + const char * expected_route1_gw = "10.1.1.1"; + const char * expected_route2_dest = "100.99.88.56"; + const char * expected_route2_gw = "10.1.1.1"; + static const Option data[] = { {"classless_static_routes", "10.0.adfadf/44 10.17.66.41 192.168.10.0/24 192.168.1.1"}, {NULL, NULL}}; @@ -475,7 +455,7 @@ test_dhcpcd_invalid_classless_routes_2(void) options = fill_table(data, options); NMTST_EXPECT_NM_WARN("*ignoring invalid classless static routes*"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + l3cd = _ip4_config_from_options(1, "eth0", options); g_test_assert_expected_messages(); /* Test falling back to old-style static routes if the classless static @@ -483,22 +463,20 @@ test_dhcpcd_invalid_classless_routes_2(void) */ /* Routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 3); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 32); - ip4_test_route(ip4_config, 1, expected_route2_dest, expected_route2_gw, 32); - ip4_test_route(ip4_config, 2, "0.0.0.0", "192.168.1.1", 0); - - g_hash_table_destroy(options); + g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 3); + ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 32); + ip4_test_route(l3cd, 1, expected_route2_dest, expected_route2_gw, 32); + ip4_test_route(l3cd, 2, "0.0.0.0", "192.168.1.1", 0); } static void test_dhclient_invalid_classless_routes_3(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "192.168.10.0"; - const char * expected_route1_gw = "192.168.1.1"; - static const Option data[] = { + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const char * expected_route1_dest = "192.168.10.0"; + const char * expected_route1_gw = "192.168.1.1"; + static const Option data[] = { {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 32 128 10 17 66 41"}, {NULL, NULL}}; @@ -506,25 +484,23 @@ test_dhclient_invalid_classless_routes_3(void) options = fill_table(data, options); NMTST_EXPECT_NM_WARN("*ignoring invalid classless static routes*"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + l3cd = _ip4_config_from_options(1, "eth0", options); g_test_assert_expected_messages(); /* IP4 routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 2); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); - ip4_test_route(ip4_config, 1, "0.0.0.0", expected_route1_gw, 0); - - g_hash_table_destroy(options); + g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 2); + ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 24); + ip4_test_route(l3cd, 1, "0.0.0.0", expected_route1_gw, 0); } static void test_dhcpcd_invalid_classless_routes_3(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "192.168.10.0"; - const char * expected_route1_gw = "192.168.1.1"; - static Option data[] = { + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const char * expected_route1_dest = "192.168.10.0"; + const char * expected_route1_gw = "192.168.1.1"; + static Option data[] = { {"classless_static_routes", "192.168.10.0/24 192.168.1.1 128/32 10.17.66.41"}, {NULL, NULL}}; @@ -532,133 +508,124 @@ test_dhcpcd_invalid_classless_routes_3(void) options = fill_table(data, options); NMTST_EXPECT_NM_WARN("*DHCP provided invalid classless static route*"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + l3cd = _ip4_config_from_options(1, "eth0", options); g_test_assert_expected_messages(); /* IP4 routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 2); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); - ip4_test_route(ip4_config, 1, "0.0.0.0", expected_route1_gw, 0); - - g_hash_table_destroy(options); + g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 2); + ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 24); + ip4_test_route(l3cd, 1, "0.0.0.0", expected_route1_gw, 0); } static void test_dhclient_gw_in_classless_routes(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "192.168.10.0"; - const char * expected_route1_gw = "192.168.1.1"; - const char * expected_gateway = "192.2.3.4"; - static Option data[] = { + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const char * expected_route1_dest = "192.168.10.0"; + const char * expected_route1_gw = "192.168.1.1"; + const char * expected_gateway = "192.2.3.4"; + static Option data[] = { {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 0 192 2 3 4"}, {NULL, NULL}}; - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + options = fill_table(generic_options, NULL); + options = fill_table(data, options); + l3cd = _ip4_config_from_options(1, "eth0", options); /* IP4 routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 2); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); - ip4_test_route(ip4_config, 1, "0.0.0.0", "192.2.3.4", 0); - - /* Gateway */ - ip4_test_gateway(ip4_config, expected_gateway); + g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 2); + ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 24); + ip4_test_route(l3cd, 1, "0.0.0.0", "192.2.3.4", 0); - g_hash_table_destroy(options); + ip4_test_gateway(l3cd, expected_gateway); } static void test_dhcpcd_gw_in_classless_routes(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "192.168.10.0"; - const char * expected_route1_gw = "192.168.1.1"; - const char * expected_gateway = "192.2.3.4"; - static Option data[] = { + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const char * expected_route1_dest = "192.168.10.0"; + const char * expected_route1_gw = "192.168.1.1"; + const char * expected_gateway = "192.2.3.4"; + static Option data[] = { {"classless_static_routes", "192.168.10.0/24 192.168.1.1 0.0.0.0/0 192.2.3.4"}, {NULL, NULL}}; - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + options = fill_table(generic_options, NULL); + options = fill_table(data, options); + l3cd = _ip4_config_from_options(1, "eth0", options); /* IP4 routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 2); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); - ip4_test_route(ip4_config, 1, "0.0.0.0", "192.2.3.4", 0); - - /* Gateway */ - ip4_test_gateway(ip4_config, expected_gateway); + g_assert_cmpint(nm_l3_config_data_get_num_routes(l3cd, AF_INET), ==, 2); + ip4_test_route(l3cd, 0, expected_route1_dest, expected_route1_gw, 24); + ip4_test_route(l3cd, 1, "0.0.0.0", "192.2.3.4", 0); - g_hash_table_destroy(options); + ip4_test_gateway(l3cd, expected_gateway); } static void test_escaped_domain_searches(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_search0 = "host1"; - const char * expected_search1 = "host2"; - const char * expected_search2 = "host3"; + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const char * expected_search0 = "host1"; + const char * expected_search1 = "host2"; + const char * expected_search2 = "host3"; static const Option data[] = {{"domain_search", "host1\\032host2\\032host3"}, {NULL, NULL}}; + const char *const * strarr; + guint u; - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - - /* domain searches */ - g_assert_cmpint(nm_ip4_config_get_num_searches(ip4_config), ==, 3); - g_assert_cmpstr(nm_ip4_config_get_search(ip4_config, 0), ==, expected_search0); - g_assert_cmpstr(nm_ip4_config_get_search(ip4_config, 1), ==, expected_search1); - g_assert_cmpstr(nm_ip4_config_get_search(ip4_config, 2), ==, expected_search2); + options = fill_table(generic_options, NULL); + options = fill_table(data, options); + l3cd = _ip4_config_from_options(1, "eth0", options); - g_hash_table_destroy(options); + strarr = nm_l3_config_data_get_searches(l3cd, AF_INET, &u); + g_assert_cmpint(u, ==, 3); + g_assert_cmpstr(strarr[0], ==, expected_search0); + g_assert_cmpstr(strarr[1], ==, expected_search1); + g_assert_cmpstr(strarr[2], ==, expected_search2); } static void test_invalid_escaped_domain_searches(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; static const Option data[] = {{"domain_search", "host1\\aahost2\\032host3"}, {NULL, NULL}}; + const char *const * strarr; + guint u; options = fill_table(generic_options, NULL); options = fill_table(data, options); NMTST_EXPECT_NM_WARN("*invalid domain search*"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + l3cd = _ip4_config_from_options(1, "eth0", options); g_test_assert_expected_messages(); - /* domain searches */ - g_assert_cmpint(nm_ip4_config_get_num_searches(ip4_config), ==, 0); - - g_hash_table_destroy(options); + strarr = nm_l3_config_data_get_searches(l3cd, AF_INET, &u); + g_assert_cmpint(u, ==, 0); + g_assert(!strarr); } static void test_ip4_missing_prefix(const char *ip, guint32 expected_prefix) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const NMPlatformIP4Address * address; + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const NMPlatformIP4Address * address; options = fill_table(generic_options, NULL); g_hash_table_insert(options, "ip_address", (gpointer) ip); g_hash_table_remove(options, "subnet_mask"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + l3cd = _ip4_config_from_options(1, "eth0", options); - g_assert_cmpint(nm_ip4_config_get_num_addresses(ip4_config), ==, 1); - address = _nmtst_ip4_config_get_address(ip4_config, 0); + g_assert_cmpint(nm_l3_config_data_get_num_addresses(l3cd, AF_INET), ==, 1); + address = nmtst_l3_config_data_get_address_at_4(l3cd, 0); g_assert(address); g_assert_cmpint(address->plen, ==, expected_prefix); - - g_hash_table_destroy(options); } static void @@ -682,9 +649,9 @@ test_ip4_missing_prefix_8(void) static void test_ip4_prefix_classless(void) { - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const NMPlatformIP4Address * address; + gs_unref_hashtable GHashTable *options = NULL; + nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; + const NMPlatformIP4Address * address; /* Ensure that the missing-subnet-mask handler doesn't mangle classless * subnet masks at all. The handler should trigger only if the server @@ -695,14 +662,12 @@ test_ip4_prefix_classless(void) g_hash_table_insert(options, "ip_address", "172.16.54.22"); g_hash_table_insert(options, "subnet_mask", "255.255.252.0"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); + l3cd = _ip4_config_from_options(1, "eth0", options); - g_assert_cmpint(nm_ip4_config_get_num_addresses(ip4_config), ==, 1); - address = _nmtst_ip4_config_get_address(ip4_config, 0); + g_assert_cmpint(nm_l3_config_data_get_num_addresses(l3cd, AF_INET), ==, 1); + address = nmtst_l3_config_data_get_address_at_4(l3cd, 0); g_assert(address); g_assert_cmpint(address->plen, ==, 22); - - g_hash_table_destroy(options); } #define COMPARE_ID(src, is_str, expected, expected_len) \ diff --git a/src/core/dns/nm-dns-dnsmasq.c b/src/core/dns/nm-dns-dnsmasq.c index 126e0a217a..b40521a32b 100644 --- a/src/core/dns/nm-dns-dnsmasq.c +++ b/src/core/dns/nm-dns-dnsmasq.c @@ -19,10 +19,9 @@ #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" #include "nm-dbus-manager.h" #include "NetworkManagerUtils.h" +#include "nm-l3-config-data.h" #define PIDFILE NMRUNDIR "/dnsmasq.pid" #define CONFDIR NMCONFDIR "/dnsmasq.d" @@ -806,20 +805,22 @@ add_global_config(NMDnsDnsmasq * self, static void add_ip_config(NMDnsDnsmasq *self, GVariantBuilder *servers, const NMDnsConfigIPData *ip_data) { - NMIPConfig * ip_config = ip_data->ip_config; - gconstpointer addr; - const char * iface, *domain; + const char * iface; + const char * domain; char ip_addr_to_string_buf[IP_ADDR_TO_STRING_BUFLEN]; - int addr_family; - guint i, j, num; + gconstpointer nameservers; + guint num; + guint i; + guint j; - iface = nm_platform_link_get_name(NM_PLATFORM_GET, ip_data->data->ifindex); - addr_family = nm_ip_config_get_addr_family(ip_config); + iface = nm_platform_link_get_name(NM_PLATFORM_GET, ip_data->data->ifindex); - num = nm_ip_config_get_num_nameservers(ip_config); + nameservers = nm_l3_config_data_get_nameservers(ip_data->l3cd, ip_data->addr_family, &num); for (i = 0; i < num; i++) { - addr = nm_ip_config_get_nameserver(ip_config, i); - ip_addr_to_string(addr_family, addr, iface, ip_addr_to_string_buf); + gconstpointer addr; + + addr = nm_ip_addr_from_packed_array(ip_data->addr_family, nameservers, i); + ip_addr_to_string(ip_data->addr_family, addr, iface, ip_addr_to_string_buf); if (!ip_data->domains.has_default_route_explicit && ip_data->domains.has_default_route) add_dnsmasq_nameserver(self, servers, ip_addr_to_string_buf, NULL); @@ -846,7 +847,7 @@ add_ip_config(NMDnsDnsmasq *self, GVariantBuilder *servers, const NMDnsConfigIPD static GVariant * create_update_args(NMDnsDnsmasq * self, const NMGlobalDnsConfig *global_config, - const CList * ip_config_lst_head, + const CList * ip_data_lst_head, const char * hostname) { GVariantBuilder servers; @@ -857,7 +858,7 @@ create_update_args(NMDnsDnsmasq * self, if (global_config) add_global_config(self, &servers, global_config); else { - c_list_for_each_entry (ip_data, ip_config_lst_head, ip_config_lst) + c_list_for_each_entry (ip_data, ip_data_lst_head, ip_data_lst) add_ip_config(self, &servers, ip_data); } @@ -1122,7 +1123,7 @@ start_dnsmasq(NMDnsDnsmasq *self, gboolean force_start, GError **error) static gboolean update(NMDnsPlugin * plugin, const NMGlobalDnsConfig *global_config, - const CList * ip_config_lst_head, + const CList * ip_data_lst_head, const char * hostname, GError ** error) { @@ -1134,7 +1135,7 @@ update(NMDnsPlugin * plugin, nm_clear_pointer(&priv->set_server_ex_args, g_variant_unref); priv->set_server_ex_args = - g_variant_ref_sink(create_update_args(self, global_config, ip_config_lst_head, hostname)); + g_variant_ref_sink(create_update_args(self, global_config, ip_data_lst_head, hostname)); send_dnsmasq_update(self); return TRUE; diff --git a/src/core/dns/nm-dns-manager.c b/src/core/dns/nm-dns-manager.c index f161b14c0d..e2d8e77f2e 100644 --- a/src/core/dns/nm-dns-manager.c +++ b/src/core/dns/nm-dns-manager.c @@ -7,6 +7,8 @@ #include "src/core/nm-default-daemon.h" +#include "nm-dns-manager.h" + #include #include #include @@ -22,22 +24,20 @@ #include #endif -#include "libnm-glib-aux/nm-str-buf.h" -#include "nm-utils.h" #include "libnm-core-intern/nm-core-internal.h" -#include "nm-dns-manager.h" -#include "nm-ip4-config.h" -#include "nm-ip6-config.h" +#include "libnm-glib-aux/nm-str-buf.h" + #include "NetworkManagerUtils.h" +#include "devices/nm-device.h" #include "nm-config.h" #include "nm-dbus-object.h" -#include "devices/nm-device.h" -#include "nm-manager.h" - -#include "nm-dns-plugin.h" #include "nm-dns-dnsmasq.h" +#include "nm-dns-plugin.h" #include "nm-dns-systemd-resolved.h" #include "nm-dns-unbound.h" +#include "nm-l3-config-data.h" +#include "nm-manager.h" +#include "nm-utils.h" #define HASH_LEN NM_UTILS_CHECKSUM_LENGTH_SHA1 @@ -84,10 +84,10 @@ typedef struct { GHashTable *configs_dict; CList configs_lst_head; - CList ip_config_lst_head; + CList ip_data_lst_head; GVariant *config_variant; - bool ip_config_lst_need_sort : 1; + bool ip_data_lst_need_sort : 1; bool configs_lst_need_sort : 1; @@ -159,11 +159,6 @@ NM_DEFINE_SINGLETON_GETTER(NMDnsManager, nm_dns_manager_get, NM_TYPE_DNS_MANAGER /*****************************************************************************/ -static void -_ip_config_dns_priority_changed(gpointer config, GParamSpec *pspec, NMDnsConfigIPData *ip_data); - -/*****************************************************************************/ - static gboolean domain_is_valid(const char *domain, gboolean check_public_suffix) { @@ -208,6 +203,24 @@ static NM_UTILS_LOOKUP_STR_DEFINE( /*****************************************************************************/ +static int +_dns_config_ip_data_get_dns_priority1(const NML3ConfigData *l3cd, int addr_family) +{ + int prio; + + if (!nm_l3_config_data_get_dns_priority(l3cd, addr_family, &prio)) + return 0; + + nm_assert(prio != 0); + return prio; +} + +static int +_dns_config_ip_data_get_dns_priority(const NMDnsConfigIPData *ip_data) +{ + return _dns_config_ip_data_get_dns_priority1(ip_data->l3cd, ip_data->addr_family); +} + static void _ASSERT_dns_config_data(const NMDnsConfigData *data) { @@ -221,9 +234,9 @@ _ASSERT_dns_config_ip_data(const NMDnsConfigIPData *ip_data) { nm_assert(ip_data); _ASSERT_dns_config_data(ip_data->data); - nm_assert(NM_IS_IP_CONFIG(ip_data->ip_config)); + nm_assert(NM_IS_L3_CONFIG_DATA(ip_data->l3cd)); nm_assert(c_list_contains(&ip_data->data->data_lst_head, &ip_data->data_lst)); - nm_assert(ip_data->data->ifindex == nm_ip_config_get_ifindex(ip_data->ip_config)); + nm_assert(ip_data->data->ifindex == nm_l3_config_data_get_ifindex(ip_data->l3cd)); #if NM_MORE_ASSERTS > 5 { gboolean has_default = FALSE; @@ -243,37 +256,36 @@ _ASSERT_dns_config_ip_data(const NMDnsConfigIPData *ip_data) if (ip_data->domains.has_default_route_exclusive) nm_assert(ip_data->domains.has_default_route); } + nm_assert(_dns_config_ip_data_get_dns_priority(ip_data) != 0); #endif } static NMDnsConfigIPData * -_dns_config_ip_data_new(NMDnsConfigData * data, - NMIPConfig * ip_config, - NMDnsIPConfigType ip_config_type) +_dns_config_ip_data_new(NMDnsConfigData * data, + int addr_family, + gconstpointer source_tag, + const NML3ConfigData *l3cd, + NMDnsIPConfigType ip_config_type) { NMDnsConfigIPData *ip_data; _ASSERT_dns_config_data(data); - nm_assert(NM_IS_IP_CONFIG(ip_config)); + nm_assert(NM_IS_L3_CONFIG_DATA(l3cd)); nm_assert(ip_config_type != NM_DNS_IP_CONFIG_TYPE_REMOVED); ip_data = g_slice_new(NMDnsConfigIPData); *ip_data = (NMDnsConfigIPData){ .data = data, - .ip_config = g_object_ref(ip_config), + .source_tag = source_tag, + .l3cd = nm_l3_config_data_ref_and_seal(l3cd), .ip_config_type = ip_config_type, + .addr_family = addr_family, }; c_list_link_tail(&data->data_lst_head, &ip_data->data_lst); - 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! */ + c_list_link_tail(&NM_DNS_MANAGER_GET_PRIVATE(data->self)->ip_data_lst_head, + &ip_data->ip_data_lst); - g_signal_connect(ip_config, - NM_IS_IP4_CONFIG(ip_config) ? "notify::" NM_IP4_CONFIG_DNS_PRIORITY - : "notify::" NM_IP6_CONFIG_DNS_PRIORITY, - (GCallback) _ip_config_dns_priority_changed, - ip_data); + /* We also need to set priv->ip_data_lst_need_sort, but the caller will do that! */ _ASSERT_dns_config_ip_data(ip_data); return ip_data; @@ -285,35 +297,15 @@ _dns_config_ip_data_free(NMDnsConfigIPData *ip_data) _ASSERT_dns_config_ip_data(ip_data); c_list_unlink_stale(&ip_data->data_lst); - c_list_unlink_stale(&ip_data->ip_config_lst); + c_list_unlink_stale(&ip_data->ip_data_lst); g_free(ip_data->domains.search); g_strfreev(ip_data->domains.reverse); - g_signal_handlers_disconnect_by_func(ip_data->ip_config, - _ip_config_dns_priority_changed, - ip_data); - - g_object_unref(ip_data->ip_config); + nm_l3_config_data_unref(ip_data->l3cd); nm_g_slice_free(ip_data); } -static NMDnsConfigIPData * -_dns_config_data_find_ip_config(NMDnsConfigData *data, NMIPConfig *ip_config) -{ - NMDnsConfigIPData *ip_data; - - _ASSERT_dns_config_data(data); - - c_list_for_each_entry (ip_data, &data->data_lst_head, data_lst) { - _ASSERT_dns_config_ip_data(ip_data); - - if (ip_data->ip_config == ip_config) - return ip_data; - } - return NULL; -} - static void _dns_config_data_free(NMDnsConfigData *data) { @@ -325,14 +317,13 @@ _dns_config_data_free(NMDnsConfigData *data) } static int -_mgr_get_ip_config_lst_cmp(const CList *a_lst, const CList *b_lst, const void *user_data) +_mgr_get_ip_data_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); + const NMDnsConfigIPData *a = c_list_entry(a_lst, NMDnsConfigIPData, ip_data_lst); + const NMDnsConfigIPData *b = c_list_entry(b_lst, NMDnsConfigIPData, ip_data_lst); /* Configurations with lower priority value first */ - NM_CMP_DIRECT(nm_ip_config_get_dns_priority(a->ip_config), - nm_ip_config_get_dns_priority(b->ip_config)); + NM_CMP_DIRECT(_dns_config_ip_data_get_dns_priority(a), _dns_config_ip_data_get_dns_priority(b)); /* Sort according to type (descendingly) */ NM_CMP_FIELD(b, a, ip_config_type); @@ -341,16 +332,16 @@ _mgr_get_ip_config_lst_cmp(const CList *a_lst, const CList *b_lst, const void *u } static CList * -_mgr_get_ip_config_lst_head(NMDnsManager *self) +_mgr_get_ip_data_lst_head(NMDnsManager *self) { NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE(self); - 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); + if (G_UNLIKELY(priv->ip_data_lst_need_sort)) { + priv->ip_data_lst_need_sort = FALSE; + c_list_sort(&priv->ip_data_lst_head, _mgr_get_ip_data_lst_cmp, NULL); } - return &priv->ip_config_lst_head; + return &priv->ip_data_lst_head; } static int @@ -427,28 +418,33 @@ add_dns_option_item(GPtrArray *array, const char *str) } static void -add_dns_domains(GPtrArray * array, - const NMIPConfig *ip_config, - gboolean include_routing, - gboolean dup) +add_dns_domains(GPtrArray * array, + int addr_family, + const NML3ConfigData *l3cd, + gboolean include_routing, + gboolean dup) { - guint num_domains, num_searches, i; - const char *str; + const char *const *domains; + const char *const *searches; + guint num_domains; + guint num_searches; + guint i; + const char * str; - num_domains = nm_ip_config_get_num_domains(ip_config); - num_searches = nm_ip_config_get_num_searches(ip_config); + domains = nm_l3_config_data_get_domains(l3cd, addr_family, &num_domains); + searches = nm_l3_config_data_get_searches(l3cd, addr_family, &num_searches); for (i = 0; i < num_searches; i++) { - str = nm_ip_config_get_search(ip_config, i); + str = searches[i]; if (!include_routing && domain_is_routing(str)) continue; if (!domain_is_valid(nm_utils_parse_dns_domain(str, NULL), FALSE)) continue; add_string_item(array, str, dup); } - if (num_domains > 1 || !num_searches) { + if (num_domains > 1 || num_searches == 0) { for (i = 0; i < num_domains; i++) { - str = nm_ip_config_get_domain(ip_config, i); + str = domains[i]; if (!include_routing && domain_is_routing(str)) continue; if (!domain_is_valid(nm_utils_parse_dns_domain(str, NULL), FALSE)) @@ -459,26 +455,24 @@ add_dns_domains(GPtrArray * array, } static void -merge_one_ip_config(NMResolvConfData *rc, int ifindex, const NMIPConfig *ip_config) +merge_one_l3cd(NMResolvConfData *rc, int addr_family, int ifindex, const NML3ConfigData *l3cd) { - int addr_family; - char buf[NM_UTILS_INET_ADDRSTRLEN + 50]; - gboolean has_trust_ad; - guint num_nameservers; - guint num; - guint i; - - addr_family = nm_ip_config_get_addr_family(ip_config); + char buf[NM_UTILS_INET_ADDRSTRLEN + 50]; + gboolean has_trust_ad; + guint num_nameservers; + guint num; + guint i; + gconstpointer nameservers; + const char *const *strv; - nm_assert_addr_family(addr_family); - nm_assert(ifindex > 0); - nm_assert(ifindex == nm_ip_config_get_ifindex(ip_config)); + nm_assert(ifindex == nm_l3_config_data_get_ifindex(l3cd)); - num_nameservers = nm_ip_config_get_num_nameservers(ip_config); + nameservers = nm_l3_config_data_get_nameservers(l3cd, addr_family, &num_nameservers); for (i = 0; i < num_nameservers; i++) { const NMIPAddr *addr; - addr = nm_ip_config_get_nameserver(ip_config, i); + addr = nm_ip_addr_from_packed_array(addr_family, nameservers, i); + if (addr_family == AF_INET) nm_utils_inet_ntop(addr_family, addr, buf); else if (IN6_IS_ADDR_V4MAPPED(addr)) @@ -499,22 +493,23 @@ merge_one_ip_config(NMResolvConfData *rc, int ifindex, const NMIPConfig *ip_conf add_string_item(rc->nameservers, buf, TRUE); } - add_dns_domains(rc->searches, ip_config, FALSE, TRUE); + add_dns_domains(rc->searches, addr_family, l3cd, FALSE, TRUE); has_trust_ad = FALSE; - num = nm_ip_config_get_num_dns_options(ip_config); + strv = nm_l3_config_data_get_dns_options(l3cd, addr_family, &num); for (i = 0; i < num; i++) { - const char *option = nm_ip_config_get_dns_option(ip_config, i); + const char *option = strv[i]; if (nm_streq(option, NM_SETTING_DNS_OPTION_TRUST_AD)) { has_trust_ad = TRUE; continue; } - add_dns_option_item(rc->options, nm_ip_config_get_dns_option(ip_config, i)); + add_dns_option_item(rc->options, option); } + if (num_nameservers == 0) { - /* If the @ip_config contributes no DNS servers, ignore whether trust-ad is set or unset - * for this @ip_config. */ + /* If the @l3cd contributes no DNS servers, ignore whether trust-ad is set or unset + * for this @l3cd. */ } else if (has_trust_ad) { /* We only set has_trust_ad to TRUE, if all IP configs agree (or don't contribute). * Once set to FALSE, it doesn't get reset. */ @@ -524,20 +519,17 @@ merge_one_ip_config(NMResolvConfData *rc, int ifindex, const NMIPConfig *ip_conf rc->has_trust_ad = NM_TERNARY_FALSE; if (addr_family == AF_INET) { - const NMIP4Config *ip4_config = (const NMIP4Config *) ip_config; + const in_addr_t *nis_servers; + const char * nis_domain; - /* NIS stuff */ - num = nm_ip4_config_get_num_nis_servers(ip4_config); - for (i = 0; i < num; i++) { - add_string_item(rc->nis_servers, - _nm_utils_inet4_ntop(nm_ip4_config_get_nis_server(ip4_config, i), buf), - TRUE); - } + nis_servers = nm_l3_config_data_get_nis_servers(l3cd, &num); + for (i = 0; i < num; i++) + add_string_item(rc->nis_servers, _nm_utils_inet4_ntop(nis_servers[i], buf), TRUE); - if (nm_ip4_config_get_nis_domain(ip4_config)) { + if ((nis_domain = nm_l3_config_data_get_nis_domain(l3cd))) { /* FIXME: handle multiple domains */ if (!rc->nis_domain) - rc->nis_domain = nm_ip4_config_get_nis_domain(ip4_config); + rc->nis_domain = nis_domain; } } } @@ -1119,9 +1111,9 @@ 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_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); + head = _mgr_get_ip_data_lst_head(self); + c_list_for_each_entry (ip_data, head, ip_data_lst) + ; //XXX nm_ip_config_hash(ip_data->l3cd, sum, TRUE); } nm_utils_checksum_get_digest_len(sum, buffer, HASH_LEN); @@ -1169,19 +1161,18 @@ merge_global_dns_config(NMResolvConfData *rc, NMGlobalDnsConfig *global_conf) } static const char * -get_nameserver_list(const NMIPConfig *config, NMStrBuf *tmp_strbuf) +get_nameserver_list(int addr_family, const NML3ConfigData *l3cd, NMStrBuf *tmp_strbuf) { - char buf[NM_UTILS_INET_ADDRSTRLEN]; - int addr_family; - guint num; - guint i; + char buf[NM_UTILS_INET_ADDRSTRLEN]; + const char *const *strv; + guint num; + guint i; nm_str_buf_reset(tmp_strbuf); - addr_family = nm_ip_config_get_addr_family(config); - num = nm_ip_config_get_num_nameservers(config); + strv = nm_l3_config_data_get_nameservers(l3cd, addr_family, &num); for (i = 0; i < num; i++) { - nm_utils_inet_ntop(addr_family, nm_ip_config_get_nameserver(config, i), buf); + nm_utils_inet_ntop(addr_family, strv[i], buf); if (i > 0) nm_str_buf_append_c(tmp_strbuf, ' '); nm_str_buf_append(tmp_strbuf, buf); @@ -1224,36 +1215,39 @@ _collect_resolv_conf_data(NMDnsManager * self, merge_global_dns_config(&rc, global_config); else { 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) { + head = _mgr_get_ip_data_lst_head(self); + c_list_for_each_entry (ip_data, head, ip_data_lst) { gboolean skip = FALSE; + int dns_priority; _ASSERT_dns_config_ip_data(ip_data); - prio = nm_ip_config_get_dns_priority(ip_data->ip_config); + if (!nm_l3_config_data_get_dns_priority(ip_data->l3cd, + ip_data->addr_family, + &dns_priority)) + nm_assert_not_reached(); if (is_first) { is_first = FALSE; - first_prio = prio; - } else if (first_prio < 0 && first_prio != prio) + first_prio = dns_priority; + } else if (first_prio < 0 && first_prio != dns_priority) skip = TRUE; _LOGT("config: %8d %-7s v%c %-5d %s: %s", - prio, + dns_priority, _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)), + nm_utils_addr_family_to_char(ip_data->addr_family), ip_data->data->ifindex, skip ? "" : "", - get_nameserver_list(ip_data->ip_config, &tmp_strbuf)); + get_nameserver_list(ip_data->addr_family, ip_data->l3cd, &tmp_strbuf)); if (!skip) - merge_one_ip_config(&rc, ip_data->data->ifindex, ip_data->ip_config); + merge_one_l3cd(&rc, ip_data->addr_family, ip_data->data->ifindex, ip_data->l3cd); } } @@ -1289,27 +1283,32 @@ _collect_resolv_conf_data(NMDnsManager * self, /*****************************************************************************/ static char ** -get_ip_rdns_domains(NMIPConfig *ip_config) +get_ip_rdns_domains(int addr_family, const NML3ConfigData *l3cd) { - int addr_family = nm_ip_config_get_addr_family(ip_config); - char ** strv; - GPtrArray * domains; - NMDedupMultiIter ipconf_iter; - const NMPlatformIPAddress *address; - const NMPlatformIPRoute * route; - - nm_assert_addr_family(addr_family); + const int IS_IPv4 = NM_IS_IPv4(addr_family); + char ** strv; + GPtrArray * domains; + NMDedupMultiIter ipconf_iter; + const NMPObject *obj; domains = g_ptr_array_sized_new(5); - nm_ip_config_iter_ip_address_for_each (&ipconf_iter, ip_config, &address) { + nm_l3_config_data_iter_obj_for_each (&ipconf_iter, + l3cd, + &obj, + NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4)) { nm_utils_get_reverse_dns_domains_ip(addr_family, - address->address_ptr, - address->plen, + NMP_OBJECT_CAST_IP_ADDRESS(obj)->address_ptr, + NMP_OBJECT_CAST_IP_ADDRESS(obj)->plen, domains); } - nm_ip_config_iter_ip_route_for_each (&ipconf_iter, ip_config, &route) { + nm_l3_config_data_iter_obj_for_each (&ipconf_iter, + l3cd, + &obj, + NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4)) { + const NMPlatformIPRoute *route = NMP_OBJECT_CAST_IP_ROUTE(obj); + if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT(route)) { nm_utils_get_reverse_dns_domains_ip(addr_family, route->network_ptr, @@ -1391,12 +1390,12 @@ _mgr_configs_data_construct(NMDnsManager *self) CList * head; int prev_priority = G_MININT; - head = _mgr_get_ip_config_lst_head(self); + head = _mgr_get_ip_data_lst_head(self); #if NM_MORE_ASSERTS /* we call _mgr_configs_data_clear() at the end of update. We * don't expect any domain settings here. */ - c_list_for_each_entry (ip_data, head, ip_config_lst) { + c_list_for_each_entry (ip_data, head, ip_data_lst) { nm_assert(!ip_data->domains.search); nm_assert(!ip_data->domains.reverse); nm_assert(!ip_data->domains.has_default_route_explicit); @@ -1405,26 +1404,28 @@ _mgr_configs_data_construct(NMDnsManager *self) } #endif - c_list_for_each_entry (ip_data, head, ip_config_lst) { - NMIPConfig *ip_config = ip_data->ip_config; - gboolean add_wildcard = FALSE; + c_list_for_each_entry (ip_data, head, ip_data_lst) { + gboolean add_wildcard = FALSE; + guint num; - if (!nm_ip_config_get_num_nameservers(ip_config)) + nm_l3_config_data_get_nameservers(ip_data->l3cd, ip_data->addr_family, &num); + if (num == 0) continue; - if (nm_ip_config_best_default_route_get(ip_config)) + if (nm_l3_config_data_get_best_default_route(ip_data->l3cd, ip_data->addr_family)) { + /* FIXME(l3cfg): the best-default route of a l3cd is not significant! */ add_wildcard = TRUE; - else { + } else { /* If a VPN has never-default=no but doesn't get a default * route (this can happen for example when the server * pushes routes with openconnect), and there are no * search or routing domains, then the name servers pushed * by the server would be unused. It is preferable in this * case to use the VPN DNS server for all queries. */ - if (ip_data->ip_config_type == NM_DNS_IP_CONFIG_TYPE_VPN - && !nm_ip_config_get_never_default(ip_data->ip_config) - && nm_ip_config_get_num_searches(ip_data->ip_config) == 0 - && nm_ip_config_get_num_domains(ip_data->ip_config) == 0) - add_wildcard = TRUE; + //XXX if (ip_data->ip_config_type == NM_DNS_IP_CONFIG_TYPE_VPN + //XXX && !nm_ip_config_get_never_default(ip_data->ip_data->l3cd) + //XXX && nm_ip_config_get_num_searches(ip_data->ip_data->l3cd) == 0 + //XXX && nm_ip_config_get_num_domains(ip_data->ip_data->l3cd) == 0) + //XXX add_wildcard = TRUE; } if (add_wildcard) { @@ -1434,29 +1435,33 @@ _mgr_configs_data_construct(NMDnsManager *self) } } - c_list_for_each_entry (ip_data, head, ip_config_lst) { - NMIPConfig * ip_config = ip_data->ip_config; - int priority; - const char **domains; - guint n_searches; - guint n_domains; - guint num_dom1; - guint num_dom2; - guint n_domains_allocated; - guint i; - gboolean has_default_route_maybe = FALSE; - gboolean has_default_route_explicit = FALSE; - gboolean has_default_route_auto = FALSE; - - if (!nm_ip_config_get_num_nameservers(ip_config)) + c_list_for_each_entry (ip_data, head, ip_data_lst) { + int priority; + const char ** domains; + const char *const *strv_searches; + const char *const *strv_domains; + guint n_searches; + guint n_domains; + guint num_dom1; + guint num_dom2; + guint n_domains_allocated; + guint i; + gboolean has_default_route_maybe = FALSE; + gboolean has_default_route_explicit = FALSE; + gboolean has_default_route_auto = FALSE; + guint num; + + nm_l3_config_data_get_nameservers(ip_data->l3cd, ip_data->addr_family, &num); + if (num == 0) continue; - n_searches = nm_ip_config_get_num_searches(ip_config); - n_domains = nm_ip_config_get_num_domains(ip_config); + strv_searches = + nm_l3_config_data_get_searches(ip_data->l3cd, ip_data->addr_family, &n_searches); + strv_domains = + nm_l3_config_data_get_domains(ip_data->l3cd, ip_data->addr_family, &n_domains); - priority = nm_ip_config_get_dns_priority(ip_config); + priority = _dns_config_ip_data_get_dns_priority(ip_data); - nm_assert(priority != 0); nm_assert(prev_priority <= priority); prev_priority = priority; @@ -1484,10 +1489,10 @@ _mgr_configs_data_construct(NMDnsManager *self) /* searches are preferred over domains */ if (n_searches > 0) { for (i = 0; i < n_searches; i++) - domains[num_dom1++] = nm_ip_config_get_search(ip_config, i); + domains[num_dom1++] = strv_searches[i]; } else { for (i = 0; i < n_domains; i++) - domains[num_dom1++] = nm_ip_config_get_domain(ip_config, i); + domains[num_dom1++] = strv_domains[i]; } nm_assert(num_dom1 < n_domains_allocated); @@ -1575,8 +1580,8 @@ _mgr_configs_data_construct(NMDnsManager *self) nm_assert(!ip_data->domains.search); nm_assert(!ip_data->domains.reverse); - ip_data->domains.search = domains; - ip_data->domains.reverse = get_ip_rdns_domains(ip_config); + ip_data->domains.search = domains; + ip_data->domains.reverse = get_ip_rdns_domains(ip_data->addr_family, ip_data->l3cd); ip_data->domains.has_default_route_explicit = has_default_route_explicit; ip_data->domains.has_default_route_exclusive = has_default_route_explicit || (priority < 0 && has_default_route_auto); @@ -1608,8 +1613,8 @@ _mgr_configs_data_clear(NMDnsManager *self) NMDnsConfigIPData *ip_data; CList * head; - head = _mgr_get_ip_config_lst_head(self); - c_list_for_each_entry (ip_data, head, ip_config_lst) { + head = _mgr_get_ip_data_lst_head(self); + c_list_for_each_entry (ip_data, head, ip_data_lst) { nm_clear_g_free(&ip_data->domains.search); nm_clear_pointer(&ip_data->domains.reverse, g_strfreev); ip_data->domains.has_default_route_explicit = FALSE; @@ -1677,7 +1682,7 @@ update_dns(NMDnsManager *self, gboolean no_caching, gboolean force_emit, GError if (priv->sd_resolve_plugin) { nm_dns_plugin_update(priv->sd_resolve_plugin, global_config, - _mgr_get_ip_config_lst_head(self), + _mgr_get_ip_data_lst_head(self), priv->hostname, NULL); } @@ -1699,7 +1704,7 @@ update_dns(NMDnsManager *self, gboolean no_caching, gboolean force_emit, GError _LOGD("update-dns: updating plugin %s", plugin_name); if (!nm_dns_plugin_update(plugin, global_config, - _mgr_get_ip_config_lst_head(self), + _mgr_get_ip_data_lst_head(self), priv->hostname, &plugin_error)) { _LOGW("update-dns: plugin %s update failed: %s", plugin_name, plugin_error->message); @@ -1831,53 +1836,99 @@ plugin_skip:; /*****************************************************************************/ -static void -_ip_config_dns_priority_changed(gpointer config, GParamSpec *pspec, NMDnsConfigIPData *ip_data) -{ - _ASSERT_dns_config_ip_data(ip_data); - - NM_DNS_MANAGER_GET_PRIVATE(ip_data->data->self)->ip_config_lst_need_sort = TRUE; -} - gboolean -nm_dns_manager_set_ip_config(NMDnsManager * self, - NMIPConfig * ip_config, - NMDnsIPConfigType ip_config_type) +nm_dns_manager_set_ip_config(NMDnsManager * self, + int addr_family, + gconstpointer source_tag, + const NML3ConfigData *l3cd, + NMDnsIPConfigType ip_config_type, + gboolean replace_all) { NMDnsManagerPrivate *priv; - NMDnsConfigIPData * ip_data; NMDnsConfigData * data; int ifindex; + gboolean changed = FALSE; + NMDnsConfigIPData * ip_data = NULL; + int dns_priority; g_return_val_if_fail(NM_IS_DNS_MANAGER(self), FALSE); - g_return_val_if_fail(NM_IS_IP_CONFIG(ip_config), FALSE); + g_return_val_if_fail(NM_IS_L3_CONFIG_DATA(l3cd), FALSE); + g_return_val_if_fail(source_tag, FALSE); + + ifindex = nm_l3_config_data_get_ifindex(l3cd); + nm_assert(ifindex > 0); - ifindex = nm_ip_config_get_ifindex(ip_config); - g_return_val_if_fail(ifindex > 0, FALSE); + if (addr_family == AF_UNSPEC) { + /* Setting AF_UNSPEC is a shortcut for calling this function twice for AF_INET and + * AF_INET6. */ + if (nm_dns_manager_set_ip_config(self, + AF_INET, + source_tag, + l3cd, + ip_config_type, + replace_all)) + changed = TRUE; + if (nm_dns_manager_set_ip_config(self, + AF_INET6, + source_tag, + l3cd, + ip_config_type, + replace_all)) + changed = TRUE; + return changed; + } + + nm_assert_addr_family(addr_family); priv = NM_DNS_MANAGER_GET_PRIVATE(self); data = g_hash_table_lookup(priv->configs_dict, &ifindex); - if (!data) - ip_data = NULL; - else - ip_data = _dns_config_data_find_ip_config(data, ip_config); - if (ip_config_type == NM_DNS_IP_CONFIG_TYPE_REMOVED) { - if (!ip_data) - return FALSE; - /* 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)) - g_hash_table_remove(priv->configs_dict, &ifindex); - goto changed; + if (data) { + NMDnsConfigIPData *ip_data_iter; + NMDnsConfigIPData *ip_data_safe; + + c_list_for_each_entry_safe (ip_data_iter, ip_data_safe, &data->data_lst_head, data_lst) { + _ASSERT_dns_config_ip_data(ip_data_iter); + + if (ip_data_iter->source_tag != source_tag) + continue; + if (ip_data_iter->addr_family != addr_family) + continue; + + if (ip_config_type != NM_DNS_IP_CONFIG_TYPE_REMOVED && ip_data_iter->l3cd == l3cd) { + nm_assert(!ip_data); + ip_data = ip_data_iter; + continue; + } + + if (!replace_all && l3cd && ip_data_iter->l3cd != l3cd) + continue; + + changed = TRUE; + _dns_config_ip_data_free(ip_data_iter); + } } + if (ip_config_type == NM_DNS_IP_CONFIG_TYPE_REMOVED) + goto done; + + if (!l3cd) + goto done; + if (ip_data && ip_data->ip_config_type == ip_config_type) { /* nothing to do. */ - return FALSE; + goto done; + } + + dns_priority = _dns_config_ip_data_get_dns_priority1(l3cd, addr_family); + if (dns_priority == 0) { + /* no DNS priority for this address family. Skip it! */ + goto done; } + changed = TRUE; + if (!data) { data = g_slice_new(NMDnsConfigData); *data = (NMDnsConfigData){ @@ -1892,13 +1943,26 @@ nm_dns_manager_set_ip_config(NMDnsManager * self, } if (!ip_data) - ip_data = _dns_config_ip_data_new(data, ip_config, ip_config_type); + ip_data = _dns_config_ip_data_new(data, addr_family, source_tag, l3cd, ip_config_type); else ip_data->ip_config_type = ip_config_type; - priv->ip_config_lst_need_sort = TRUE; + priv->ip_data_lst_need_sort = TRUE; + + nm_assert(l3cd); + nm_assert(ip_config_type != NM_DNS_IP_CONFIG_TYPE_REMOVED); + nm_assert(ip_data->addr_family == addr_family); + nm_assert(ip_data->source_tag == source_tag); + nm_assert(ip_data->l3cd == l3cd); + nm_assert(ip_data->ip_config_type == ip_config_type); + +done: + if (!changed) + return FALSE; + + if (data && c_list_is_empty(&data->data_lst_head)) + g_hash_table_remove(priv->configs_dict, &ifindex); -changed: if (!priv->updates_queue) { gs_free_error GError *error = NULL; @@ -2418,51 +2482,54 @@ _get_config_variant(NMDnsManager *self) g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}")); - 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; - GVariantBuilder strv_builder; - guint i, num; - const int addr_family = nm_ip_config_get_addr_family(ip_config); - char buf[NM_UTILS_INET_ADDRSTRLEN]; - const NMIPAddr * addr; - const char * ifname; - - num = nm_ip_config_get_num_nameservers(ip_config); - if (!num) + head = _mgr_get_ip_data_lst_head(self); + c_list_for_each_entry (ip_data, head, ip_data_lst) { + GVariantBuilder entry_builder; + GVariantBuilder strv_builder; + guint num; + guint num_domains; + guint num_searches; + guint i; + char buf[NM_UTILS_INET_ADDRSTRLEN]; + const char * ifname; + gconstpointer nameservers; + + nameservers = nm_l3_config_data_get_nameservers(ip_data->l3cd, ip_data->addr_family, &num); + if (num == 0) continue; g_variant_builder_init(&entry_builder, G_VARIANT_TYPE("a{sv}")); g_variant_builder_init(&strv_builder, G_VARIANT_TYPE("as")); for (i = 0; i < num; i++) { - addr = nm_ip_config_get_nameserver(ip_config, i); - g_variant_builder_add(&strv_builder, "s", nm_utils_inet_ntop(addr_family, addr, buf)); + const NMIPAddr *addr; + + addr = nm_ip_addr_from_packed_array(ip_data->addr_family, nameservers, i); + g_variant_builder_add(&strv_builder, + "s", + nm_utils_inet_ntop(ip_data->addr_family, addr, buf)); } g_variant_builder_add(&entry_builder, "{sv}", "nameservers", g_variant_builder_end(&strv_builder)); - num = nm_ip_config_get_num_domains(ip_config); - num += nm_ip_config_get_num_searches(ip_config); + nm_l3_config_data_get_domains(ip_data->l3cd, ip_data->addr_family, &num_domains); + nm_l3_config_data_get_searches(ip_data->l3cd, ip_data->addr_family, &num_searches); + num = num_domains + num_searches; if (num > 0) { if (!array_domains) array_domains = g_ptr_array_sized_new(num); else g_ptr_array_set_size(array_domains, 0); - add_dns_domains(array_domains, ip_config, TRUE, FALSE); + add_dns_domains(array_domains, ip_data->addr_family, ip_data->l3cd, TRUE, FALSE); if (array_domains->len) { - g_variant_builder_init(&strv_builder, G_VARIANT_TYPE("as")); - for (i = 0; i < array_domains->len; i++) { - g_variant_builder_add(&strv_builder, "s", array_domains->pdata[i]); - } g_variant_builder_add(&entry_builder, "{sv}", "domains", - g_variant_builder_end(&strv_builder)); + g_variant_new_strv((const char *const *) array_domains->pdata, + array_domains->len)); } } @@ -2477,7 +2544,7 @@ _get_config_variant(NMDnsManager *self) g_variant_builder_add(&entry_builder, "{sv}", "priority", - g_variant_new_int32(nm_ip_config_get_dns_priority(ip_config))); + g_variant_new_int32(_dns_config_ip_data_get_dns_priority(ip_data))); g_variant_builder_add( &entry_builder, @@ -2524,7 +2591,7 @@ nm_dns_manager_init(NMDnsManager *self) _LOGT("creating..."); c_list_init(&priv->configs_lst_head); - c_list_init(&priv->ip_config_lst_head); + c_list_init(&priv->ip_data_lst_head); priv->config = g_object_ref(nm_config_get()); @@ -2562,7 +2629,7 @@ dispose(GObject *object) g_clear_object(&priv->sd_resolve_plugin); _clear_plugin(self); - c_list_for_each_entry_safe (ip_data, ip_data_safe, &priv->ip_config_lst_head, ip_config_lst) + c_list_for_each_entry_safe (ip_data, ip_data_safe, &priv->ip_data_lst_head, ip_data_lst) _dns_config_ip_data_free(ip_data); nm_clear_pointer(&priv->configs_dict, g_hash_table_destroy); diff --git a/src/core/dns/nm-dns-manager.h b/src/core/dns/nm-dns-manager.h index 937ba62a05..22f5963534 100644 --- a/src/core/dns/nm-dns-manager.h +++ b/src/core/dns/nm-dns-manager.h @@ -8,8 +8,7 @@ #ifndef __NETWORKMANAGER_DNS_MANAGER_H__ #define __NETWORKMANAGER_DNS_MANAGER_H__ -#include "nm-ip4-config.h" -#include "nm-ip6-config.h" +#include "c-list/src/c-list.h" #include "nm-setting-connection.h" typedef enum { @@ -32,10 +31,12 @@ struct _NMDnsManager; typedef struct { struct _NMDnsConfigData *data; - NMIPConfig * ip_config; + gconstpointer source_tag; + const NML3ConfigData * l3cd; CList data_lst; - CList ip_config_lst; + CList ip_data_lst; NMDnsIPConfigType ip_config_type; + int addr_family; struct { const char **search; char ** reverse; @@ -101,9 +102,12 @@ NMDnsManager *nm_dns_manager_get(void); void nm_dns_manager_begin_updates(NMDnsManager *self, const char *func); void nm_dns_manager_end_updates(NMDnsManager *self, const char *func); -gboolean nm_dns_manager_set_ip_config(NMDnsManager * self, - NMIPConfig * ip_config, - NMDnsIPConfigType ip_config_type); +gboolean nm_dns_manager_set_ip_config(NMDnsManager * self, + int addr_family, + gconstpointer source_tag, + const NML3ConfigData *l3cd, + NMDnsIPConfigType ip_config_type, + gboolean replace_all); void nm_dns_manager_set_initial_hostname(NMDnsManager *self, const char *hostname); void nm_dns_manager_set_hostname(NMDnsManager *self, const char *hostname, gboolean skip_update); diff --git a/src/core/dns/nm-dns-systemd-resolved.c b/src/core/dns/nm-dns-systemd-resolved.c index 972ef643a3..0207c984a1 100644 --- a/src/core/dns/nm-dns-systemd-resolved.c +++ b/src/core/dns/nm-dns-systemd-resolved.c @@ -21,10 +21,9 @@ #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" #include "nm-dbus-manager.h" #include "nm-manager.h" +#include "nm-l3-config-data.h" #include "nm-setting-connection.h" #include "devices/nm-device.h" #include "NetworkManagerUtils.h" @@ -230,40 +229,42 @@ static gboolean update_add_ip_config(NMDnsSystemdResolved *self, GVariantBuilder * dns, GVariantBuilder * domains, - NMDnsConfigIPData * data) + NMDnsConfigIPData * ip_data) { - int addr_family; - gsize addr_size; - guint i, n; - gboolean is_routing; - const char *domain; - gboolean has_config = FALSE; - - addr_family = nm_ip_config_get_addr_family(data->ip_config); - addr_size = nm_utils_addr_family_to_size(addr_family); - - if ((!data->domains.search || !data->domains.search[0]) - && !data->domains.has_default_route_exclusive && !data->domains.has_default_route) + gsize addr_size; + guint n; + guint i; + gboolean is_routing; + const char * domain; + gboolean has_config = FALSE; + gconstpointer nameservers; + + addr_size = nm_utils_addr_family_to_size(ip_data->addr_family); + + if ((!ip_data->domains.search || !ip_data->domains.search[0]) + && !ip_data->domains.has_default_route_exclusive && !ip_data->domains.has_default_route) return FALSE; - n = nm_ip_config_get_num_nameservers(data->ip_config); + nameservers = nm_l3_config_data_get_nameservers(ip_data->l3cd, ip_data->addr_family, &n); for (i = 0; i < n; i++) { g_variant_builder_open(dns, G_VARIANT_TYPE("(iay)")); - g_variant_builder_add(dns, "i", addr_family); + g_variant_builder_add(dns, "i", ip_data->addr_family); g_variant_builder_add_value( dns, - nm_g_variant_new_ay(nm_ip_config_get_nameserver(data->ip_config, i), addr_size)); + nm_g_variant_new_ay(nm_ip_addr_from_packed_array(ip_data->addr_family, nameservers, i), + addr_size)); g_variant_builder_close(dns); has_config = TRUE; } - if (!data->domains.has_default_route_explicit && data->domains.has_default_route_exclusive) { + if (!ip_data->domains.has_default_route_explicit + && ip_data->domains.has_default_route_exclusive) { g_variant_builder_add(domains, "(sb)", ".", TRUE); has_config = TRUE; } - if (data->domains.search) { - for (i = 0; data->domains.search[i]; i++) { - domain = nm_utils_parse_dns_domain(data->domains.search[i], &is_routing); + if (ip_data->domains.search) { + for (i = 0; ip_data->domains.search[i]; i++) { + domain = nm_utils_parse_dns_domain(ip_data->domains.search[i], &is_routing); g_variant_builder_add(domains, "(sb)", domain[0] ? domain : ".", is_routing); has_config = TRUE; } @@ -304,17 +305,16 @@ prepare_one_interface(NMDnsSystemdResolved *self, InterfaceConfig *ic) g_variant_builder_open(&domains, G_VARIANT_TYPE("a(sb)")); c_list_for_each_entry (elem, &ic->configs_lst_head, lst) { - NMDnsConfigIPData *data = elem->data; - NMIPConfig * ip_config = data->ip_config; + NMDnsConfigIPData *ip_data = elem->data; - has_config |= update_add_ip_config(self, &dns, &domains, data); + has_config |= update_add_ip_config(self, &dns, &domains, ip_data); - if (data->domains.has_default_route) + if (ip_data->domains.has_default_route) has_default_route = TRUE; - if (NM_IS_IP4_CONFIG(ip_config)) { - mdns = NM_MAX(mdns, nm_ip4_config_mdns_get(NM_IP4_CONFIG(ip_config))); - llmnr = NM_MAX(llmnr, nm_ip4_config_llmnr_get(NM_IP4_CONFIG(ip_config))); + if (NM_IS_IPv4(ip_data->addr_family)) { + mdns = NM_MAX(mdns, nm_l3_config_data_get_mdns(ip_data->l3cd)); + llmnr = NM_MAX(llmnr, nm_l3_config_data_get_llmnr(ip_data->l3cd)); } } @@ -513,7 +513,7 @@ start_resolve: static gboolean update(NMDnsPlugin * plugin, const NMGlobalDnsConfig *global_config, - const CList * ip_config_lst_head, + const CList * ip_data_lst_head, const char * hostname, GError ** error) { @@ -531,11 +531,11 @@ update(NMDnsPlugin * plugin, interfaces = g_hash_table_new_full(nm_direct_hash, NULL, NULL, (GDestroyNotify) _interface_config_free); - c_list_for_each_entry (ip_data, ip_config_lst_head, ip_config_lst) { + c_list_for_each_entry (ip_data, ip_data_lst_head, ip_data_lst) { InterfaceConfig *ic = NULL; ifindex = ip_data->data->ifindex; - nm_assert(ifindex == nm_ip_config_get_ifindex(ip_data->ip_config)); + nm_assert(ifindex == nm_l3_config_data_get_ifindex(ip_data->l3cd)); ic = g_hash_table_lookup(interfaces, GINT_TO_POINTER(ifindex)); if (!ic) { diff --git a/src/core/dnsmasq/nm-dnsmasq-manager.c b/src/core/dnsmasq/nm-dnsmasq-manager.c index e8697e817e..f4eea33a13 100644 --- a/src/core/dnsmasq/nm-dnsmasq-manager.c +++ b/src/core/dnsmasq/nm-dnsmasq-manager.c @@ -17,6 +17,7 @@ #include "nm-dnsmasq-utils.h" #include "nm-utils.h" #include "NetworkManagerUtils.h" +#include "nm-l3-config-data.h" #include "libnm-core-intern/nm-core-internal.h" #define CONFDIR NMCONFDIR "/dnsmasq-shared.d" @@ -85,24 +86,28 @@ dm_watch_cb(GPid pid, int status, gpointer user_data) } static GPtrArray * -create_dm_cmd_line(const char * iface, - const NMIP4Config *ip4_config, - const char * pidfile, - gboolean announce_android_metered, - GError ** error) +create_dm_cmd_line(const char * iface, + const NML3ConfigData *l3cd, + const char * pidfile, + gboolean announce_android_metered, + GError ** error) { gs_unref_ptrarray GPtrArray *cmd = NULL; nm_auto_free_gstring GString *s = NULL; char first[INET_ADDRSTRLEN]; char last[INET_ADDRSTRLEN]; char listen_address_s[INET_ADDRSTRLEN]; - char tmpaddr[INET_ADDRSTRLEN]; + char sbuf_addr[INET_ADDRSTRLEN]; gs_free char * error_desc = NULL; const char * dm_binary; const NMPlatformIP4Address * listen_address; - guint i, n; + const in_addr_t * ipv4arr; + const char *const * strarr; + guint n; + guint i; - listen_address = nm_ip4_config_get_first_address(ip4_config); + listen_address = NMP_OBJECT_CAST_IP4_ADDRESS( + nm_l3_config_data_get_first_obj(l3cd, NMP_OBJECT_TYPE_IP4_ADDRESS, NULL)); g_return_val_if_fail(listen_address, NULL); @@ -151,28 +156,28 @@ create_dm_cmd_line(const char * iface, nm_strv_ptrarray_add_string_printf(cmd, "--dhcp-range=%s,%s,60m", first, last); - if (nm_ip4_config_best_default_route_get(ip4_config)) { + if (nm_l3_config_data_get_best_default_route(l3cd, AF_INET)) { nm_strv_ptrarray_add_string_concat(cmd, "--dhcp-option=option:router,", listen_address_s); } - if ((n = nm_ip4_config_get_num_nameservers(ip4_config))) { + ipv4arr = nm_l3_config_data_get_nameservers(l3cd, AF_INET, &n); + if (n > 0) { nm_gstring_prepare(&s); g_string_append(s, "--dhcp-option=option:dns-server"); for (i = 0; i < n; i++) { g_string_append_c(s, ','); - g_string_append( - s, - _nm_utils_inet4_ntop(nm_ip4_config_get_nameserver(ip4_config, i), tmpaddr)); + g_string_append(s, _nm_utils_inet4_ntop(ipv4arr[i], sbuf_addr)); } nm_strv_ptrarray_take_gstring(cmd, &s); } - if ((n = nm_ip4_config_get_num_searches(ip4_config))) { + strarr = nm_l3_config_data_get_searches(l3cd, AF_INET, &n); + if (n > 0) { nm_gstring_prepare(&s); g_string_append(s, "--dhcp-option=option:domain-search"); for (i = 0; i < n; i++) { g_string_append_c(s, ','); - g_string_append(s, nm_ip4_config_get_search(ip4_config, i)); + g_string_append(s, strarr[i]); } nm_strv_ptrarray_take_gstring(cmd, &s); } @@ -237,25 +242,25 @@ out: } gboolean -nm_dnsmasq_manager_start(NMDnsMasqManager *manager, - NMIP4Config * ip4_config, - gboolean announce_android_metered, - GError ** error) +nm_dnsmasq_manager_start(NMDnsMasqManager * manager, + const NML3ConfigData *l3cd, + gboolean announce_android_metered, + GError ** error) { - NMDnsMasqManagerPrivate *priv; gs_unref_ptrarray GPtrArray *dm_cmd = NULL; gs_free char * cmd_str = NULL; + NMDnsMasqManagerPrivate * priv; g_return_val_if_fail(NM_IS_DNSMASQ_MANAGER(manager), FALSE); g_return_val_if_fail(!error || !*error, FALSE); - g_return_val_if_fail(nm_ip4_config_get_num_addresses(ip4_config) > 0, FALSE); + g_return_val_if_fail(NM_IS_L3_CONFIG_DATA(l3cd), FALSE); + g_return_val_if_fail(nm_l3_config_data_get_num_addresses(l3cd, AF_INET) > 0, FALSE); priv = NM_DNSMASQ_MANAGER_GET_PRIVATE(manager); kill_existing_by_pidfile(priv->pidfile); - dm_cmd = - create_dm_cmd_line(priv->iface, ip4_config, priv->pidfile, announce_android_metered, error); + dm_cmd = create_dm_cmd_line(priv->iface, l3cd, priv->pidfile, announce_android_metered, error); if (!dm_cmd) return FALSE; diff --git a/src/core/dnsmasq/nm-dnsmasq-manager.h b/src/core/dnsmasq/nm-dnsmasq-manager.h index 272d1cead1..78ca37251e 100644 --- a/src/core/dnsmasq/nm-dnsmasq-manager.h +++ b/src/core/dnsmasq/nm-dnsmasq-manager.h @@ -6,8 +6,6 @@ #ifndef __NETWORKMANAGER_DNSMASQ_MANAGER_H__ #define __NETWORKMANAGER_DNSMASQ_MANAGER_H__ -#include "nm-ip4-config.h" - #define NM_TYPE_DNSMASQ_MANAGER (nm_dnsmasq_manager_get_type()) #define NM_DNSMASQ_MANAGER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DNSMASQ_MANAGER, NMDnsMasqManager)) @@ -35,10 +33,10 @@ GType nm_dnsmasq_manager_get_type(void); NMDnsMasqManager *nm_dnsmasq_manager_new(const char *iface); -gboolean nm_dnsmasq_manager_start(NMDnsMasqManager *manager, - NMIP4Config * ip4_config, - gboolean announce_android_metered, - GError ** error); +gboolean nm_dnsmasq_manager_start(NMDnsMasqManager * manager, + const NML3ConfigData *l3cd, + gboolean announce_android_metered, + GError ** error); void nm_dnsmasq_manager_stop(NMDnsMasqManager *manager); diff --git a/src/core/meson.build b/src/core/meson.build index f4d7af6407..2ab8b664fd 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -53,8 +53,6 @@ libNetworkManagerBase = static_library( 'nm-l3-ipv4ll.c', 'nm-l3cfg.c', 'nm-ip-config.c', - 'nm-ip4-config.c', - 'nm-ip6-config.c', ), dependencies: [ core_default_dep, @@ -92,7 +90,6 @@ endif libNetworkManager = static_library( 'NetworkManager', sources: files( - 'devices/nm-acd-manager.c', 'devices/nm-device-6lowpan.c', 'devices/nm-device-bond.c', 'devices/nm-device-bridge.c', @@ -168,7 +165,6 @@ libNetworkManager = static_library( 'nm-manager.c', 'nm-pacrunner-manager.c', 'nm-policy.c', - 'nm-proxy-config.c', 'nm-rfkill-manager.c', 'nm-session-monitor.c', 'nm-sleep-monitor.c', diff --git a/src/core/ndisc/nm-ndisc.c b/src/core/ndisc/nm-ndisc.c index cf1b58ecf4..2dce07871e 100644 --- a/src/core/ndisc/nm-ndisc.c +++ b/src/core/ndisc/nm-ndisc.c @@ -16,6 +16,7 @@ #include "nm-utils.h" #include "libnm-platform/nm-platform.h" #include "libnm-platform/nmp-netns.h" +#include "libnm-platform/nm-platform-utils.h" #include "nm-l3-config-data.h" #define _NMLOG_PREFIX_NAME "ndisc" @@ -101,8 +102,6 @@ nm_ndisc_data_to_l3cd(NMDedupMultiIndex * multi_idx, int ifindex, const NMNDiscData * rdata, NMSettingIP6ConfigPrivacy ip6_privacy, - guint32 route_table, - guint32 route_metric, gboolean kernel_support_rta_pref, gboolean kernel_support_extended_ifa_flags) { @@ -166,8 +165,10 @@ nm_ndisc_data_to_l3cd(NMDedupMultiIndex * multi_idx, .plen = ndisc_route->plen, .gateway = ndisc_route->gateway, .rt_source = NM_IP_CONFIG_SOURCE_NDISC, - .table_coerced = nm_platform_route_table_coerce(route_table), - .metric = route_metric, + .table_any = TRUE, + .table_coerced = 0, + .metric_any = TRUE, + .metric = 0, .rt_pref = ndisc_route->preference, }; nm_assert((NMIcmpv6RouterPref) r.rt_pref == ndisc_route->preference); @@ -180,8 +181,10 @@ nm_ndisc_data_to_l3cd(NMDedupMultiIndex * multi_idx, NMPlatformIP6Route r = { .rt_source = NM_IP_CONFIG_SOURCE_NDISC, .ifindex = ifindex, - .table_coerced = nm_platform_route_table_coerce(route_table), - .metric = route_metric, + .table_any = TRUE, + .table_coerced = 0, + .metric_any = TRUE, + .metric = 0, }; for (i = 0; i < rdata->gateways_n; i++) { @@ -983,30 +986,85 @@ announce_router_solicited(NMNDisc *ndisc) /*****************************************************************************/ void -nm_ndisc_set_config(NMNDisc * ndisc, - const GArray *addresses, - const GArray *dns_servers, - const GArray *dns_domains) +nm_ndisc_set_config(NMNDisc *ndisc, const NML3ConfigData *l3cd) { - gboolean changed = FALSE; - guint i; + gboolean changed = FALSE; + const struct in6_addr *in6arr; + const char *const * strvarr; + NMDedupMultiIter iter; + const NMPObject * obj; + gint64 now_msec; + guint len; + guint i; + + nm_assert(NM_IS_NDISC(ndisc)); + nm_assert(nm_ndisc_get_node_type(ndisc) == NM_NDISC_NODE_TYPE_ROUTER); - for (i = 0; i < addresses->len; i++) { - if (nm_ndisc_add_address(ndisc, &g_array_index(addresses, NMNDiscAddress, i), 0, FALSE)) + now_msec = nm_utils_get_monotonic_timestamp_msec(); + + nm_l3_config_data_iter_obj_for_each (&iter, l3cd, &obj, NMP_OBJECT_TYPE_IP6_ADDRESS) { + const NMPlatformIP6Address *addr = NMP_OBJECT_CAST_IP6_ADDRESS(obj); + guint32 preferred; + guint32 lifetime; + NMNDiscAddress a; + + if (IN6_IS_ADDR_UNSPECIFIED(&addr->address) || IN6_IS_ADDR_LINKLOCAL(&addr->address)) + continue; + + if (addr->n_ifa_flags & IFA_F_TENTATIVE || addr->n_ifa_flags & IFA_F_DADFAILED) + continue; + + if (addr->plen != 64) + continue; + + lifetime = nmp_utils_lifetime_get(addr->timestamp, + addr->lifetime, + addr->preferred, + NM_NDISC_EXPIRY_BASE_TIMESTAMP / 1000, + &preferred); + if (!lifetime) + continue; + + a = (NMNDiscAddress){ + .address = addr->address, + .expiry_msec = _nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, lifetime), + .expiry_preferred_msec = + _nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, preferred), + }; + + if (nm_ndisc_add_address(ndisc, &a, now_msec, FALSE)) changed = TRUE; } - for (i = 0; i < dns_servers->len; i++) { - if (nm_ndisc_add_dns_server(ndisc, - &g_array_index(dns_servers, NMNDiscDNSServer, i), - G_MININT64)) + in6arr = NULL; + len = 0; + if (l3cd) + in6arr = nm_l3_config_data_get_nameservers(l3cd, AF_INET6, &len); + for (i = 0; i < len; i++) { + NMNDiscDNSServer n; + + n = (NMNDiscDNSServer){ + .address = in6arr[i], + .expiry_msec = _nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, + NM_NDISC_ROUTER_LIFETIME), + }; + if (nm_ndisc_add_dns_server(ndisc, &n, G_MININT64)) changed = TRUE; } - for (i = 0; i < dns_domains->len; i++) { - if (nm_ndisc_add_dns_domain(ndisc, - &g_array_index(dns_domains, NMNDiscDNSDomain, i), - G_MININT64)) + strvarr = NULL; + len = 0; + if (l3cd) + strvarr = nm_l3_config_data_get_searches(l3cd, AF_INET6, &len); + for (i = 0; i < len; i++) { + NMNDiscDNSDomain n; + + n = (NMNDiscDNSDomain){ + .domain = (char *) strvarr[i], + .expiry_msec = _nm_ndisc_lifetime_to_expiry(NM_NDISC_EXPIRY_BASE_TIMESTAMP, + NM_NDISC_ROUTER_LIFETIME), + }; + if (nm_ndisc_add_dns_domain(ndisc, &n, G_MININT64)) changed = TRUE; } diff --git a/src/core/ndisc/nm-ndisc.h b/src/core/ndisc/nm-ndisc.h index 15f95d206d..bbcfad311c 100644 --- a/src/core/ndisc/nm-ndisc.h +++ b/src/core/ndisc/nm-ndisc.h @@ -226,10 +226,7 @@ void nm_ndisc_start(NMNDisc *ndisc); void nm_ndisc_stop(NMNDisc *ndisc); NMNDiscConfigMap nm_ndisc_dad_failed(NMNDisc *ndisc, const struct in6_addr *address, gboolean emit_changed_signal); -void nm_ndisc_set_config(NMNDisc * ndisc, - const GArray *addresses, - const GArray *dns_servers, - const GArray *dns_domains); +void nm_ndisc_set_config(NMNDisc *ndisc, const NML3ConfigData *l3cd); NMPlatform *nm_ndisc_get_platform(NMNDisc *self); NMPNetns * nm_ndisc_netns_get(NMNDisc *self); @@ -270,8 +267,6 @@ struct _NML3ConfigData *nm_ndisc_data_to_l3cd(NMDedupMultiIndex * multi_id int ifindex, const NMNDiscData * rdata, NMSettingIP6ConfigPrivacy ip6_privacy, - guint32 route_table, - guint32 route_metric, gboolean kernel_support_rta_pref, gboolean kernel_support_extended_ifa_flags); diff --git a/src/core/nm-act-request.c b/src/core/nm-act-request.c index d0a2e0c783..58dd4a87f8 100644 --- a/src/core/nm-act-request.c +++ b/src/core/nm-act-request.c @@ -24,8 +24,7 @@ #include "settings/nm-settings-connection.h" typedef struct { - CList call_ids_lst_head; - NMFirewallConfig *firewall_config; + CList call_ids_lst_head; } NMActRequestPrivate; struct _NMActRequest { @@ -250,36 +249,6 @@ nm_act_request_clear_secrets(NMActRequest *self) /*****************************************************************************/ -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)->firewall_config; -} - -void -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->firewall_config == rules) - return; - - if (priv->firewall_config) { - nm_firewall_config_apply(priv->firewall_config, FALSE); - priv->firewall_config = NULL; - } - if (rules) { - priv->firewall_config = rules; - nm_firewall_config_apply(priv->firewall_config, TRUE); - } -} - -/*****************************************************************************/ - static void device_notify(GObject *object, GParamSpec *pspec, gpointer self) { @@ -508,11 +477,6 @@ 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->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 9c702d31eb..698a9985a4 100644 --- a/src/core/nm-act-request.h +++ b/src/core/nm-act-request.h @@ -38,14 +38,6 @@ NMConnection *nm_act_request_get_applied_connection(NMActRequest *req); /*****************************************************************************/ -struct _NMFirewallConfig; - -struct _NMFirewallConfig *nm_act_request_get_shared(NMActRequest *req); - -void nm_act_request_set_shared(NMActRequest *req, struct _NMFirewallConfig *rules); - -/*****************************************************************************/ - /* Secrets handling */ typedef void (*NMActRequestSecretsFunc)(NMActRequest * req, diff --git a/src/core/nm-connectivity.c b/src/core/nm-connectivity.c index a29be6d2aa..524c9cde0b 100644 --- a/src/core/nm-connectivity.c +++ b/src/core/nm-connectivity.c @@ -16,6 +16,7 @@ #include #include "c-list/src/c-list.h" +#include "libnm-platform/nmp-object.h" #include "libnm-core-intern/nm-core-internal.h" #include "nm-config.h" #include "NetworkManagerUtils.h" diff --git a/src/core/nm-dhcp-config.c b/src/core/nm-dhcp-config.c index 1cbad49e2f..62b79c37a3 100644 --- a/src/core/nm-dhcp-config.c +++ b/src/core/nm-dhcp-config.c @@ -8,9 +8,11 @@ #include "nm-dhcp-config.h" #include "nm-dbus-interface.h" +#include "NetworkManagerUtils.h" #include "nm-utils.h" #include "nm-dbus-object.h" #include "nm-core-utils.h" +#include "nm-l3-config-data.h" /*****************************************************************************/ @@ -49,7 +51,8 @@ static GType nm_dhcp6_config_get_type(void); NM_GOBJECT_PROPERTIES_DEFINE(NMDhcpConfig, PROP_OPTIONS, ); typedef struct { - GVariant *options; + const NML3ConfigData *l3cd; + GVariant * options; } NMDhcpConfigPrivate; struct _NMDhcpConfig { @@ -77,17 +80,41 @@ nm_dhcp_config_get_addr_family(NMDhcpConfig *self) /*****************************************************************************/ void -nm_dhcp_config_set_options(NMDhcpConfig *self, GHashTable *options) +nm_dhcp_config_set_lease(NMDhcpConfig *self, const NML3ConfigData *l3cd) { - NMDhcpConfigPrivate *priv; + nm_auto_unref_l3cd const NML3ConfigData *l3cd2 = NULL; + gs_unref_variant GVariant *options2 = NULL; + NMDhcpConfigPrivate * priv; g_return_if_fail(NM_IS_DHCP_CONFIG(self)); - g_return_if_fail(options); priv = NM_DHCP_CONFIG_GET_PRIVATE(self); - nm_g_variant_unref(priv->options); - priv->options = g_variant_ref_sink(nm_utils_strdict_to_variant_asv(options)); + if (priv->l3cd == l3cd) + return; + + if (l3cd) + nm_l3_config_data_ref_and_seal(l3cd); + NM_SWAP(&priv->l3cd, &l3cd); + + options2 = NULL; + if (priv->l3cd) { + NMDhcpLease *lease; + + lease = nm_l3_config_data_get_dhcp_lease(priv->l3cd, nm_dhcp_config_get_addr_family(self)); + if (lease) + options2 = nm_utils_strdict_to_variant_asv(nm_dhcp_lease_get_options(lease)); + } + if (!options2) + options2 = nm_g_variant_singleton_aLsvI(); + + options2 = g_variant_ref_sink(options2); + + if (g_variant_equal(priv->options, options2)) + return; + + NM_SWAP(&priv->options, &options2); + _notify(self, PROP_OPTIONS); } @@ -95,19 +122,22 @@ const char * nm_dhcp_config_get_option(NMDhcpConfig *self, const char *key) { NMDhcpConfigPrivate *priv; - const char * value; + NMDhcpLease * lease; g_return_val_if_fail(NM_IS_DHCP_CONFIG(self), NULL); g_return_val_if_fail(key, NULL); priv = NM_DHCP_CONFIG_GET_PRIVATE(self); - if (priv->options && g_variant_lookup(priv->options, key, "&s", &value)) - return value; - else + if (!priv->l3cd) return NULL; + + lease = nm_l3_config_data_get_dhcp_lease(priv->l3cd, nm_dhcp_config_get_addr_family(self)); + return nm_dhcp_lease_lookup_option(lease, key); } +/*****************************************************************************/ + GVariant * nm_dhcp_config_get_options(NMDhcpConfig *self) { @@ -125,7 +155,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 ?: nm_g_variant_singleton_aLsvI()); + g_value_set_variant(value, priv->options); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); @@ -137,7 +167,9 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) static void nm_dhcp_config_init(NMDhcpConfig *self) -{} +{ + NM_DHCP_CONFIG_GET_PRIVATE(self)->options = g_variant_ref(nm_g_variant_singleton_aLsvI()); +} NMDhcpConfig * nm_dhcp_config_new(int addr_family) @@ -154,6 +186,8 @@ finalize(GObject *object) nm_g_variant_unref(priv->options); + nm_l3_config_data_unref(priv->l3cd); + G_OBJECT_CLASS(nm_dhcp_config_parent_class)->finalize(object); } diff --git a/src/core/nm-dhcp-config.h b/src/core/nm-dhcp-config.h index 9e68f2fb3a..6fb15ebfa9 100644 --- a/src/core/nm-dhcp-config.h +++ b/src/core/nm-dhcp-config.h @@ -27,7 +27,7 @@ NMDhcpConfig *nm_dhcp_config_new(int addr_family); int nm_dhcp_config_get_addr_family(NMDhcpConfig *self); -void nm_dhcp_config_set_options(NMDhcpConfig *self, GHashTable *options); +void nm_dhcp_config_set_lease(NMDhcpConfig *self, const NML3ConfigData *l3cd); const char *nm_dhcp_config_get_option(NMDhcpConfig *self, const char *option); diff --git a/src/core/nm-dispatcher.c b/src/core/nm-dispatcher.c index 32c9db627c..67786125b7 100644 --- a/src/core/nm-dispatcher.c +++ b/src/core/nm-dispatcher.c @@ -15,9 +15,7 @@ #include "nm-act-request.h" #include "devices/nm-device.h" #include "nm-dhcp-config.h" -#include "nm-proxy-config.h" -#include "nm-ip4-config.h" -#include "nm-ip6-config.h" +#include "nm-l3-config-data.h" #include "nm-manager.h" #include "settings/nm-settings-connection.h" #include "libnm-platform/nm-platform.h" @@ -148,50 +146,47 @@ _init_dispatcher(void) /*****************************************************************************/ static void -dump_proxy_to_props(NMProxyConfig *proxy, GVariantBuilder *builder) +dump_proxy_to_props(const NML3ConfigData *l3cd, GVariantBuilder *builder) { - const char *pac_url = NULL, *pac_script = NULL; + const char *s; - if (nm_proxy_config_get_method(proxy) == NM_PROXY_CONFIG_METHOD_NONE) + if (nm_l3_config_data_get_proxy_method(l3cd) != NM_PROXY_CONFIG_METHOD_AUTO) return; - pac_url = nm_proxy_config_get_pac_url(proxy); - if (pac_url) { - g_variant_builder_add(builder, "{sv}", "pac-url", g_variant_new_string(pac_url)); - } + s = nm_l3_config_data_get_proxy_pac_url(l3cd); + if (s) + g_variant_builder_add(builder, "{sv}", "pac-url", g_variant_new_string(s)); - pac_script = nm_proxy_config_get_pac_script(proxy); - if (pac_script) { - g_variant_builder_add(builder, "{sv}", "pac-script", g_variant_new_string(pac_script)); - } + s = nm_l3_config_data_get_proxy_pac_script(l3cd); + if (s) + g_variant_builder_add(builder, "{sv}", "pac-script", g_variant_new_string(s)); } static void -dump_ip_to_props(NMIPConfig *ip, GVariantBuilder *builder) +dump_ip_to_props(const NML3ConfigData *l3cd, int addr_family, GVariantBuilder *builder) { - const int addr_family = nm_ip_config_get_addr_family(ip); - const int IS_IPv4 = NM_IS_IPv4(addr_family); - const NMPObject *obj; - GVariantBuilder int_builder; - NMDedupMultiIter ipconf_iter; - GVariant * var1; - GVariant * var2; - guint n; - guint i; - const NMPObject *default_route; + const int IS_IPv4 = NM_IS_IPv4(addr_family); + const NMPObject * obj; + GVariantBuilder int_builder; + NMDedupMultiIter ipconf_iter; + GVariant * var1; + GVariant * var2; + guint n; + guint i; + const NMPObject * default_route; + const char *const *strarr; + const in_addr_t * ip4arr; + gconstpointer iparr; if (IS_IPv4) g_variant_builder_init(&int_builder, G_VARIANT_TYPE("aau")); else g_variant_builder_init(&int_builder, G_VARIANT_TYPE("a(ayuay)")); - default_route = nm_ip_config_best_default_route_get(ip); - if (IS_IPv4) - nm_ip_config_iter_ip4_address_init(&ipconf_iter, NM_IP4_CONFIG(ip)); - else - nm_ip_config_iter_ip6_address_init(&ipconf_iter, NM_IP6_CONFIG(ip)); - while (nm_platform_dedup_multi_iter_next_obj(&ipconf_iter, - &obj, - NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4))) { + default_route = nm_l3_config_data_get_best_default_route(l3cd, addr_family); + nm_l3_config_data_iter_obj_for_each (&ipconf_iter, + l3cd, + &obj, + NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4)) { const NMPlatformIPXAddress *addr = NMP_OBJECT_CAST_IPX_ADDRESS(obj); if (IS_IPv4) { @@ -225,30 +220,28 @@ dump_ip_to_props(NMIPConfig *ip, GVariantBuilder *builder) g_variant_builder_init(&int_builder, G_VARIANT_TYPE("au")); else g_variant_builder_init(&int_builder, G_VARIANT_TYPE("aay")); - n = nm_ip_config_get_num_nameservers(ip); + iparr = nm_l3_config_data_get_nameservers(l3cd, addr_family, &n); for (i = 0; i < n; i++) { - if (IS_IPv4) { - g_variant_builder_add(&int_builder, - "u", - nm_ip4_config_get_nameserver(NM_IP4_CONFIG(ip), i)); - } else { - var1 = nm_g_variant_new_ay_in6addr(nm_ip6_config_get_nameserver(NM_IP6_CONFIG(ip), i)); + if (IS_IPv4) + g_variant_builder_add(&int_builder, "u", ((const in_addr_t *) iparr)[i]); + else { + var1 = nm_g_variant_new_ay_in6addr(&(((const struct in6_addr *) iparr)[i])); g_variant_builder_add(&int_builder, "@ay", var1); } } g_variant_builder_add(builder, "{sv}", "nameservers", g_variant_builder_end(&int_builder)); g_variant_builder_init(&int_builder, G_VARIANT_TYPE("as")); - n = nm_ip_config_get_num_domains(ip); + strarr = nm_l3_config_data_get_domains(l3cd, addr_family, &n); for (i = 0; i < n; i++) - g_variant_builder_add(&int_builder, "s", nm_ip_config_get_domain(ip, i)); + g_variant_builder_add(&int_builder, "s", strarr[i]); g_variant_builder_add(builder, "{sv}", "domains", g_variant_builder_end(&int_builder)); if (IS_IPv4) { g_variant_builder_init(&int_builder, G_VARIANT_TYPE("au")); - n = nm_ip4_config_get_num_wins(NM_IP4_CONFIG(ip)); + ip4arr = nm_l3_config_data_get_wins(l3cd, &n); for (i = 0; i < n; i++) - g_variant_builder_add(&int_builder, "u", nm_ip4_config_get_wins(NM_IP4_CONFIG(ip), i)); + g_variant_builder_add(&int_builder, "u", ip4arr[i]); g_variant_builder_add(builder, "{sv}", "wins-servers", g_variant_builder_end(&int_builder)); } @@ -256,13 +249,10 @@ dump_ip_to_props(NMIPConfig *ip, GVariantBuilder *builder) g_variant_builder_init(&int_builder, G_VARIANT_TYPE("aau")); else g_variant_builder_init(&int_builder, G_VARIANT_TYPE("a(ayuayu)")); - if (IS_IPv4) - nm_ip_config_iter_ip4_route_init(&ipconf_iter, NM_IP4_CONFIG(ip)); - else - nm_ip_config_iter_ip6_route_init(&ipconf_iter, NM_IP6_CONFIG(ip)); - while (nm_platform_dedup_multi_iter_next_obj(&ipconf_iter, - &obj, - NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4))) { + nm_l3_config_data_iter_obj_for_each (&ipconf_iter, + l3cd, + &obj, + NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4)) { const NMPlatformIPXRoute *route = NMP_OBJECT_CAST_IPX_ROUTE(obj); if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(route)) @@ -299,10 +289,8 @@ fill_device_props(NMDevice * device, GVariant ** dhcp4_props, GVariant ** dhcp6_props) { - NMProxyConfig *proxy_config; - NMIP4Config * ip4_config; - NMIP6Config * ip6_config; - NMDhcpConfig * dhcp_config; + const NML3ConfigData *l3cd; + NMDhcpConfig * dhcp_config; /* If the action is for a VPN, send the VPN's IP interface instead of the device's */ g_variant_builder_add(dev_builder, @@ -329,17 +317,12 @@ fill_device_props(NMDevice * device, g_variant_new_object_path(nm_dbus_object_get_path(NM_DBUS_OBJECT(device)))); } - proxy_config = nm_device_get_proxy_config(device); - if (proxy_config) - dump_proxy_to_props(proxy_config, proxy_builder); - - ip4_config = nm_device_get_ip4_config(device); - if (ip4_config) - dump_ip_to_props(NM_IP_CONFIG(ip4_config), ip4_builder); - - ip6_config = nm_device_get_ip6_config(device); - if (ip6_config) - dump_ip_to_props(NM_IP_CONFIG(ip6_config), ip6_builder); + l3cd = nm_device_get_l3cd(device, TRUE); + if (l3cd) { + dump_ip_to_props(l3cd, AF_INET, ip4_builder); + dump_ip_to_props(l3cd, AF_INET6, ip6_builder); + dump_proxy_to_props(l3cd, proxy_builder); + } dhcp_config = nm_device_get_dhcp_config(device, AF_INET); if (dhcp_config) @@ -351,19 +334,16 @@ fill_device_props(NMDevice * device, } static void -fill_vpn_props(NMProxyConfig * proxy_config, - NMIP4Config * ip4_config, - NMIP6Config * ip6_config, - GVariantBuilder *proxy_builder, - GVariantBuilder *ip4_builder, - GVariantBuilder *ip6_builder) +fill_vpn_props(const NML3ConfigData *l3cd, + GVariantBuilder * proxy_builder, + GVariantBuilder * ip4_builder, + GVariantBuilder * ip6_builder) { - if (proxy_config) - dump_proxy_to_props(proxy_config, proxy_builder); - if (ip4_config) - dump_ip_to_props(NM_IP_CONFIG(ip4_config), ip4_builder); - if (ip6_config) - dump_ip_to_props(NM_IP_CONFIG(ip6_config), ip6_builder); + if (l3cd) { + dump_ip_to_props(l3cd, AF_INET, ip4_builder); + dump_ip_to_props(l3cd, AF_INET6, ip6_builder); + dump_proxy_to_props(l3cd, proxy_builder); + } } static const char * @@ -479,9 +459,7 @@ _dispatcher_call(NMDispatcherAction action, gboolean activation_type_external, NMConnectivityState connectivity_state, const char * vpn_iface, - NMProxyConfig * vpn_proxy_config, - NMIP4Config * vpn_ip4_config, - NMIP6Config * vpn_ip6_config, + const NML3ConfigData *l3cd, NMDispatcherFunc callback, gpointer user_data, NMDispatcherCallId ** out_call_id) @@ -593,10 +571,8 @@ _dispatcher_call(NMDispatcherAction action, &device_ip6_props, &device_dhcp4_props, &device_dhcp6_props); - if (vpn_ip4_config || vpn_ip6_config) { - fill_vpn_props(vpn_proxy_config, - vpn_ip4_config, - vpn_ip6_config, + if (l3cd) { + fill_vpn_props(l3cd, &vpn_proxy_props, &vpn_ip4_props, &vpn_ip6_props); @@ -693,8 +669,6 @@ nm_dispatcher_call_hostname(NMDispatcherFunc callback, NM_CONNECTIVITY_UNKNOWN, NULL, NULL, - NULL, - NULL, callback, user_data, out_call_id); @@ -744,8 +718,6 @@ nm_dispatcher_call_device(NMDispatcherAction action, NM_CONNECTIVITY_UNKNOWN, NULL, NULL, - NULL, - NULL, callback, user_data, out_call_id); @@ -790,8 +762,6 @@ nm_dispatcher_call_device_sync(NMDispatcherAction action, NULL, NULL, NULL, - NULL, - NULL, NULL); } @@ -802,9 +772,7 @@ nm_dispatcher_call_device_sync(NMDispatcherAction action, * @applied_connection: the currently applied connection * @parent_device: the parent #NMDevice of the VPN connection * @vpn_iface: the IP interface of the VPN tunnel, if any - * @vpn_proxy_config: the #NMProxyConfig of the VPN connection - * @vpn_ip4_config: the #NMIP4Config of the VPN connection - * @vpn_ip6_config: the #NMIP6Config of the VPN connection + * @vpn_l3cd: the #NML3ConfigData of the VPN connection * @callback: a caller-supplied callback to execute when done * @user_data: caller-supplied pointer passed to @callback * @out_call_id: on success, a call identifier which can be passed to @@ -821,9 +789,7 @@ nm_dispatcher_call_vpn(NMDispatcherAction action, NMConnection * applied_connection, NMDevice * parent_device, const char * vpn_iface, - NMProxyConfig * vpn_proxy_config, - NMIP4Config * vpn_ip4_config, - NMIP6Config * vpn_ip6_config, + const NML3ConfigData *l3cd, NMDispatcherFunc callback, gpointer user_data, NMDispatcherCallId ** out_call_id) @@ -836,9 +802,7 @@ nm_dispatcher_call_vpn(NMDispatcherAction action, FALSE, NM_CONNECTIVITY_UNKNOWN, vpn_iface, - vpn_proxy_config, - vpn_ip4_config, - vpn_ip6_config, + l3cd, callback, user_data, out_call_id); @@ -851,9 +815,7 @@ nm_dispatcher_call_vpn(NMDispatcherAction action, * @applied_connection: the currently applied connection * @parent_device: the parent #NMDevice of the VPN connection * @vpn_iface: the IP interface of the VPN tunnel, if any - * @vpn_proxy_config: the #NMProxyConfig of the VPN connection - * @vpn_ip4_config: the #NMIP4Config of the VPN connection - * @vpn_ip6_config: the #NMIP6Config of the VPN connection + * @vpn_l3cd: the #NML3ConfigData of the VPN connection * * This method always invokes the dispatcher action synchronously and it may * take a long time to return. @@ -866,9 +828,7 @@ nm_dispatcher_call_vpn_sync(NMDispatcherAction action, NMConnection * applied_connection, NMDevice * parent_device, const char * vpn_iface, - NMProxyConfig * vpn_proxy_config, - NMIP4Config * vpn_ip4_config, - NMIP6Config * vpn_ip6_config) + const NML3ConfigData *l3cd) { return _dispatcher_call(action, TRUE, @@ -878,9 +838,7 @@ nm_dispatcher_call_vpn_sync(NMDispatcherAction action, FALSE, NM_CONNECTIVITY_UNKNOWN, vpn_iface, - vpn_proxy_config, - vpn_ip4_config, - vpn_ip6_config, + l3cd, NULL, NULL, NULL); @@ -913,8 +871,6 @@ nm_dispatcher_call_connectivity(NMConnectivityState connectivity_state, connectivity_state, NULL, NULL, - NULL, - NULL, callback, user_data, out_call_id); diff --git a/src/core/nm-dispatcher.h b/src/core/nm-dispatcher.h index d588de4e8f..4598a56136 100644 --- a/src/core/nm-dispatcher.h +++ b/src/core/nm-dispatcher.h @@ -48,9 +48,7 @@ gboolean nm_dispatcher_call_vpn(NMDispatcherAction action, NMConnection * applied_connection, NMDevice * parent_device, const char * vpn_iface, - NMProxyConfig * vpn_proxy_config, - NMIP4Config * vpn_ip4_config, - NMIP6Config * vpn_ip6_config, + const NML3ConfigData *l3cd, NMDispatcherFunc callback, gpointer user_data, NMDispatcherCallId ** out_call_id); @@ -60,9 +58,7 @@ gboolean nm_dispatcher_call_vpn_sync(NMDispatcherAction action, NMConnection * applied_connection, NMDevice * parent_device, const char * vpn_iface, - NMProxyConfig * vpn_proxy_config, - NMIP4Config * vpn_ip4_config, - NMIP6Config * vpn_ip6_config); + const NML3ConfigData *l3cd); gboolean nm_dispatcher_call_connectivity(NMConnectivityState state, NMDispatcherFunc callback, diff --git a/src/core/nm-iface-helper.c b/src/core/nm-iface-helper.c index 296bf091ee..2e12165e33 100644 --- a/src/core/nm-iface-helper.c +++ b/src/core/nm-iface-helper.c @@ -90,19 +90,24 @@ static struct { NULL, \ "iface-helper: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__) _NM_UTILS_MACRO_REST(__VA_ARGS__)) +//XXX +#if 0 + /*****************************************************************************/ static void -dhcp4_state_changed(NMDhcpClient *client, - NMDhcpState state, - NMIP4Config * ip4_config, - GHashTable * options, - gpointer user_data) +dhcp4_state_changed(NMDhcpClient * client, + NMDhcpState state, + NML3ConfigData *l3cfg, + gpointer user_data) { static NMIP4Config *last_config = NULL; NMIP4Config * existing; gs_unref_ptrarray GPtrArray *ip4_dev_route_blacklist = NULL; gs_free_error GError *error = NULL; + NMIP4Config * ip4_config = NULL; //XXX + + /* FIXME(l3cfg): fix handling metric_any/table_any for routes. */ g_return_if_fail(!ip4_config || NM_IS_IP4_CONFIG(ip4_config)); @@ -512,10 +517,13 @@ ip6_address_changed(NMPlatform * platform, data, nm_g_slice_free_fcn(DadFailedHandleData)); } +#endif int main(int argc, char *argv[]) { +//XXX +#if 0 char * bad_domains = NULL; gs_free_error GError *error = NULL; gboolean wrote_pidfile = FALSE; @@ -666,8 +674,6 @@ main(int argc, char *argv[]) hwaddr, bcast_hwaddr, global_opt.uuid, - RT_TABLE_MAIN, - global_opt.priority_v4, NM_DHCP_CLIENT_FLAGS_NONE, !!global_opt.dhcp4_hostname, global_opt.dhcp4_hostname, @@ -763,6 +769,7 @@ main(int argc, char *argv[]) nm_clear_g_source(&sd_id); nm_clear_pointer(&gl.main_loop, g_main_loop_unref); +#endif return 0; } @@ -855,5 +862,6 @@ nm_device_get_type(void) GType nm_active_connection_get_type(void) { + (void) gl; //XXX g_return_val_if_reached(0); } diff --git a/src/core/nm-ip-config.c b/src/core/nm-ip-config.c index 2426eb4941..f0a93cc4d2 100644 --- a/src/core/nm-ip-config.c +++ b/src/core/nm-ip-config.c @@ -12,26 +12,29 @@ /*****************************************************************************/ -NM_GOBJECT_PROPERTIES_DEFINE(NMIPConfig, PROP_L3CFG, PROP_IS_VPN, ); +GType nm_ip4_config_get_type(void); +GType nm_ip6_config_get_type(void); -typedef struct _NMIPConfigPrivate { - NML3Cfg *l3cfg; - bool is_vpn : 1; -} NMIPConfigPrivate; +/*****************************************************************************/ + +typedef struct _NMIPConfigPrivate NMIPConfigPrivate; + +NM_GOBJECT_PROPERTIES_DEFINE_FULL(_ip, NMIPConfig, PROP_IP_L3CFG, PROP_IP_IS_VPN, ); G_DEFINE_ABSTRACT_TYPE(NMIPConfig, nm_ip_config, NM_TYPE_DBUS_OBJECT) -#define NM_IP_CONFIG_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMIPConfig, NM_IS_IP_CONFIG) +#define NM_IP_CONFIG_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMIPConfig, NM_IS_IP_CONFIG) /*****************************************************************************/ static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +get_property_ip(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NMIPConfig * self = NM_IP_CONFIG(object); NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self); - (void) priv; + (void) priv; //XXX + switch (prop_id) { default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); @@ -44,14 +47,16 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps { NMIPConfig * self = NM_IP_CONFIG(object); NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self); + gpointer ptr; switch (prop_id) { - case PROP_L3CFG: + case PROP_IP_L3CFG: /* construct-only */ - priv->l3cfg = nm_g_object_ref(g_value_get_pointer(value)); - nm_assert(!priv->l3cfg || NM_IS_L3CFG(priv->l3cfg)); + ptr = g_value_get_pointer(value); + nm_assert(NM_IS_L3CFG(ptr)); + priv->l3cfg = g_object_ref(ptr); break; - case PROP_IS_VPN: + case PROP_IP_IS_VPN: /* construct-only */ priv->is_vpn = g_value_get_boolean(value); break; @@ -65,13 +70,7 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps static void nm_ip_config_init(NMIPConfig *self) -{ - NMIPConfigPrivate *priv; - - priv = G_TYPE_INSTANCE_GET_PRIVATE(self, NM_TYPE_IP_CONFIG, NMIPConfigPrivate); - - self->_priv = priv; -} +{} NMIPConfig * nm_ip_config_new(int addr_family, NML3Cfg *l3cfg, gboolean is_vpn) @@ -88,13 +87,25 @@ nm_ip_config_new(int addr_family, NML3Cfg *l3cfg, gboolean is_vpn) NULL); } +void +nm_ip_config_take_and_unexport_on_idle(NMIPConfig *self_take) +{ + if (!self_take) + return; + + //XXX: freeze the instance so that no more signals are emitted while + // the instance gets unexported. + + nm_dbus_object_unexport_on_idle(g_steal_pointer(&self_take)); +} + static void finalize(GObject *object) { NMIPConfig * self = NM_IP_CONFIG(object); NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self); - nm_g_object_unref(priv->l3cfg); + g_object_unref(priv->l3cfg); G_OBJECT_CLASS(nm_ip_config_parent_class)->finalize(object); } @@ -102,26 +113,420 @@ finalize(GObject *object) static void nm_ip_config_class_init(NMIPConfigClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS(klass); - - g_type_class_add_private(object_class, sizeof(NMIPConfigPrivate)); + GObjectClass * object_class = G_OBJECT_CLASS(klass); + NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - object_class->get_property = get_property; + object_class->get_property = get_property_ip; object_class->set_property = set_property; object_class->finalize = finalize; - obj_properties[PROP_L3CFG] = + dbus_object_class->export_on_construction = TRUE; + + obj_properties_ip[PROP_IP_L3CFG] = g_param_spec_pointer(NM_IP_CONFIG_L3CFG, "", "", G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_IS_VPN] = + obj_properties_ip[PROP_IP_IS_VPN] = g_param_spec_boolean(NM_IP_CONFIG_IS_VPN, "", "", FALSE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST_ip, obj_properties_ip); +} + +/*****************************************************************************/ + +/* public*/ +#define NM_IP4_CONFIG_ADDRESS_DATA "address-data" +#define NM_IP4_CONFIG_DNS_OPTIONS "dns-options" +#define NM_IP4_CONFIG_DNS_PRIORITY "dns-priority" +#define NM_IP4_CONFIG_DOMAINS "domains" +#define NM_IP4_CONFIG_GATEWAY "gateway" +#define NM_IP4_CONFIG_NAMESERVER_DATA "nameserver-data" +#define NM_IP4_CONFIG_ROUTE_DATA "route-data" +#define NM_IP4_CONFIG_SEARCHES "searches" +#define NM_IP4_CONFIG_WINS_SERVER_DATA "wins-server-data" + +/* deprecated */ +#define NM_IP4_CONFIG_ADDRESSES "addresses" +#define NM_IP4_CONFIG_NAMESERVERS "nameservers" +#define NM_IP4_CONFIG_ROUTES "routes" +#define NM_IP4_CONFIG_WINS_SERVERS "wins-servers" + +typedef struct _NMIP4Config NMIP4Config; +typedef struct _NMIP4ConfigClass NMIP4ConfigClass; + +NM_GOBJECT_PROPERTIES_DEFINE_FULL(_ip4, + NMIP4Config, + PROP_IP4_ADDRESSES, + PROP_IP4_ADDRESS_DATA, + PROP_IP4_DNS_OPTIONS, + PROP_IP4_DNS_PRIORITY, + PROP_IP4_DOMAINS, + PROP_IP4_GATEWAY, + PROP_IP4_NAMESERVERS, + PROP_IP4_NAMESERVER_DATA, + PROP_IP4_ROUTES, + PROP_IP4_ROUTE_DATA, + PROP_IP4_SEARCHES, + PROP_IP4_WINS_SERVERS, + PROP_IP4_WINS_SERVER_DATA, ); + +struct _NMIP4Config { + NMIPConfig parent; +}; + +struct _NMIP4ConfigClass { + NMIPConfigClass parent; +}; + +G_DEFINE_TYPE(NMIP4Config, nm_ip4_config, NM_TYPE_IP_CONFIG) + +static void +get_property_ip4(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + NMIPConfig * self = NM_IP_CONFIG(object); + NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self); + + (void) priv; //XXX + + switch (prop_id) { + default: + return; //XXX + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static const NMDBusInterfaceInfoExtended interface_info_ip4_config = { + .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( + NM_DBUS_INTERFACE_IP4_CONFIG, + .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( + 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("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("WinsServers", + "au", + NM_IP4_CONFIG_WINS_SERVERS), ), ), +}; + +static void +nm_ip4_config_init(NMIP4Config *self) +{} + +static void +nm_ip4_config_class_init(NMIP4ConfigClass *klass) +{ + GObjectClass * object_class = G_OBJECT_CLASS(klass); + NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); + NMIPConfigClass * ip_config_class = NM_IP_CONFIG_CLASS(klass); + + ip_config_class->addr_family = AF_INET; + + dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED(NM_DBUS_PATH "/IP4Config"); + dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_ip4_config); + + object_class->get_property = get_property_ip4; + + obj_properties_ip4[PROP_IP4_ADDRESS_DATA] = + g_param_spec_variant(NM_IP4_CONFIG_ADDRESS_DATA, + "", + "", + G_VARIANT_TYPE("aa{sv}"), + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties_ip4[PROP_IP4_ADDRESSES] = + g_param_spec_variant(NM_IP4_CONFIG_ADDRESSES, + "", + "", + G_VARIANT_TYPE("aau"), + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties_ip4[PROP_IP4_ROUTE_DATA] = + g_param_spec_variant(NM_IP4_CONFIG_ROUTE_DATA, + "", + "", + G_VARIANT_TYPE("aa{sv}"), + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties_ip4[PROP_IP4_ROUTES] = + g_param_spec_variant(NM_IP4_CONFIG_ROUTES, + "", + "", + G_VARIANT_TYPE("aau"), + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties_ip4[PROP_IP4_GATEWAY] = + g_param_spec_string(NM_IP4_CONFIG_GATEWAY, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties_ip4[PROP_IP4_NAMESERVER_DATA] = + g_param_spec_variant(NM_IP4_CONFIG_NAMESERVER_DATA, + "", + "", + G_VARIANT_TYPE("aa{sv}"), + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties_ip4[PROP_IP4_NAMESERVERS] = + g_param_spec_variant(NM_IP4_CONFIG_NAMESERVERS, + "", + "", + G_VARIANT_TYPE("au"), + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties_ip4[PROP_IP4_DOMAINS] = + g_param_spec_boxed(NM_IP4_CONFIG_DOMAINS, + "", + "", + G_TYPE_STRV, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties_ip4[PROP_IP4_SEARCHES] = + g_param_spec_boxed(NM_IP4_CONFIG_SEARCHES, + "", + "", + G_TYPE_STRV, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties_ip4[PROP_IP4_DNS_OPTIONS] = + g_param_spec_boxed(NM_IP4_CONFIG_DNS_OPTIONS, + "", + "", + G_TYPE_STRV, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties_ip4[PROP_IP4_DNS_PRIORITY] = + g_param_spec_int(NM_IP4_CONFIG_DNS_PRIORITY, + "", + "", + G_MININT32, + G_MAXINT32, + 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties_ip4[PROP_IP4_WINS_SERVER_DATA] = + g_param_spec_variant(NM_IP4_CONFIG_WINS_SERVER_DATA, + "", + "", + G_VARIANT_TYPE("as"), + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties_ip4[PROP_IP4_WINS_SERVERS] = + g_param_spec_variant(NM_IP4_CONFIG_WINS_SERVERS, + "", + "", + G_VARIANT_TYPE("au"), + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST_ip4, obj_properties_ip4); +} + +/*****************************************************************************/ + +/* public */ +#define NM_IP6_CONFIG_ADDRESS_DATA "address-data" +#define NM_IP6_CONFIG_ROUTE_DATA "route-data" +#define NM_IP6_CONFIG_GATEWAY "gateway" +#define NM_IP6_CONFIG_NAMESERVERS "nameservers" +#define NM_IP6_CONFIG_DOMAINS "domains" +#define NM_IP6_CONFIG_SEARCHES "searches" +#define NM_IP6_CONFIG_DNS_OPTIONS "dns-options" +#define NM_IP6_CONFIG_DNS_PRIORITY "dns-priority" + +/* deprecated */ +#define NM_IP6_CONFIG_ADDRESSES "addresses" +#define NM_IP6_CONFIG_ROUTES "routes" + +typedef struct _NMIP6Config NMIP6Config; +typedef struct _NMIP6ConfigClass NMIP6ConfigClass; + +NM_GOBJECT_PROPERTIES_DEFINE_FULL(_ip6, + NMIP6Config, + PROP_IP6_ADDRESS_DATA, + PROP_IP6_ROUTE_DATA, + PROP_IP6_GATEWAY, + PROP_IP6_NAMESERVERS, + PROP_IP6_DOMAINS, + PROP_IP6_SEARCHES, + PROP_IP6_DNS_OPTIONS, + PROP_IP6_DNS_PRIORITY, + PROP_IP6_ADDRESSES, + PROP_IP6_ROUTES, ); + +struct _NMIP6Config { + NMIPConfig parent; +}; + +struct _NMIP6ConfigClass { + NMIPConfigClass parent; +}; + +G_DEFINE_TYPE(NMIP6Config, nm_ip6_config, NM_TYPE_IP_CONFIG) + +static const NMDBusInterfaceInfoExtended interface_info_ip6_config = { + .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( + NM_DBUS_INTERFACE_IP6_CONFIG, + .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( + 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 +get_property_ip6(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + NMIPConfig * self = NM_IP_CONFIG(object); + NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self); + + (void) priv; //XXX + + switch (prop_id) { + //XXX + default: + return; //XXX + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +nm_ip6_config_init(NMIP6Config *self) +{} + +static void +nm_ip6_config_class_init(NMIP6ConfigClass *klass) +{ + GObjectClass * object_class = G_OBJECT_CLASS(klass); + NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); + NMIPConfigClass * ip_config_class = NM_IP_CONFIG_CLASS(klass); + + ip_config_class->addr_family = AF_INET6; + + dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED(NM_DBUS_PATH "/IP6Config"); + dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_ip6_config); + + object_class->get_property = get_property_ip6; + + obj_properties_ip6[PROP_IP6_ADDRESS_DATA] = + g_param_spec_variant(NM_IP6_CONFIG_ADDRESS_DATA, + "", + "", + G_VARIANT_TYPE("aa{sv}"), + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties_ip6[PROP_IP6_ADDRESSES] = + g_param_spec_variant(NM_IP6_CONFIG_ADDRESSES, + "", + "", + G_VARIANT_TYPE("a(ayuay)"), + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties_ip6[PROP_IP6_ROUTE_DATA] = + g_param_spec_variant(NM_IP6_CONFIG_ROUTE_DATA, + "", + "", + G_VARIANT_TYPE("aa{sv}"), + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties_ip6[PROP_IP6_ROUTES] = + g_param_spec_variant(NM_IP6_CONFIG_ROUTES, + "", + "", + G_VARIANT_TYPE("a(ayuayu)"), + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties_ip6[PROP_IP6_GATEWAY] = + g_param_spec_string(NM_IP6_CONFIG_GATEWAY, + "", + "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties_ip6[PROP_IP6_NAMESERVERS] = + g_param_spec_variant(NM_IP6_CONFIG_NAMESERVERS, + "", + "", + G_VARIANT_TYPE("aay"), + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties_ip6[PROP_IP6_DOMAINS] = + g_param_spec_boxed(NM_IP6_CONFIG_DOMAINS, + "", + "", + G_TYPE_STRV, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties_ip6[PROP_IP6_SEARCHES] = + g_param_spec_boxed(NM_IP6_CONFIG_SEARCHES, + "", + "", + G_TYPE_STRV, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties_ip6[PROP_IP6_DNS_OPTIONS] = + g_param_spec_boxed(NM_IP6_CONFIG_DNS_OPTIONS, + "", + "", + G_TYPE_STRV, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties_ip6[PROP_IP6_DNS_PRIORITY] = + g_param_spec_int(NM_IP6_CONFIG_DNS_PRIORITY, + "", + "", + G_MININT32, + G_MAXINT32, + 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST_ip6, obj_properties_ip6); } diff --git a/src/core/nm-ip-config.h b/src/core/nm-ip-config.h index 8e1a593412..6e4022b5e0 100644 --- a/src/core/nm-ip-config.h +++ b/src/core/nm-ip-config.h @@ -7,6 +7,7 @@ #define __NM_IP_CONFIG_H__ #include "nm-dbus-object.h" +#include "nm-l3cfg.h" /*****************************************************************************/ @@ -22,23 +23,55 @@ #define NM_IP_CONFIG_L3CFG "l3cfg" #define NM_IP_CONFIG_IS_VPN "is-vpn" -struct _NMIPConfigPrivate; +struct _NMIPConfigPrivate { + NML3Cfg *l3cfg; + bool is_vpn : 1; +}; struct _NMIPConfig { - NMDBusObject parent; - struct _NMIPConfigPrivate *_priv; + NMDBusObject parent; + struct _NMIPConfigPrivate _priv; }; typedef struct { NMDBusObjectClass parent; - gboolean is_ipv4; int addr_family; } NMIPConfigClass; GType nm_ip_config_get_type(void); -GType nm_ip4_config_get_type(void); -GType nm_ip6_config_get_type(void); NMIPConfig *nm_ip_config_new(int addr_family, NML3Cfg *l3cfg, gboolean is_vpn); +void nm_ip_config_take_and_unexport_on_idle(NMIPConfig *self_take); + +/*****************************************************************************/ + +static inline NML3Cfg * +nm_ip_config_get_l3cfg(NMIPConfig *self) +{ + g_return_val_if_fail(NM_IS_IP_CONFIG(self), NULL); + + return self->_priv.l3cfg; +} + +static inline struct _NMDedupMultiIndex * +nm_ip_config_get_multi_index(NMIPConfig *self) +{ + return nm_l3cfg_get_multi_idx(nm_ip_config_get_l3cfg(self)); +} + +static inline int +nm_ip_config_get_ifindex(NMIPConfig *self) +{ + return nm_l3cfg_get_ifindex(nm_ip_config_get_l3cfg(self)); +} + +static inline int +nm_ip_config_get_addr_family(NMIPConfig *self) +{ + g_return_val_if_fail(NM_IS_IP_CONFIG(self), AF_UNSPEC); + + return NM_IP_CONFIG_GET_CLASS(self)->addr_family; +} + #endif /* __NM_IP_CONFIG_H__ */ diff --git a/src/core/nm-ip4-config.c b/src/core/nm-ip4-config.c deleted file mode 100644 index 171ed4bae1..0000000000 --- a/src/core/nm-ip4-config.c +++ /dev/null @@ -1,3297 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2005 - 2017 Red Hat, Inc. - * Copyright (C) 2006 - 2008 Novell, Inc. - */ - -#include "src/core/nm-default-daemon.h" - -#include "nm-ip4-config.h" - -#include -#include -#include - -#include "libnm-glib-aux/nm-dedup-multi.h" - -#include "nm-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 "libnm-core-intern/nm-core-internal.h" -#include "nm-dbus-object.h" - -/*****************************************************************************/ - -/* internal guint32 are assigned to gobject properties of type uint. Ensure, that uint is large enough */ -G_STATIC_ASSERT(sizeof(uint) >= sizeof(guint32)); -G_STATIC_ASSERT(G_MAXUINT >= 0xFFFFFFFF); - -/*****************************************************************************/ - -static gboolean -_route_valid(const NMPlatformIP4Route *r) -{ - return r && r->plen <= 32 - && r->network == nm_utils_ip4_address_clear_host_address(r->network, r->plen); -} - -/*****************************************************************************/ - -static void -_idx_obj_id_hash_update(const NMDedupMultiIdxType *idx_type, - const NMDedupMultiObj * obj, - NMHashState * h) -{ - nmp_object_id_hash_update((NMPObject *) obj, h); -} - -static gboolean -_idx_obj_id_equal(const NMDedupMultiIdxType *idx_type, - const NMDedupMultiObj * obj_a, - const NMDedupMultiObj * obj_b) -{ - return nmp_object_id_equal((NMPObject *) obj_a, (NMPObject *) obj_b); -} - -void -nm_ip_config_dedup_multi_idx_type_init(NMIPConfigDedupMultiIdxType *idx_type, - NMPObjectType obj_type) -{ - static const NMDedupMultiIdxTypeClass idx_type_class = { - .idx_obj_id_hash_update = _idx_obj_id_hash_update, - .idx_obj_id_equal = _idx_obj_id_equal, - }; - - nm_dedup_multi_idx_type_init((NMDedupMultiIdxType *) idx_type, &idx_type_class); - idx_type->obj_type = obj_type; -} - -/*****************************************************************************/ - -gboolean -_nm_ip_config_add_obj(NMDedupMultiIndex * multi_idx, - NMIPConfigDedupMultiIdxType *idx_type, - int ifindex, - const NMPObject * obj_new, - const NMPlatformObject * pl_new, - gboolean merge, - gboolean append_force, - const NMPObject ** out_obj_old /* returns a reference! */, - const NMPObject ** out_obj_new /* does not return a reference */) -{ - NMPObject obj_new_stackinit; - const NMDedupMultiEntry *entry_old; - const NMDedupMultiEntry *entry_new; - - nm_assert(multi_idx); - nm_assert(idx_type); - nm_assert(NM_IN_SET(idx_type->obj_type, - NMP_OBJECT_TYPE_IP4_ADDRESS, - NMP_OBJECT_TYPE_IP4_ROUTE, - NMP_OBJECT_TYPE_IP6_ADDRESS, - NMP_OBJECT_TYPE_IP6_ROUTE)); - nm_assert(ifindex > 0); - - /* we go through extra lengths to accept a full obj_new object. That one, - * can be reused by increasing the ref-count. */ - if (!obj_new) { - nm_assert(pl_new); - obj_new = nmp_object_stackinit(&obj_new_stackinit, idx_type->obj_type, pl_new); - NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(&obj_new_stackinit)->ifindex = ifindex; - } else { - nm_assert(!pl_new); - nm_assert(NMP_OBJECT_GET_TYPE(obj_new) == idx_type->obj_type); - if (NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj_new)->ifindex != ifindex) { - obj_new = nmp_object_stackinit_obj(&obj_new_stackinit, obj_new); - NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(&obj_new_stackinit)->ifindex = ifindex; - } - } - nm_assert(NMP_OBJECT_GET_TYPE(obj_new) == idx_type->obj_type); - nm_assert(nmp_object_is_alive(obj_new)); - - entry_old = nm_dedup_multi_index_lookup_obj(multi_idx, &idx_type->parent, obj_new); - - if (entry_old) { - gboolean modified = FALSE; - const NMPObject *obj_old = entry_old->obj; - - if (nmp_object_equal(obj_new, obj_old)) { - nm_dedup_multi_entry_set_dirty(entry_old, FALSE); - goto append_force_and_out; - } - - /* if @merge, we merge the new object with the existing one. - * Otherwise, we replace it entirely. */ - if (merge) { - switch (idx_type->obj_type) { - case NMP_OBJECT_TYPE_IP4_ADDRESS: - case NMP_OBJECT_TYPE_IP6_ADDRESS: - /* for addresses that we read from the kernel, we keep the timestamps as defined - * by the previous source (item_old). The reason is, that the other source configured the lifetimes - * with "what should be" and the kernel values are "what turned out after configuring it". - * - * For other sources, the longer lifetime wins. */ - if ((obj_new->ip_address.addr_source == NM_IP_CONFIG_SOURCE_KERNEL - && obj_old->ip_address.addr_source != NM_IP_CONFIG_SOURCE_KERNEL) - || nm_platform_ip_address_cmp_expiry(NMP_OBJECT_CAST_IP_ADDRESS(obj_old), - NMP_OBJECT_CAST_IP_ADDRESS(obj_new)) - > 0) { - obj_new = nmp_object_stackinit_obj(&obj_new_stackinit, obj_new); - obj_new_stackinit.ip_address.timestamp = - NMP_OBJECT_CAST_IP_ADDRESS(obj_old)->timestamp; - obj_new_stackinit.ip_address.lifetime = - NMP_OBJECT_CAST_IP_ADDRESS(obj_old)->lifetime; - obj_new_stackinit.ip_address.preferred = - NMP_OBJECT_CAST_IP_ADDRESS(obj_old)->preferred; - modified = TRUE; - } - - /* keep the maximum addr_source. */ - if (obj_new->ip_address.addr_source < obj_old->ip_address.addr_source) { - obj_new = nmp_object_stackinit_obj(&obj_new_stackinit, obj_new); - obj_new_stackinit.ip_address.addr_source = obj_old->ip_address.addr_source; - modified = TRUE; - } - break; - case NMP_OBJECT_TYPE_IP4_ROUTE: - case NMP_OBJECT_TYPE_IP6_ROUTE: - /* keep the maximum rt_source. */ - if (obj_new->ip_route.rt_source < obj_old->ip_route.rt_source) { - obj_new = nmp_object_stackinit_obj(&obj_new_stackinit, obj_new); - obj_new_stackinit.ip_route.rt_source = obj_old->ip_route.rt_source; - modified = TRUE; - } - break; - default: - nm_assert_not_reached(); - break; - } - - if (modified && nmp_object_equal(obj_new, obj_old)) { - nm_dedup_multi_entry_set_dirty(entry_old, FALSE); - goto append_force_and_out; - } - } - } - - if (!nm_dedup_multi_index_add_full(multi_idx, - &idx_type->parent, - obj_new, - append_force ? NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE - : NM_DEDUP_MULTI_IDX_MODE_APPEND, - NULL, - entry_old ?: NM_DEDUP_MULTI_ENTRY_MISSING, - NULL, - &entry_new, - out_obj_old)) { - nm_assert_not_reached(); - NM_SET_OUT(out_obj_new, NULL); - return FALSE; - } - - NM_SET_OUT(out_obj_new, entry_new->obj); - return TRUE; - -append_force_and_out: - NM_SET_OUT(out_obj_old, nmp_object_ref(entry_old->obj)); - NM_SET_OUT(out_obj_new, entry_old->obj); - if (append_force) { - if (nm_dedup_multi_entry_reorder(entry_old, NULL, TRUE)) - return TRUE; - } - return FALSE; -} - -/** - * _nm_ip_config_lookup_ip_route: - * @multi_idx: - * @idx_type: - * @needle: - * @cmp_type: after lookup, filter the result by comparing with @cmp_type. Only - * return the result, if it compares equal to @needle according to this @cmp_type. - * Note that the index uses %NM_PLATFORM_IP_ROUTE_CMP_TYPE_DST type, so passing - * that compare-type means not to filter any further. - * - * Returns: the found entry or %NULL. - */ -const NMDedupMultiEntry * -_nm_ip_config_lookup_ip_route(const NMDedupMultiIndex * multi_idx, - const NMIPConfigDedupMultiIdxType *idx_type, - const NMPObject * needle, - NMPlatformIPRouteCmpType cmp_type) -{ - const NMDedupMultiEntry *entry; - - nm_assert(multi_idx); - nm_assert(idx_type); - nm_assert(NM_IN_SET(idx_type->obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); - nm_assert(NMP_OBJECT_GET_TYPE(needle) == idx_type->obj_type); - - entry = nm_dedup_multi_index_lookup_obj(multi_idx, &idx_type->parent, needle); - if (!entry) - return NULL; - - if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) { - nm_assert((NMP_OBJECT_GET_TYPE(needle) == NMP_OBJECT_TYPE_IP4_ROUTE - && nm_platform_ip4_route_cmp(NMP_OBJECT_CAST_IP4_ROUTE(entry->obj), - NMP_OBJECT_CAST_IP4_ROUTE(needle), - cmp_type) - == 0) - || (NMP_OBJECT_GET_TYPE(needle) == NMP_OBJECT_TYPE_IP6_ROUTE - && nm_platform_ip6_route_cmp(NMP_OBJECT_CAST_IP6_ROUTE(entry->obj), - NMP_OBJECT_CAST_IP6_ROUTE(needle), - cmp_type) - == 0)); - } else { - if (NMP_OBJECT_GET_TYPE(needle) == NMP_OBJECT_TYPE_IP4_ROUTE) { - if (nm_platform_ip4_route_cmp(NMP_OBJECT_CAST_IP4_ROUTE(entry->obj), - NMP_OBJECT_CAST_IP4_ROUTE(needle), - cmp_type) - != 0) - return NULL; - } else { - if (nm_platform_ip6_route_cmp(NMP_OBJECT_CAST_IP6_ROUTE(entry->obj), - NMP_OBJECT_CAST_IP6_ROUTE(needle), - cmp_type) - != 0) - return NULL; - } - } - return entry; -} - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE(NMIP4Config, - PROP_MULTI_IDX, - PROP_IFINDEX, - PROP_ADDRESS_DATA, - PROP_ADDRESSES, - PROP_ROUTE_DATA, - PROP_ROUTES, - PROP_GATEWAY, - PROP_NAMESERVER_DATA, - PROP_NAMESERVERS, - PROP_DOMAINS, - PROP_SEARCHES, - PROP_DNS_OPTIONS, - PROP_WINS_SERVER_DATA, - PROP_WINS_SERVERS, - PROP_DNS_PRIORITY, ); - -typedef struct { - bool metered : 1; - bool never_default : 1; - guint32 mtu; - int ifindex; - NMIPConfigSource mtu_source; - int dns_priority; - NMSettingConnectionMdns mdns; - NMSettingConnectionLlmnr llmnr; - GArray * nameservers; - GPtrArray * domains; - GPtrArray * searches; - GPtrArray * dns_options; - GArray * nis; - char * nis_domain; - GArray * wins; - GVariant * address_data_variant; - GVariant * addresses_variant; - GVariant * route_data_variant; - GVariant * routes_variant; - NMDedupMultiIndex * multi_idx; - const NMPObject * best_default_route; - union { - NMIPConfigDedupMultiIdxType idx_ip4_addresses_; - NMDedupMultiIdxType idx_ip4_addresses; - }; - union { - NMIPConfigDedupMultiIdxType idx_ip4_routes_; - NMDedupMultiIdxType idx_ip4_routes; - }; - NMIPConfigFlags config_flags; -} NMIP4ConfigPrivate; - -struct _NMIP4Config { - NMIPConfig parent; - NMIP4ConfigPrivate _priv; -}; - -struct _NMIP4ConfigClass { - NMIPConfigClass parent; -}; - -G_DEFINE_TYPE(NMIP4Config, nm_ip4_config, NM_TYPE_IP_CONFIG) - -#define NM_IP4_CONFIG_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMIP4Config, NM_IS_IP4_CONFIG) - -/*****************************************************************************/ - -static void -_add_address(NMIP4Config *self, const NMPObject *obj_new, const NMPlatformIP4Address *new); -static void _add_route(NMIP4Config * self, - const NMPObject *obj_new, - const NMPlatformIP4Route *new, - const NMPObject **out_obj_new); -static const NMDedupMultiEntry * -_lookup_route(const NMIP4Config *self, const NMPObject *needle, NMPlatformIPRouteCmpType cmp_type); - -/*****************************************************************************/ - -int -nm_ip4_config_get_ifindex(const NMIP4Config *self) -{ - return NM_IP4_CONFIG_GET_PRIVATE(self)->ifindex; -} - -NMDedupMultiIndex * -nm_ip4_config_get_multi_idx(const NMIP4Config *self) -{ - return NM_IP4_CONFIG_GET_PRIVATE(self)->multi_idx; -} - -/*****************************************************************************/ - -const NMDedupMultiHeadEntry * -nm_ip4_config_lookup_addresses(const NMIP4Config *self) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - return nm_dedup_multi_index_lookup_head(priv->multi_idx, &priv->idx_ip4_addresses, NULL); -} - -void -nm_ip_config_iter_ip4_address_init(NMDedupMultiIter *ipconf_iter, const NMIP4Config *self) -{ - nm_assert(NM_IS_IP4_CONFIG(self)); - - nm_dedup_multi_iter_init(ipconf_iter, nm_ip4_config_lookup_addresses(self)); -} - -/*****************************************************************************/ - -const NMDedupMultiHeadEntry * -nm_ip4_config_lookup_routes(const NMIP4Config *self) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - return nm_dedup_multi_index_lookup_head(priv->multi_idx, &priv->idx_ip4_routes, NULL); -} - -void -nm_ip_config_iter_ip4_route_init(NMDedupMultiIter *ipconf_iter, const NMIP4Config *self) -{ - nm_assert(NM_IS_IP4_CONFIG(self)); - - nm_dedup_multi_iter_init(ipconf_iter, nm_ip4_config_lookup_routes(self)); -} - -/*****************************************************************************/ - -const NMPObject * -_nm_ip_config_best_default_route_find_better(const NMPObject *obj_cur, const NMPObject *obj_cmp) -{ - nm_assert(!obj_cur - || NM_IN_SET(NMP_OBJECT_GET_TYPE(obj_cur), - NMP_OBJECT_TYPE_IP4_ROUTE, - NMP_OBJECT_TYPE_IP6_ROUTE)); - nm_assert(!obj_cmp - || (!obj_cur - && NM_IN_SET(NMP_OBJECT_GET_TYPE(obj_cmp), - NMP_OBJECT_TYPE_IP4_ROUTE, - NMP_OBJECT_TYPE_IP6_ROUTE)) - || NMP_OBJECT_GET_TYPE(obj_cur) == NMP_OBJECT_GET_TYPE(obj_cmp)); - nm_assert(!obj_cur || nmp_object_ip_route_is_best_defaut_route(obj_cur)); - - /* assumes that @obj_cur is already the best default route (or NULL). It checks whether - * @obj_cmp is also a default route and returns the best of both. */ - if (obj_cmp && nmp_object_ip_route_is_best_defaut_route(obj_cmp)) { - guint32 metric_cur, metric_cmp; - - if (!obj_cur) - return obj_cmp; - - metric_cur = NMP_OBJECT_CAST_IP_ROUTE(obj_cur)->metric; - metric_cmp = NMP_OBJECT_CAST_IP_ROUTE(obj_cmp)->metric; - - if (metric_cmp < metric_cur) - return obj_cmp; - - if (metric_cmp == metric_cur) { - int c; - - /* Routes have the same metric. We still want to deterministically - * prefer one or the other. It's important to consistently choose one - * or the other, so that the order doesn't matter how routes are added - * (and merged). */ - c = nmp_object_cmp(obj_cur, obj_cmp); - if (c != 0) - return c < 0 ? obj_cur : obj_cmp; - - /* as last resort, compare pointers. */ - if (obj_cmp < obj_cur) - return obj_cmp; - } - } - return obj_cur; -} - -gboolean -_nm_ip_config_best_default_route_merge(const NMPObject **best_default_route, - const NMPObject * new_candidate) -{ - new_candidate = - _nm_ip_config_best_default_route_find_better(*best_default_route, new_candidate); - return nmp_object_ref_set(best_default_route, new_candidate); -} - -const NMPObject * -nm_ip4_config_best_default_route_get(const NMIP4Config *self) -{ - g_return_val_if_fail(NM_IS_IP4_CONFIG(self), NULL); - - return NM_IP4_CONFIG_GET_PRIVATE(self)->best_default_route; -} - -const NMPObject * -_nm_ip4_config_best_default_route_find(const NMIP4Config *self) -{ - NMDedupMultiIter ipconf_iter; - const NMPObject *new_best_default_route = NULL; - - nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, self, NULL) { - new_best_default_route = - _nm_ip_config_best_default_route_find_better(new_best_default_route, - ipconf_iter.current->obj); - } - return new_best_default_route; -} - -in_addr_t -nmtst_ip4_config_get_gateway(NMIP4Config *config) -{ - const NMPObject *rt; - - g_assert(NM_IS_IP4_CONFIG(config)); - - rt = nm_ip4_config_best_default_route_get(config); - if (!rt) - return 0; - return NMP_OBJECT_CAST_IP4_ROUTE(rt)->gateway; -} - -/*****************************************************************************/ - -static void -_notify_addresses(NMIP4Config *self) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - nm_clear_g_variant(&priv->address_data_variant); - nm_clear_g_variant(&priv->addresses_variant); - nm_gobject_notify_together(self, PROP_ADDRESS_DATA, PROP_ADDRESSES); -} - -static void -_notify_routes(NMIP4Config *self) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - nm_assert(priv->best_default_route == _nm_ip4_config_best_default_route_find(self)); - nm_clear_g_variant(&priv->route_data_variant); - nm_clear_g_variant(&priv->routes_variant); - nm_gobject_notify_together(self, PROP_ROUTE_DATA, PROP_ROUTES); -} - -/*****************************************************************************/ - -static int -sort_captured_addresses(const CList *lst_a, const CList *lst_b, gconstpointer user_data) -{ - const NMPlatformIP4Address *addr_a = - NMP_OBJECT_CAST_IP4_ADDRESS(c_list_entry(lst_a, NMDedupMultiEntry, lst_entries)->obj); - const NMPlatformIP4Address *addr_b = - NMP_OBJECT_CAST_IP4_ADDRESS(c_list_entry(lst_b, NMDedupMultiEntry, lst_entries)->obj); - - nm_assert(addr_a); - nm_assert(addr_b); - - /* Primary addresses first */ - return NM_FLAGS_HAS(addr_a->n_ifa_flags, IFA_F_SECONDARY) - - NM_FLAGS_HAS(addr_b->n_ifa_flags, IFA_F_SECONDARY); -} - -NMIP4Config * -nm_ip4_config_clone(const NMIP4Config *self) -{ - NMIP4Config *copy; - - copy = nm_ip4_config_new(nm_ip4_config_get_multi_idx(self), -1); - nm_ip4_config_replace(copy, self, NULL); - - return copy; -} - -NMIP4Config * -nm_ip4_config_capture(NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex) -{ - NMIP4Config * self; - NMIP4ConfigPrivate * priv; - const NMDedupMultiHeadEntry *head_entry; - NMDedupMultiIter iter; - const NMPObject * plobj = NULL; - - nm_assert(ifindex > 0); - - /* Slaves have no IP configuration */ - if (nm_platform_link_get_master(platform, ifindex) > 0) - return NULL; - - self = nm_ip4_config_new(multi_idx, ifindex); - priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - head_entry = nm_platform_lookup_object(platform, NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex); - if (head_entry) { - nmp_cache_iter_for_each (&iter, head_entry, &plobj) { - if (!_nm_ip_config_add_obj(priv->multi_idx, - &priv->idx_ip4_addresses_, - ifindex, - plobj, - NULL, - FALSE, - TRUE, - NULL, - NULL)) - nm_assert_not_reached(); - } - head_entry = nm_ip4_config_lookup_addresses(self); - nm_assert(head_entry); - nm_dedup_multi_head_entry_sort(head_entry, sort_captured_addresses, NULL); - _notify_addresses(self); - } - - head_entry = nm_platform_lookup_object(platform, NMP_OBJECT_TYPE_IP4_ROUTE, ifindex); - - /* Extract gateway from default route */ - nmp_cache_iter_for_each (&iter, head_entry, &plobj) - _add_route(self, plobj, NULL, NULL); - - return self; -} - -void -nm_ip4_config_update_routes_metric(NMIP4Config *self, gint64 metric) -{ - gs_free NMPlatformIP4Route *routes = NULL; - gboolean need_update = FALSE; - const NMPlatformIP4Route * r; - NMDedupMultiIter iter; - guint num = 0, i = 0; - - nm_ip_config_iter_ip4_route_for_each (&iter, self, &r) { - if (r->metric != metric) - need_update = TRUE; - num++; - } - if (!need_update) - return; - - routes = g_new(NMPlatformIP4Route, num); - nm_ip_config_iter_ip4_route_for_each (&iter, self, &r) { - routes[i] = *r; - routes[i].metric = metric; - i++; - } - - g_object_freeze_notify(G_OBJECT(self)); - nm_ip4_config_reset_routes(self); - for (i = 0; i < num; i++) - nm_ip4_config_add_route(self, &routes[i], NULL); - g_object_thaw_notify(G_OBJECT(self)); -} - -void -nm_ip4_config_add_dependent_routes(NMIP4Config *self, - guint32 route_table, - guint32 route_metric, - gboolean is_vrf, - GPtrArray ** out_ip4_dev_route_blacklist) -{ - GPtrArray * ip4_dev_route_blacklist = NULL; - const NMPlatformIP4Address *my_addr; - const NMPlatformIP4Route * my_route; - int ifindex; - NMDedupMultiIter iter; - - g_return_if_fail(NM_IS_IP4_CONFIG(self)); - - ifindex = nm_ip4_config_get_ifindex(self); - g_return_if_fail(ifindex > 0); - - /* For IPv6 slaac, we explicitly add the device-routes (onlink) to NMIP6Config. - * As we don't do that for IPv4 (and manual IPv6 addresses), add them explicitly. */ - - nm_ip_config_iter_ip4_address_for_each (&iter, self, &my_addr) { - nm_auto_nmpobj NMPObject *r = NULL; - NMPlatformIP4Route * route; - in_addr_t network; - - if (my_addr->plen == 0) - continue; - - nm_assert(my_addr->plen <= 32); - - /* The destination network depends on the peer-address. */ - network = nm_utils_ip4_address_clear_host_address(my_addr->peer_address, my_addr->plen); - - if (my_addr->external) - continue; - - 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. */ - continue; - } - - if (my_addr->plen == 32 && my_addr->address == my_addr->peer_address) { - /* Kernel doesn't add device-routes for /32 addresses unless - * they have a peer. */ - continue; - } - - 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 = network; - route->plen = my_addr->plen; - route->pref_src = my_addr->address; - route->table_coerced = nm_platform_route_table_coerce(route_table); - route->metric = route_metric; - route->scope_inv = nm_platform_route_scope_inv(NM_RT_SCOPE_LINK); - - nm_platform_ip_route_normalize(AF_INET, (NMPlatformIPRoute *) route); - - if (_lookup_route(self, r, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID)) { - /* we already track this route. Don't add it again. */ - } else - _add_route(self, r, NULL, NULL); - - if (out_ip4_dev_route_blacklist - && (route_table != RT_TABLE_MAIN - || route_metric != NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE)) { - nm_auto_nmpobj NMPObject *r_dev = NULL; - - r_dev = nmp_object_clone(r, FALSE); - route = NMP_OBJECT_CAST_IP4_ROUTE(r_dev); - route->table_coerced = nm_platform_route_table_coerce(RT_TABLE_MAIN); - route->metric = NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE; - - nm_platform_ip_route_normalize(AF_INET, (NMPlatformIPRoute *) route); - - if (_lookup_route(self, r_dev, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID)) { - /* we track such a route explicitly. Don't blacklist it. */ - } else { - if (!ip4_dev_route_blacklist) - ip4_dev_route_blacklist = - g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref); - - g_ptr_array_add(ip4_dev_route_blacklist, g_steal_pointer(&r_dev)); - } - } - } - -again: - nm_ip_config_iter_ip4_route_for_each (&iter, self, &my_route) { - NMPlatformIP4Route rt; - - if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT(my_route) || my_route->gateway == 0 - || NM_IS_IP_CONFIG_SOURCE_RTPROT(my_route->rt_source) - || nm_ip4_config_get_direct_route_for_host( - self, - my_route->gateway, - nm_platform_route_table_uncoerce(my_route->table_coerced, TRUE))) - continue; - - rt = *my_route; - rt.network = my_route->gateway; - rt.plen = 32; - rt.gateway = 0; - _add_route(self, NULL, &rt, NULL); - /* adding the route might have invalidated the iteration. Start again. */ - goto again; - } - - NM_SET_OUT(out_ip4_dev_route_blacklist, ip4_dev_route_blacklist); -} - -gboolean -nm_ip4_config_commit(const NMIP4Config * self, - NMPlatform * platform, - NMIPRouteTableSyncMode route_table_sync) -{ - gs_unref_ptrarray GPtrArray *addresses = NULL; - gs_unref_ptrarray GPtrArray *routes = NULL; - gs_unref_ptrarray GPtrArray *routes_prune = NULL; - int ifindex; - gboolean success = TRUE; - - g_return_val_if_fail(NM_IS_IP4_CONFIG(self), FALSE); - - ifindex = nm_ip4_config_get_ifindex(self); - g_return_val_if_fail(ifindex > 0, FALSE); - - addresses = - nm_dedup_multi_objs_to_ptr_array_head(nm_ip4_config_lookup_addresses(self), NULL, NULL); - - routes = nm_dedup_multi_objs_to_ptr_array_head(nm_ip4_config_lookup_routes(self), NULL, NULL); - - routes_prune = - nm_platform_ip_route_get_prune_list(platform, AF_INET, ifindex, route_table_sync); - - nm_platform_ip4_address_sync(platform, ifindex, addresses); - - if (!nm_platform_ip_route_sync(platform, AF_INET, ifindex, routes, routes_prune, NULL)) - success = FALSE; - - return success; -} - -void -nm_ip4_config_merge_setting(NMIP4Config * self, - NMSettingIPConfig * setting, - NMSettingConnectionMdns mdns, - NMSettingConnectionLlmnr llmnr, - guint32 route_table, - guint32 route_metric) -{ - guint naddresses, nroutes, nnameservers, nsearches; - int i, priority; - const char *gateway_str; - guint32 gateway_bin; - - if (!setting) - return; - - g_return_if_fail(NM_IS_SETTING_IP4_CONFIG(setting)); - - g_object_freeze_notify(G_OBJECT(self)); - - naddresses = nm_setting_ip_config_get_num_addresses(setting); - nroutes = nm_setting_ip_config_get_num_routes(setting); - nnameservers = nm_setting_ip_config_get_num_dns(setting); - nsearches = nm_setting_ip_config_get_num_dns_searches(setting); - - /* Gateway */ - if (!nm_setting_ip_config_get_never_default(setting) - && (gateway_str = nm_setting_ip_config_get_gateway(setting)) - && inet_pton(AF_INET, gateway_str, &gateway_bin) == 1 && gateway_bin) { - const NMPlatformIP4Route r = { - .rt_source = NM_IP_CONFIG_SOURCE_USER, - .gateway = gateway_bin, - .table_coerced = nm_platform_route_table_coerce(route_table), - .metric = route_metric, - }; - - _add_route(self, NULL, &r, NULL); - } - - /* Addresses */ - for (i = 0; i < naddresses; i++) { - NMIPAddress * s_addr = nm_setting_ip_config_get_address(setting, i); - GVariant * label; - NMPlatformIP4Address address; - - memset(&address, 0, sizeof(address)); - nm_ip_address_get_address_binary(s_addr, &address.address); - address.peer_address = address.address; - address.plen = nm_ip_address_get_prefix(s_addr); - nm_assert(address.plen <= 32); - address.lifetime = NM_PLATFORM_LIFETIME_PERMANENT; - address.preferred = NM_PLATFORM_LIFETIME_PERMANENT; - address.addr_source = NM_IP_CONFIG_SOURCE_USER; - - label = nm_ip_address_get_attribute(s_addr, NM_IP_ADDRESS_ATTRIBUTE_LABEL); - if (label) - g_strlcpy(address.label, g_variant_get_string(label, NULL), sizeof(address.label)); - - _add_address(self, NULL, &address); - } - - /* Routes */ - for (i = 0; i < nroutes; i++) { - NMIPRoute * s_route = nm_setting_ip_config_get_route(setting, i); - NMPlatformIP4Route route; - gint64 m; - - if (nm_ip_route_get_family(s_route) != AF_INET) { - nm_assert_not_reached(); - continue; - } - - memset(&route, 0, sizeof(route)); - nm_ip_route_get_dest_binary(s_route, &route.network); - - route.plen = nm_ip_route_get_prefix(s_route); - nm_assert(route.plen <= 32); - - nm_ip_route_get_next_hop_binary(s_route, &route.gateway); - m = nm_ip_route_get_metric(s_route); - if (m < 0) - route.metric = route_metric; - else - route.metric = m; - route.rt_source = NM_IP_CONFIG_SOURCE_USER; - - route.network = nm_utils_ip4_address_clear_host_address(route.network, route.plen); - - nm_utils_ip_route_attribute_to_platform(AF_INET, - s_route, - NM_PLATFORM_IP_ROUTE_CAST(&route), - route_table); - _add_route(self, NULL, &route, NULL); - } - - /* DNS */ - if (nm_setting_ip_config_get_ignore_auto_dns(setting)) { - nm_ip4_config_reset_nameservers(self); - nm_ip4_config_reset_domains(self); - nm_ip4_config_reset_searches(self); - } - for (i = 0; i < nnameservers; i++) { - guint32 ip; - - if (inet_pton(AF_INET, nm_setting_ip_config_get_dns(setting, i), &ip) == 1) - nm_ip4_config_add_nameserver(self, ip); - } - for (i = 0; i < nsearches; i++) - nm_ip4_config_add_search(self, nm_setting_ip_config_get_dns_search(setting, i)); - - i = 0; - while ((i = nm_setting_ip_config_next_valid_dns_option(setting, i)) >= 0) { - nm_ip4_config_add_dns_option(self, nm_setting_ip_config_get_dns_option(setting, i)); - i++; - } - - priority = nm_setting_ip_config_get_dns_priority(setting); - if (priority) - nm_ip4_config_set_dns_priority(self, priority); - - nm_ip4_config_mdns_set(self, mdns); - nm_ip4_config_llmnr_set(self, llmnr); - - nm_ip4_config_set_never_default(self, nm_setting_ip_config_get_never_default(setting)); - - g_object_thaw_notify(G_OBJECT(self)); -} - -NMSetting * -nm_ip4_config_create_setting(const NMIP4Config *self) -{ - const NMIP4ConfigPrivate * priv; - NMSettingIPConfig * s_ip4; - guint nnameservers, nsearches, noptions; - const char * method = NULL; - int i; - NMDedupMultiIter ipconf_iter; - const NMPlatformIP4Address *address; - const NMPlatformIP4Route * route; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - s_ip4 = NM_SETTING_IP_CONFIG(nm_setting_ip4_config_new()); - - if (!self) { - g_object_set(s_ip4, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP4_CONFIG_METHOD_DISABLED, - NULL); - return NM_SETTING(s_ip4); - } - - priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - nnameservers = nm_ip4_config_get_num_nameservers(self); - nsearches = nm_ip4_config_get_num_searches(self); - noptions = nm_ip4_config_get_num_dns_options(self); - - /* Addresses */ - nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, self, &address) { - NMIPAddress *s_addr; - - /* Detect dynamic address */ - if (address->lifetime != NM_PLATFORM_LIFETIME_PERMANENT) { - method = NM_SETTING_IP4_CONFIG_METHOD_AUTO; - continue; - } - - /* Static address found. */ - if (!method) - method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL; - - s_addr = nm_ip_address_new_binary(AF_INET, &address->address, address->plen, NULL); - if (*address->label) - nm_ip_address_set_attribute(s_addr, - NM_IP_ADDRESS_ATTRIBUTE_LABEL, - g_variant_new_string(address->label)); - - nm_setting_ip_config_add_address(s_ip4, s_addr); - nm_ip_address_unref(s_addr); - } - - /* Gateway */ - if (priv->best_default_route && nm_setting_ip_config_get_num_addresses(s_ip4) > 0) { - g_object_set( - s_ip4, - NM_SETTING_IP_CONFIG_GATEWAY, - _nm_utils_inet4_ntop(NMP_OBJECT_CAST_IP4_ROUTE(priv->best_default_route)->gateway, - sbuf), - NULL); - } - - /* Use 'disabled' if the method wasn't previously set */ - if (!method) - method = NM_SETTING_IP4_CONFIG_METHOD_DISABLED; - - g_object_set(s_ip4, NM_SETTING_IP_CONFIG_METHOD, method, NULL); - - /* Routes */ - nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, self, &route) { - NMIPRoute *s_route; - - if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(route)) - continue; - - /* Ignore routes provided by external sources */ - if (route->rt_source - != nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER)) - continue; - - s_route = nm_ip_route_new_binary(AF_INET, - &route->network, - route->plen, - &route->gateway, - route->metric, - NULL); - nm_setting_ip_config_add_route(s_ip4, s_route); - nm_ip_route_unref(s_route); - } - - /* DNS */ - for (i = 0; i < nnameservers; i++) { - guint32 nameserver = nm_ip4_config_get_nameserver(self, i); - - nm_setting_ip_config_add_dns(s_ip4, _nm_utils_inet4_ntop(nameserver, sbuf)); - } - for (i = 0; i < nsearches; i++) { - const char *search = nm_ip4_config_get_search(self, i); - - nm_setting_ip_config_add_dns_search(s_ip4, search); - } - - for (i = 0; i < noptions; i++) { - const char *option = nm_ip4_config_get_dns_option(self, i); - - nm_setting_ip_config_add_dns_option(s_ip4, option); - } - - g_object_set(s_ip4, - NM_SETTING_IP_CONFIG_DNS_PRIORITY, - nm_ip4_config_get_dns_priority(self), - NULL); - - return NM_SETTING(s_ip4); -} - -/*****************************************************************************/ - -void -nm_ip4_config_merge(NMIP4Config * dst, - const NMIP4Config * src, - NMIPConfigMergeFlags merge_flags, - guint32 default_route_metric_penalty) -{ - NMIP4ConfigPrivate * dst_priv; - const NMIP4ConfigPrivate * src_priv; - guint32 i; - NMDedupMultiIter ipconf_iter; - const NMPlatformIP4Address *address = NULL; - - g_return_if_fail(src != NULL); - g_return_if_fail(dst != NULL); - - dst_priv = NM_IP4_CONFIG_GET_PRIVATE(dst); - src_priv = NM_IP4_CONFIG_GET_PRIVATE(src); - - g_object_freeze_notify(G_OBJECT(dst)); - - /* addresses */ - nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, src, &address) { - if (NM_FLAGS_HAS(merge_flags, NM_IP_CONFIG_MERGE_EXTERNAL) && !address->external) { - NMPlatformIP4Address a; - - a = *address; - a.external = TRUE; - _add_address(dst, NULL, &a); - } else - _add_address(dst, NMP_OBJECT_UP_CAST(address), NULL); - } - - /* nameservers */ - if (!NM_FLAGS_HAS(merge_flags, NM_IP_CONFIG_MERGE_NO_DNS)) { - for (i = 0; i < nm_ip4_config_get_num_nameservers(src); i++) - nm_ip4_config_add_nameserver(dst, nm_ip4_config_get_nameserver(src, i)); - } - - /* routes */ - if (!NM_FLAGS_HAS(merge_flags, NM_IP_CONFIG_MERGE_NO_ROUTES)) { - const NMPlatformIP4Route *r_src; - - nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, src, &r_src) { - if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(r_src)) { - if (NM_FLAGS_HAS(merge_flags, NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES) - && !NM_FLAGS_HAS(src_priv->config_flags, - NM_IP_CONFIG_FLAGS_IGNORE_MERGE_NO_DEFAULT_ROUTES)) - continue; - if (default_route_metric_penalty) { - NMPlatformIP4Route r = *r_src; - - r.metric = - nm_utils_ip_route_metric_penalize(r.metric, default_route_metric_penalty); - _add_route(dst, NULL, &r, NULL); - continue; - } - } - _add_route(dst, ipconf_iter.current->obj, NULL, NULL); - } - } - - /* domains */ - if (!NM_FLAGS_HAS(merge_flags, NM_IP_CONFIG_MERGE_NO_DNS)) { - for (i = 0; i < nm_ip4_config_get_num_domains(src); i++) - nm_ip4_config_add_domain(dst, nm_ip4_config_get_domain(src, i)); - } - - /* dns searches */ - if (!NM_FLAGS_HAS(merge_flags, NM_IP_CONFIG_MERGE_NO_DNS)) { - for (i = 0; i < nm_ip4_config_get_num_searches(src); i++) - nm_ip4_config_add_search(dst, nm_ip4_config_get_search(src, i)); - } - - /* dns options */ - if (!NM_FLAGS_HAS(merge_flags, NM_IP_CONFIG_MERGE_NO_DNS)) { - for (i = 0; i < nm_ip4_config_get_num_dns_options(src); i++) - nm_ip4_config_add_dns_option(dst, nm_ip4_config_get_dns_option(src, i)); - } - - /* MTU */ - if (src_priv->mtu_source > dst_priv->mtu_source - || (src_priv->mtu_source == dst_priv->mtu_source - && ((!dst_priv->mtu && src_priv->mtu) - || (dst_priv->mtu && src_priv->mtu < dst_priv->mtu)))) - nm_ip4_config_set_mtu(dst, src_priv->mtu, src_priv->mtu_source); - - /* NIS */ - if (!NM_FLAGS_HAS(merge_flags, NM_IP_CONFIG_MERGE_NO_DNS)) { - for (i = 0; i < nm_ip4_config_get_num_nis_servers(src); i++) - nm_ip4_config_add_nis_server(dst, nm_ip4_config_get_nis_server(src, i)); - - if (nm_ip4_config_get_nis_domain(src)) - nm_ip4_config_set_nis_domain(dst, nm_ip4_config_get_nis_domain(src)); - } - - /* WINS */ - if (!NM_FLAGS_HAS(merge_flags, NM_IP_CONFIG_MERGE_NO_DNS)) { - for (i = 0; i < nm_ip4_config_get_num_wins(src); i++) - nm_ip4_config_add_wins(dst, nm_ip4_config_get_wins(src, i)); - } - - /* metered flag */ - nm_ip4_config_set_metered(dst, - nm_ip4_config_get_metered(dst) || nm_ip4_config_get_metered(src)); - - /* never default */ - nm_ip4_config_set_never_default(dst, - nm_ip4_config_get_never_default(dst) - || nm_ip4_config_get_never_default(src)); - - /* DNS priority */ - if (nm_ip4_config_get_dns_priority(src)) - nm_ip4_config_set_dns_priority(dst, nm_ip4_config_get_dns_priority(src)); - - /* mdns */ - nm_ip4_config_mdns_set(dst, NM_MAX(nm_ip4_config_mdns_get(src), nm_ip4_config_mdns_get(dst))); - /* LLMNR */ - nm_ip4_config_llmnr_set(dst, - NM_MAX(nm_ip4_config_llmnr_get(src), nm_ip4_config_llmnr_get(dst))); - - g_object_thaw_notify(G_OBJECT(dst)); -} - -/*****************************************************************************/ - -static int -_nameservers_get_index(const NMIP4Config *self, guint32 ns) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - guint i; - - for (i = 0; i < priv->nameservers->len; i++) { - guint32 n = g_array_index(priv->nameservers, guint32, i); - - if (ns == n) - return (int) i; - } - return -1; -} - -static int -_domains_get_index(const NMIP4Config *self, const char *domain) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - guint i; - - for (i = 0; i < priv->domains->len; i++) { - const char *d = g_ptr_array_index(priv->domains, i); - - if (g_strcmp0(domain, d) == 0) - return (int) i; - } - return -1; -} - -static int -_searches_get_index(const NMIP4Config *self, const char *search) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - guint i; - - for (i = 0; i < priv->searches->len; i++) { - const char *s = g_ptr_array_index(priv->searches, i); - - if (g_strcmp0(search, s) == 0) - return (int) i; - } - return -1; -} - -static int -_dns_options_get_index(const NMIP4Config *self, const char *option) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - guint i; - - for (i = 0; i < priv->dns_options->len; i++) { - const char *s = g_ptr_array_index(priv->dns_options, i); - - if (g_strcmp0(option, s) == 0) - return (int) i; - } - return -1; -} - -static int -_nis_servers_get_index(const NMIP4Config *self, guint32 nis_server) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - guint i; - - for (i = 0; i < priv->nis->len; i++) { - guint32 n = g_array_index(priv->nis, guint32, i); - - if (n == nis_server) - return (int) i; - } - return -1; -} - -static int -_wins_get_index(const NMIP4Config *self, guint32 wins_server) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - guint i; - - for (i = 0; i < priv->wins->len; i++) { - guint32 n = g_array_index(priv->wins, guint32, i); - - if (n == wins_server) - return (int) i; - } - return -1; -} - -/*****************************************************************************/ - -/** - * nm_ip4_config_subtract: - * @dst: config from which to remove everything in @src - * @src: config to remove from @dst - * @default_route_metric_penalty: pretend that on source we applied - * a route penalty on the default-route. It means, for default routes - * we don't remove routes that match exactly, but those with a lower - * metric (with the penalty removed). - * - * Removes everything in @src from @dst. - */ -void -nm_ip4_config_subtract(NMIP4Config * dst, - const NMIP4Config *src, - guint32 default_route_metric_penalty) -{ - NMIP4ConfigPrivate * dst_priv; - guint i; - int idx; - const NMPlatformIP4Address *a; - const NMPlatformIP4Route * r; - NMDedupMultiIter ipconf_iter; - gboolean changed; - gboolean changed_default_route; - - g_return_if_fail(src != NULL); - g_return_if_fail(dst != NULL); - - dst_priv = NM_IP4_CONFIG_GET_PRIVATE(dst); - - g_object_freeze_notify(G_OBJECT(dst)); - - /* addresses */ - changed = FALSE; - nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, src, &a) { - if (nm_dedup_multi_index_remove_obj(dst_priv->multi_idx, - &dst_priv->idx_ip4_addresses, - NMP_OBJECT_UP_CAST(a), - NULL)) - changed = TRUE; - } - if (changed) - _notify_addresses(dst); - - /* nameservers */ - for (i = 0; i < nm_ip4_config_get_num_nameservers(src); i++) { - idx = _nameservers_get_index(dst, nm_ip4_config_get_nameserver(src, i)); - if (idx >= 0) - nm_ip4_config_del_nameserver(dst, idx); - } - - /* routes */ - changed = FALSE; - changed_default_route = FALSE; - nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, src, &r) { - const NMPObject * o_src = NMP_OBJECT_UP_CAST(r); - NMPObject o_lookup_copy; - const NMPObject * o_lookup; - nm_auto_nmpobj const NMPObject *obj_old = NULL; - - if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(r) && default_route_metric_penalty) { - NMPlatformIP4Route *rr; - - /* the default route was penalized when merging it to the combined ip-config. - * When subtracting the routes, we must re-do that process when comparing - * the routes. */ - o_lookup = nmp_object_stackinit_obj(&o_lookup_copy, o_src); - rr = NMP_OBJECT_CAST_IP4_ROUTE(&o_lookup_copy); - rr->metric = - nm_utils_ip_route_metric_penalize(rr->metric, default_route_metric_penalty); - } else - o_lookup = o_src; - - if (nm_dedup_multi_index_remove_obj(dst_priv->multi_idx, - &dst_priv->idx_ip4_routes, - o_lookup, - (gconstpointer *) &obj_old)) { - if (dst_priv->best_default_route == obj_old) { - nm_clear_nmp_object(&dst_priv->best_default_route); - changed_default_route = TRUE; - } - changed = TRUE; - } - } - if (changed_default_route) { - nmp_object_ref_set(&dst_priv->best_default_route, - _nm_ip4_config_best_default_route_find(dst)); - _notify(dst, PROP_GATEWAY); - } - if (changed) - _notify_routes(dst); - - /* domains */ - for (i = 0; i < nm_ip4_config_get_num_domains(src); i++) { - idx = _domains_get_index(dst, nm_ip4_config_get_domain(src, i)); - if (idx >= 0) - nm_ip4_config_del_domain(dst, idx); - } - - /* dns searches */ - for (i = 0; i < nm_ip4_config_get_num_searches(src); i++) { - idx = _searches_get_index(dst, nm_ip4_config_get_search(src, i)); - if (idx >= 0) - nm_ip4_config_del_search(dst, idx); - } - - /* dns options */ - for (i = 0; i < nm_ip4_config_get_num_dns_options(src); i++) { - idx = _dns_options_get_index(dst, nm_ip4_config_get_dns_option(src, i)); - if (idx >= 0) - nm_ip4_config_del_dns_option(dst, idx); - } - - /* MTU */ - if (nm_ip4_config_get_mtu(src) == nm_ip4_config_get_mtu(dst) - && nm_ip4_config_get_mtu_source(src) == nm_ip4_config_get_mtu_source(dst)) - nm_ip4_config_set_mtu(dst, 0, NM_IP_CONFIG_SOURCE_UNKNOWN); - - /* NIS */ - for (i = 0; i < nm_ip4_config_get_num_nis_servers(src); i++) { - idx = _nis_servers_get_index(dst, nm_ip4_config_get_nis_server(src, i)); - if (idx >= 0) - nm_ip4_config_del_nis_server(dst, idx); - } - - if (g_strcmp0(nm_ip4_config_get_nis_domain(src), nm_ip4_config_get_nis_domain(dst)) == 0) - nm_ip4_config_set_nis_domain(dst, NULL); - - /* WINS */ - for (i = 0; i < nm_ip4_config_get_num_wins(src); i++) { - idx = _wins_get_index(dst, nm_ip4_config_get_wins(src, i)); - if (idx >= 0) - nm_ip4_config_del_wins(dst, idx); - } - - /* DNS priority */ - if (nm_ip4_config_get_dns_priority(src) == nm_ip4_config_get_dns_priority(dst)) - nm_ip4_config_set_dns_priority(dst, 0); - - /* mdns */ - if (nm_ip4_config_mdns_get(src) == nm_ip4_config_mdns_get(dst)) - nm_ip4_config_mdns_set(dst, NM_SETTING_CONNECTION_MDNS_DEFAULT); - - /* LLMNR */ - if (nm_ip4_config_llmnr_get(src) == nm_ip4_config_llmnr_get(dst)) - nm_ip4_config_llmnr_set(dst, NM_SETTING_CONNECTION_LLMNR_DEFAULT); - - g_object_thaw_notify(G_OBJECT(dst)); -} - -static gboolean -_nm_ip4_config_intersect_helper(NMIP4Config * dst, - const NMIP4Config *src, - gboolean intersect_addresses, - gboolean intersect_routes, - guint32 default_route_metric_penalty, - gboolean update_dst) -{ - NMIP4ConfigPrivate * dst_priv; - const NMIP4ConfigPrivate * src_priv; - NMDedupMultiIter ipconf_iter; - const NMPlatformIP4Address *a; - const NMPlatformIP4Route * r; - const NMPObject * new_best_default_route; - gboolean changed, result = FALSE; - - g_return_val_if_fail(src, FALSE); - g_return_val_if_fail(dst, FALSE); - - dst_priv = NM_IP4_CONFIG_GET_PRIVATE(dst); - src_priv = NM_IP4_CONFIG_GET_PRIVATE(src); - - if (update_dst) - g_object_freeze_notify(G_OBJECT(dst)); - - /* addresses */ - if (intersect_addresses) { - changed = FALSE; - nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, dst, &a) { - if (nm_dedup_multi_index_lookup_obj(src_priv->multi_idx, - &src_priv->idx_ip4_addresses, - NMP_OBJECT_UP_CAST(a))) - continue; - - if (!update_dst) - return TRUE; - - if (nm_dedup_multi_index_remove_entry(dst_priv->multi_idx, ipconf_iter.current) != 1) - nm_assert_not_reached(); - changed = TRUE; - } - if (changed) { - _notify_addresses(dst); - result = TRUE; - } - } - - /* ignore nameservers */ - - /* routes */ - if (!intersect_routes) - goto skip_routes; - - changed = FALSE; - new_best_default_route = NULL; - nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, dst, &r) { - const NMPObject *o_dst = NMP_OBJECT_UP_CAST(r); - const NMPObject *o_lookup; - NMPObject o_lookup_copy; - - if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(r) && default_route_metric_penalty) { - NMPlatformIP4Route *rr; - - /* the default route was penalized when merging it to the combined ip-config. - * When intersecting the routes, we must re-do that process when comparing - * the routes. */ - o_lookup = nmp_object_stackinit_obj(&o_lookup_copy, o_dst); - rr = NMP_OBJECT_CAST_IP4_ROUTE(&o_lookup_copy); - rr->metric = - nm_utils_ip_route_metric_penalize(rr->metric, default_route_metric_penalty); - } else - o_lookup = o_dst; - - if (nm_dedup_multi_index_lookup_obj(src_priv->multi_idx, - &src_priv->idx_ip4_routes, - o_lookup)) { - new_best_default_route = - _nm_ip_config_best_default_route_find_better(new_best_default_route, o_dst); - continue; - } - - if (!update_dst) - return TRUE; - - if (nm_dedup_multi_index_remove_entry(dst_priv->multi_idx, ipconf_iter.current) != 1) - nm_assert_not_reached(); - changed = TRUE; - } - if (nmp_object_ref_set(&dst_priv->best_default_route, new_best_default_route)) { - nm_assert(changed); - _notify(dst, PROP_GATEWAY); - } - - if (changed) { - _notify_routes(dst); - result = TRUE; - } - -skip_routes: - /* ignore domains */ - /* ignore dns searches */ - /* ignore dns options */ - /* ignore NIS */ - /* ignore WINS */ - /* ignore mdns */ - /* ignore LLMNR */ - - if (update_dst) - g_object_thaw_notify(G_OBJECT(dst)); - return result; -} - -/** - * nm_ip4_config_intersect: - * @dst: a configuration to be updated - * @src: another configuration - * @intersect_addresses: whether addresses should be intersected - * @intersect_routes: whether routes should be intersected - * @default_route_metric_penalty: the default route metric penalty - * - * Computes the intersection between @src and @dst and updates @dst in place - * with the result. - */ -void -nm_ip4_config_intersect(NMIP4Config * dst, - const NMIP4Config *src, - gboolean intersect_addresses, - gboolean intersect_routes, - guint32 default_route_metric_penalty) -{ - _nm_ip4_config_intersect_helper(dst, - src, - intersect_addresses, - intersect_routes, - default_route_metric_penalty, - TRUE); -} - -/** - * nm_ip4_config_intersect_alloc: - * @a: a configuration - * @b: another configuration - * @intersect_addresses: whether addresses should be intersected - * @intersect_routes: whether routes should be intersected - * @default_route_metric_penalty: the default route metric penalty - * - * Computes the intersection between @a and @b and returns the result in a newly - * allocated configuration. As a special case, if @a and @b are identical (with - * respect to the only properties considered - addresses and routes) the - * functions returns NULL so that one of existing configuration can be reused - * without allocation. - * - * Returns: the intersection between @a and @b, or %NULL if the result is equal - * to @a and @b. - */ -NMIP4Config * -nm_ip4_config_intersect_alloc(const NMIP4Config *a, - const NMIP4Config *b, - gboolean intersect_addresses, - gboolean intersect_routes, - guint32 default_route_metric_penalty) -{ - NMIP4Config *a_copy; - - if (_nm_ip4_config_intersect_helper((NMIP4Config *) a, - b, - intersect_addresses, - intersect_routes, - default_route_metric_penalty, - FALSE)) { - a_copy = nm_ip4_config_clone(a); - _nm_ip4_config_intersect_helper(a_copy, - b, - intersect_addresses, - intersect_routes, - default_route_metric_penalty, - TRUE); - return a_copy; - } else - return NULL; -} - -/** - * nm_ip4_config_replace: - * @dst: config to replace with @src content - * @src: source config to copy - * @relevant_changes: return whether there are changes to the - * destination object that are relevant. This is equal to - * nm_ip4_config_equal() showing any difference. - * - * Replaces everything in @dst with @src so that the two configurations - * contain the same content -- with the exception of the dbus path. - * - * Returns: whether the @dst instance changed in any way (including minor changes, - * that are not signaled by the output parameter @relevant_changes). - */ -gboolean -nm_ip4_config_replace(NMIP4Config *dst, const NMIP4Config *src, gboolean *relevant_changes) -{ -#if NM_MORE_ASSERTS - gboolean config_equal; -#endif - gboolean has_minor_changes = FALSE, has_relevant_changes = FALSE, are_equal; - guint i, num; - NMIP4ConfigPrivate * dst_priv; - const NMIP4ConfigPrivate * src_priv; - NMDedupMultiIter ipconf_iter_src, ipconf_iter_dst; - const NMDedupMultiHeadEntry *head_entry_src; - const NMPObject * new_best_default_route; - - g_return_val_if_fail(src != NULL, FALSE); - g_return_val_if_fail(dst != NULL, FALSE); - g_return_val_if_fail(src != dst, FALSE); - -#if NM_MORE_ASSERTS - config_equal = nm_ip4_config_equal(dst, src); -#endif - - dst_priv = NM_IP4_CONFIG_GET_PRIVATE(dst); - src_priv = NM_IP4_CONFIG_GET_PRIVATE(src); - - g_object_freeze_notify(G_OBJECT(dst)); - - /* ifindex */ - if (src_priv->ifindex != dst_priv->ifindex) { - dst_priv->ifindex = src_priv->ifindex; - has_minor_changes = TRUE; - } - - /* addresses */ - head_entry_src = nm_ip4_config_lookup_addresses(src); - nm_dedup_multi_iter_init(&ipconf_iter_src, head_entry_src); - nm_ip_config_iter_ip4_address_init(&ipconf_iter_dst, dst); - are_equal = TRUE; - while (TRUE) { - gboolean has; - const NMPlatformIP4Address *r_src = NULL; - const NMPlatformIP4Address *r_dst = NULL; - - has = nm_platform_dedup_multi_iter_next_ip4_address(&ipconf_iter_src, &r_src); - if (has != nm_platform_dedup_multi_iter_next_ip4_address(&ipconf_iter_dst, &r_dst)) { - are_equal = FALSE; - has_relevant_changes = TRUE; - break; - } - if (!has) - break; - - if (nm_platform_ip4_address_cmp(r_src, r_dst) != 0) { - are_equal = FALSE; - if (r_src->address != r_dst->address || r_src->plen != r_dst->plen - || r_src->peer_address != r_dst->peer_address) { - has_relevant_changes = TRUE; - break; - } - } - } - if (!are_equal) { - has_minor_changes = TRUE; - nm_dedup_multi_index_dirty_set_idx(dst_priv->multi_idx, &dst_priv->idx_ip4_addresses); - nm_dedup_multi_iter_for_each (&ipconf_iter_src, head_entry_src) { - _nm_ip_config_add_obj(dst_priv->multi_idx, - &dst_priv->idx_ip4_addresses_, - dst_priv->ifindex, - ipconf_iter_src.current->obj, - NULL, - FALSE, - TRUE, - NULL, - NULL); - } - nm_dedup_multi_index_dirty_remove_idx(dst_priv->multi_idx, - &dst_priv->idx_ip4_addresses, - FALSE); - _notify_addresses(dst); - } - - /* routes */ - head_entry_src = nm_ip4_config_lookup_routes(src); - nm_dedup_multi_iter_init(&ipconf_iter_src, head_entry_src); - nm_ip_config_iter_ip4_route_init(&ipconf_iter_dst, dst); - are_equal = TRUE; - while (TRUE) { - gboolean has; - const NMPlatformIP4Route *r_src = NULL; - const NMPlatformIP4Route *r_dst = NULL; - - has = nm_platform_dedup_multi_iter_next_ip4_route(&ipconf_iter_src, &r_src); - if (has != nm_platform_dedup_multi_iter_next_ip4_route(&ipconf_iter_dst, &r_dst)) { - are_equal = FALSE; - has_relevant_changes = TRUE; - break; - } - if (!has) - break; - - if (nm_platform_ip4_route_cmp_full(r_src, r_dst) != 0) { - are_equal = FALSE; - if (r_src->plen != r_dst->plen - || !nm_utils_ip4_address_same_prefix(r_src->network, r_dst->network, r_src->plen) - || r_src->gateway != r_dst->gateway || r_src->metric != r_dst->metric) { - has_relevant_changes = TRUE; - break; - } - } - } - if (!are_equal) { - has_minor_changes = TRUE; - new_best_default_route = NULL; - nm_dedup_multi_index_dirty_set_idx(dst_priv->multi_idx, &dst_priv->idx_ip4_routes); - nm_dedup_multi_iter_for_each (&ipconf_iter_src, head_entry_src) { - const NMPObject *o = ipconf_iter_src.current->obj; - const NMPObject *obj_new; - - _nm_ip_config_add_obj(dst_priv->multi_idx, - &dst_priv->idx_ip4_routes_, - dst_priv->ifindex, - o, - NULL, - FALSE, - TRUE, - NULL, - &obj_new); - new_best_default_route = - _nm_ip_config_best_default_route_find_better(new_best_default_route, obj_new); - } - nm_dedup_multi_index_dirty_remove_idx(dst_priv->multi_idx, - &dst_priv->idx_ip4_routes, - FALSE); - if (nmp_object_ref_set(&dst_priv->best_default_route, new_best_default_route)) - _notify(dst, PROP_GATEWAY); - _notify_routes(dst); - } - - /* nameservers */ - num = nm_ip4_config_get_num_nameservers(src); - are_equal = num == nm_ip4_config_get_num_nameservers(dst); - if (are_equal) { - for (i = 0; i < num; i++) { - if (nm_ip4_config_get_nameserver(src, i) != nm_ip4_config_get_nameserver(dst, i)) { - are_equal = FALSE; - break; - } - } - } - if (!are_equal) { - nm_ip4_config_reset_nameservers(dst); - for (i = 0; i < num; i++) - nm_ip4_config_add_nameserver(dst, nm_ip4_config_get_nameserver(src, i)); - has_relevant_changes = TRUE; - } - - /* domains */ - num = nm_ip4_config_get_num_domains(src); - are_equal = num == nm_ip4_config_get_num_domains(dst); - if (are_equal) { - for (i = 0; i < num; i++) { - if (g_strcmp0(nm_ip4_config_get_domain(src, i), nm_ip4_config_get_domain(dst, i))) { - are_equal = FALSE; - break; - } - } - } - if (!are_equal) { - nm_ip4_config_reset_domains(dst); - for (i = 0; i < num; i++) - nm_ip4_config_add_domain(dst, nm_ip4_config_get_domain(src, i)); - has_relevant_changes = TRUE; - } - - /* dns searches */ - num = nm_ip4_config_get_num_searches(src); - are_equal = num == nm_ip4_config_get_num_searches(dst); - if (are_equal) { - for (i = 0; i < num; i++) { - if (g_strcmp0(nm_ip4_config_get_search(src, i), nm_ip4_config_get_search(dst, i))) { - are_equal = FALSE; - break; - } - } - } - if (!are_equal) { - nm_ip4_config_reset_searches(dst); - for (i = 0; i < num; i++) - nm_ip4_config_add_search(dst, nm_ip4_config_get_search(src, i)); - has_relevant_changes = TRUE; - } - - /* dns options */ - num = nm_ip4_config_get_num_dns_options(src); - are_equal = num == nm_ip4_config_get_num_dns_options(dst); - if (are_equal) { - for (i = 0; i < num; i++) { - if (g_strcmp0(nm_ip4_config_get_dns_option(src, i), - nm_ip4_config_get_dns_option(dst, i))) { - are_equal = FALSE; - break; - } - } - } - if (!are_equal) { - nm_ip4_config_reset_dns_options(dst); - for (i = 0; i < num; i++) - nm_ip4_config_add_dns_option(dst, nm_ip4_config_get_dns_option(src, i)); - has_relevant_changes = TRUE; - } - - if (src_priv->mdns != dst_priv->mdns) { - dst_priv->mdns = src_priv->mdns; - has_relevant_changes = TRUE; - } - - if (src_priv->llmnr != dst_priv->llmnr) { - dst_priv->llmnr = src_priv->llmnr; - has_relevant_changes = TRUE; - } - - /* DNS priority */ - if (src_priv->dns_priority != dst_priv->dns_priority) { - nm_ip4_config_set_dns_priority(dst, src_priv->dns_priority); - has_minor_changes = TRUE; - } - - /* nis */ - num = nm_ip4_config_get_num_nis_servers(src); - are_equal = num == nm_ip4_config_get_num_nis_servers(dst); - if (are_equal) { - for (i = 0; i < num; i++) { - if (nm_ip4_config_get_nis_server(src, i) != nm_ip4_config_get_nis_server(dst, i)) { - are_equal = FALSE; - break; - } - } - } - if (!are_equal) { - nm_ip4_config_reset_nis_servers(dst); - for (i = 0; i < num; i++) - nm_ip4_config_add_nis_server(dst, nm_ip4_config_get_nis_server(src, i)); - has_relevant_changes = TRUE; - } - - /* nis_domain */ - if (g_strcmp0(src_priv->nis_domain, dst_priv->nis_domain)) { - nm_ip4_config_set_nis_domain(dst, src_priv->nis_domain); - has_relevant_changes = TRUE; - } - - /* wins */ - num = nm_ip4_config_get_num_wins(src); - are_equal = num == nm_ip4_config_get_num_wins(dst); - if (are_equal) { - for (i = 0; i < num; i++) { - if (nm_ip4_config_get_wins(src, i) != nm_ip4_config_get_wins(dst, i)) { - are_equal = FALSE; - break; - } - } - } - if (!are_equal) { - nm_ip4_config_reset_wins(dst); - for (i = 0; i < num; i++) - nm_ip4_config_add_wins(dst, nm_ip4_config_get_wins(src, i)); - has_relevant_changes = TRUE; - } - - /* mtu */ - if (src_priv->mtu != dst_priv->mtu || src_priv->mtu_source != dst_priv->mtu_source) { - nm_ip4_config_set_mtu(dst, src_priv->mtu, src_priv->mtu_source); - has_minor_changes = TRUE; - } - - /* metered */ - if (src_priv->metered != dst_priv->metered) { - dst_priv->metered = src_priv->metered; - has_minor_changes = TRUE; - } - - /* never default */ - if (src_priv->never_default != dst_priv->never_default) { - dst_priv->never_default = src_priv->never_default; - has_minor_changes = TRUE; - } - -#if NM_MORE_ASSERTS - /* config_equal does not compare *all* the fields, therefore, we might have has_minor_changes - * regardless of config_equal. But config_equal must correspond to has_relevant_changes. */ - nm_assert(config_equal == !has_relevant_changes); -#endif - - g_object_thaw_notify(G_OBJECT(dst)); - - if (relevant_changes) - *relevant_changes = has_relevant_changes; - - return has_relevant_changes || has_minor_changes; -} - -void -nm_ip_config_dump(const NMIPConfig *self, const char *detail, NMLogLevel level, NMLogDomain domain) -{ - NMDedupMultiIter ipconf_iter; - const NMPlatformIP4Address *addr4; - const NMPlatformIP6Address *addr6; - const NMPlatformIP4Route * route4; - const NMPlatformIP6Route * route6; - const NMIP4Config * ip4; - const NMIP6Config * ip6; - int addr_family = AF_UNSPEC; - char addr_family_char = '?'; - const char * path; - gconstpointer ptr; - guint i; - - if (self) { - addr_family = nm_ip_config_get_addr_family(self); - addr_family_char = nm_utils_addr_family_to_char(addr_family); - } - - nm_log(level, domain, NULL, NULL, "---- NMIP%cConfig %p (%s)", addr_family_char, self, detail); - - if (!self) - return; - - path = nm_dbus_object_get_path(NM_DBUS_OBJECT(self)); - if (path) - nm_log(level, domain, NULL, NULL, " path : %s", path); - - if (addr_family == AF_INET) { - ip4 = NM_IP4_CONFIG(self); - nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ip4, &addr4) { - nm_log(level, - domain, - NULL, - NULL, - " address : %s", - nm_platform_ip4_address_to_string(addr4, NULL, 0)); - } - nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &route4) { - nm_log(level, - domain, - NULL, - NULL, - " route : %s", - nm_platform_ip4_route_to_string(route4, NULL, 0)); - } - } else { - ip6 = NM_IP6_CONFIG(self); - nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6, &addr6) { - nm_log(level, - domain, - NULL, - NULL, - " address : %s", - nm_platform_ip6_address_to_string(addr6, NULL, 0)); - } - nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route6) { - nm_log(level, - domain, - NULL, - NULL, - " route : %s", - nm_platform_ip6_route_to_string(route6, NULL, 0)); - } - } - - for (i = 0; i < nm_ip_config_get_num_nameservers(self); i++) { - char buf[NM_UTILS_INET_ADDRSTRLEN]; - - ptr = nm_ip_config_get_nameserver(self, i); - nm_log(level, - domain, - NULL, - NULL, - " dns : %s", - nm_utils_inet_ntop(addr_family, ptr, buf)); - } - - for (i = 0; i < nm_ip_config_get_num_domains(self); i++) - nm_log(level, domain, NULL, NULL, " domain : %s", nm_ip_config_get_domain(self, i)); - - for (i = 0; i < nm_ip_config_get_num_searches(self); i++) - nm_log(level, domain, NULL, NULL, " search : %s", nm_ip_config_get_search(self, i)); - - for (i = 0; i < nm_ip_config_get_num_dns_options(self); i++) - nm_log(level, domain, NULL, NULL, "dns-option: %s", nm_ip_config_get_dns_option(self, i)); - - nm_log(level, domain, NULL, NULL, " dns-prio : %d", nm_ip_config_get_dns_priority(self)); - - if (addr_family == AF_INET) { - ip4 = NM_IP4_CONFIG(self); - nm_log(level, - domain, - NULL, - NULL, - " mtu : %" G_GUINT32_FORMAT " (source: %d)", - nm_ip4_config_get_mtu(ip4), - (int) nm_ip4_config_get_mtu_source(ip4)); - nm_log(level, domain, NULL, NULL, " metered : %d", (int) nm_ip4_config_get_metered(ip4)); - } -} - -/*****************************************************************************/ - -void -nm_ip4_config_reset_addresses(NMIP4Config *self) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - if (nm_dedup_multi_index_remove_idx(priv->multi_idx, &priv->idx_ip4_addresses) > 0) - _notify_addresses(self); -} - -static void -_add_address(NMIP4Config *self, const NMPObject *obj_new, const NMPlatformIP4Address *new) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - if (_nm_ip_config_add_obj(priv->multi_idx, - &priv->idx_ip4_addresses_, - priv->ifindex, - obj_new, - (const NMPlatformObject *) new, - TRUE, - FALSE, - NULL, - NULL)) - _notify_addresses(self); -} - -/** - * nm_ip4_config_add_address: - * @self: the #NMIP4Config - * @new: the new address to add to @self - * - * Adds the new address to @self. If an address with the same basic properties - * (address, prefix) already exists in @self, it is overwritten with the - * lifetime and preferred of @new. The source is also overwritten by the source - * from @new if that source is higher priority. - */ -void -nm_ip4_config_add_address(NMIP4Config *self, const NMPlatformIP4Address *new) -{ - g_return_if_fail(self); - g_return_if_fail(new); - g_return_if_fail(new->plen <= 32); - g_return_if_fail(NM_IP4_CONFIG_GET_PRIVATE(self)->ifindex > 0); - - _add_address(self, NULL, new); -} - -void -_nmtst_ip4_config_del_address(NMIP4Config *self, guint i) -{ - const NMPlatformIP4Address *a; - - a = _nmtst_ip4_config_get_address(self, i); - if (!nm_ip4_config_nmpobj_remove(self, NMP_OBJECT_UP_CAST(a))) - g_assert_not_reached(); -} - -guint -nm_ip4_config_get_num_addresses(const NMIP4Config *self) -{ - const NMDedupMultiHeadEntry *head_entry; - - head_entry = nm_ip4_config_lookup_addresses(self); - return head_entry ? head_entry->len : 0; -} - -const NMPlatformIP4Address * -nm_ip4_config_get_first_address(const NMIP4Config *self) -{ - NMDedupMultiIter iter; - const NMPlatformIP4Address *a = NULL; - - nm_ip_config_iter_ip4_address_for_each (&iter, self, &a) - return a; - return NULL; -} - -const NMPlatformIP4Address * -_nmtst_ip4_config_get_address(const NMIP4Config *self, guint i) -{ - NMDedupMultiIter iter = {}; - const NMPlatformIP4Address *a = NULL; - guint j; - - j = 0; - nm_ip_config_iter_ip4_address_for_each (&iter, self, &a) { - if (i == j) - return a; - j++; - } - g_return_val_if_reached(NULL); -} - -gboolean -nm_ip4_config_address_exists(const NMIP4Config *self, const NMPlatformIP4Address *needle) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - NMPObject obj_stack; - - nmp_object_stackinit_id_ip4_address(&obj_stack, - priv->ifindex, - needle->address, - needle->plen, - needle->peer_address); - return !!nm_dedup_multi_index_lookup_obj(priv->multi_idx, &priv->idx_ip4_addresses, &obj_stack); -} - -/*****************************************************************************/ - -static const NMDedupMultiEntry * -_lookup_route(const NMIP4Config *self, const NMPObject *needle, NMPlatformIPRouteCmpType cmp_type) -{ - const NMIP4ConfigPrivate *priv; - - nm_assert(NM_IS_IP4_CONFIG(self)); - nm_assert(NMP_OBJECT_GET_TYPE(needle) == NMP_OBJECT_TYPE_IP4_ROUTE); - - priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - return _nm_ip_config_lookup_ip_route(priv->multi_idx, &priv->idx_ip4_routes_, needle, cmp_type); -} - -void -nm_ip4_config_reset_routes(NMIP4Config *self) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - if (nm_dedup_multi_index_remove_idx(priv->multi_idx, &priv->idx_ip4_routes) > 0) { - if (nm_clear_nmp_object(&priv->best_default_route)) - _notify(self, PROP_GATEWAY); - _notify_routes(self); - } -} - -static void -_add_route(NMIP4Config * self, - const NMPObject *obj_new, - const NMPlatformIP4Route *new, - const NMPObject **out_obj_new) -{ - NMIP4ConfigPrivate * priv = NM_IP4_CONFIG_GET_PRIVATE(self); - nm_auto_nmpobj const NMPObject *obj_old = NULL; - const NMPObject * obj_new_2; - - nm_assert((!new) != (!obj_new)); - nm_assert(!new || _route_valid(new)); - nm_assert(!obj_new || _route_valid(NMP_OBJECT_CAST_IP4_ROUTE(obj_new))); - - if (_nm_ip_config_add_obj(priv->multi_idx, - &priv->idx_ip4_routes_, - priv->ifindex, - obj_new, - (const NMPlatformObject *) new, - TRUE, - FALSE, - &obj_old, - &obj_new_2)) { - gboolean changed_default_route = FALSE; - - if (priv->best_default_route == obj_old && obj_old != obj_new_2) { - changed_default_route = TRUE; - nm_clear_nmp_object(&priv->best_default_route); - } - NM_SET_OUT(out_obj_new, nmp_object_ref(obj_new_2)); - if (_nm_ip_config_best_default_route_merge(&priv->best_default_route, obj_new_2)) - changed_default_route = TRUE; - - if (changed_default_route) - _notify(self, PROP_GATEWAY); - _notify_routes(self); - } else - NM_SET_OUT(out_obj_new, nmp_object_ref(obj_new_2)); -} - -/** - * nm_ip4_config_add_route: - * @self: the #NMIP4Config - * @new: the new route to add to @self - * @out_obj_new: (allow-none) (out): the added route object. Must be unrefed - * by caller. - * - * Adds the new route to @self. If a route with the same basic properties - * (network, prefix) already exists in @self, it is overwritten including the - * gateway and metric of @new. The source is also overwritten by the source - * from @new if that source is higher priority. - */ -void -nm_ip4_config_add_route(NMIP4Config *self, - const NMPlatformIP4Route *new, - const NMPObject **out_obj_new) -{ - g_return_if_fail(self); - g_return_if_fail(new); - g_return_if_fail(new->plen <= 32); - g_return_if_fail(NM_IP4_CONFIG_GET_PRIVATE(self)->ifindex > 0); - - _add_route(self, NULL, new, out_obj_new); -} - -void -_nmtst_ip4_config_del_route(NMIP4Config *self, guint i) -{ - const NMPlatformIP4Route *r; - - r = _nmtst_ip4_config_get_route(self, i); - if (!nm_ip4_config_nmpobj_remove(self, NMP_OBJECT_UP_CAST(r))) - g_assert_not_reached(); -} - -guint -nm_ip4_config_get_num_routes(const NMIP4Config *self) -{ - const NMDedupMultiHeadEntry *head_entry; - - head_entry = nm_ip4_config_lookup_routes(self); - nm_assert(!head_entry || head_entry->len == c_list_length(&head_entry->lst_entries_head)); - return head_entry ? head_entry->len : 0; -} - -const NMPlatformIP4Route * -_nmtst_ip4_config_get_route(const NMIP4Config *self, guint i) -{ - NMDedupMultiIter iter; - const NMPlatformIP4Route *r = NULL; - guint j; - - j = 0; - nm_ip_config_iter_ip4_route_for_each (&iter, self, &r) { - if (i == j) - return r; - j++; - } - g_return_val_if_reached(NULL); -} - -const NMPlatformIP4Route * -nm_ip4_config_get_direct_route_for_host(const NMIP4Config *self, - in_addr_t host, - guint32 route_table) -{ - const NMPlatformIP4Route *best_route = NULL; - const NMPlatformIP4Route *item; - NMDedupMultiIter ipconf_iter; - - g_return_val_if_fail(host, NULL); - - nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, self, &item) { - if (item->gateway != 0) - continue; - - if (best_route && best_route->plen > item->plen) - continue; - - if (nm_platform_route_table_uncoerce(item->table_coerced, TRUE) != route_table) - continue; - - if (nm_utils_ip4_address_clear_host_address(host, item->plen) - != nm_utils_ip4_address_clear_host_address(item->network, item->plen)) - continue; - - if (best_route && best_route->metric <= item->metric) - continue; - - best_route = item; - } - return best_route; -} - -/*****************************************************************************/ - -void -nm_ip4_config_reset_nameservers(NMIP4Config *self) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - if (priv->nameservers->len != 0) { - g_array_set_size(priv->nameservers, 0); - nm_gobject_notify_together(self, PROP_NAMESERVER_DATA, PROP_NAMESERVERS); - } -} - -void -nm_ip4_config_add_nameserver(NMIP4Config *self, guint32 new) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - int i; - - g_return_if_fail(new != 0); - - for (i = 0; i < priv->nameservers->len; i++) - if (new == g_array_index(priv->nameservers, guint32, i)) - return; - - g_array_append_val(priv->nameservers, new); - nm_gobject_notify_together(self, PROP_NAMESERVER_DATA, PROP_NAMESERVERS); -} - -void -nm_ip4_config_del_nameserver(NMIP4Config *self, guint i) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - g_return_if_fail(i < priv->nameservers->len); - - g_array_remove_index(priv->nameservers, i); - nm_gobject_notify_together(self, PROP_NAMESERVER_DATA, PROP_NAMESERVERS); -} - -guint -nm_ip4_config_get_num_nameservers(const NMIP4Config *self) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - return priv->nameservers->len; -} - -guint32 -nm_ip4_config_get_nameserver(const NMIP4Config *self, guint i) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - return g_array_index(priv->nameservers, guint32, i); -} - -const in_addr_t * -_nm_ip4_config_get_nameserver(const NMIP4Config *self, guint i) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - return &g_array_index(priv->nameservers, guint32, i); -} - -/*****************************************************************************/ - -gboolean -_nm_ip_config_check_and_add_domain(GPtrArray *array, const char *domain) -{ - char * copy = NULL; - size_t len; - - g_return_val_if_fail(domain, FALSE); - g_return_val_if_fail(domain[0] != '\0', FALSE); - - if (domain[0] == '.' || strstr(domain, "..")) - return FALSE; - - len = strlen(domain); - if (domain[len - 1] == '.') - domain = copy = g_strndup(domain, len - 1); - - if (nm_utils_strv_find_first((char **) array->pdata, array->len, domain) >= 0) { - g_free(copy); - return FALSE; - } - - g_ptr_array_add(array, copy ?: g_strdup(domain)); - return TRUE; -} - -void -nm_ip4_config_reset_domains(NMIP4Config *self) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - if (priv->domains->len != 0) { - g_ptr_array_set_size(priv->domains, 0); - _notify(self, PROP_DOMAINS); - } -} - -void -nm_ip4_config_add_domain(NMIP4Config *self, const char *domain) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - if (_nm_ip_config_check_and_add_domain(priv->domains, domain)) - _notify(self, PROP_DOMAINS); -} - -void -nm_ip4_config_del_domain(NMIP4Config *self, guint i) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - g_return_if_fail(i < priv->domains->len); - - g_ptr_array_remove_index(priv->domains, i); - _notify(self, PROP_DOMAINS); -} - -guint -nm_ip4_config_get_num_domains(const NMIP4Config *self) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - return priv->domains->len; -} - -const char * -nm_ip4_config_get_domain(const NMIP4Config *self, guint i) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - return g_ptr_array_index(priv->domains, i); -} - -/*****************************************************************************/ - -void -nm_ip4_config_reset_searches(NMIP4Config *self) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - if (priv->searches->len != 0) { - g_ptr_array_set_size(priv->searches, 0); - _notify(self, PROP_SEARCHES); - } -} - -void -nm_ip4_config_add_search(NMIP4Config *self, const char *search) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - if (_nm_ip_config_check_and_add_domain(priv->searches, search)) - _notify(self, PROP_SEARCHES); -} - -void -nm_ip4_config_del_search(NMIP4Config *self, guint i) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - g_return_if_fail(i < priv->searches->len); - - g_ptr_array_remove_index(priv->searches, i); - _notify(self, PROP_SEARCHES); -} - -guint -nm_ip4_config_get_num_searches(const NMIP4Config *self) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - return priv->searches->len; -} - -const char * -nm_ip4_config_get_search(const NMIP4Config *self, guint i) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - return g_ptr_array_index(priv->searches, i); -} - -/*****************************************************************************/ - -void -nm_ip4_config_reset_dns_options(NMIP4Config *self) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - if (priv->dns_options->len != 0) { - g_ptr_array_set_size(priv->dns_options, 0); - _notify(self, PROP_DNS_OPTIONS); - } -} - -void -nm_ip4_config_add_dns_option(NMIP4Config *self, const char *new) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - int i; - - g_return_if_fail(new != NULL); - g_return_if_fail(new[0] != '\0'); - - for (i = 0; i < priv->dns_options->len; i++) - if (!g_strcmp0(g_ptr_array_index(priv->dns_options, i), new)) - return; - - g_ptr_array_add(priv->dns_options, g_strdup(new)); - _notify(self, PROP_DNS_OPTIONS); -} - -void -nm_ip4_config_del_dns_option(NMIP4Config *self, guint i) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - g_return_if_fail(i < priv->dns_options->len); - - g_ptr_array_remove_index(priv->dns_options, i); - _notify(self, PROP_DNS_OPTIONS); -} - -guint -nm_ip4_config_get_num_dns_options(const NMIP4Config *self) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - return priv->dns_options->len; -} - -const char * -nm_ip4_config_get_dns_option(const NMIP4Config *self, guint i) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - return g_ptr_array_index(priv->dns_options, i); -} - -/*****************************************************************************/ - -NMSettingConnectionMdns -nm_ip4_config_mdns_get(const NMIP4Config *self) -{ - return NM_IP4_CONFIG_GET_PRIVATE(self)->mdns; -} - -void -nm_ip4_config_mdns_set(NMIP4Config *self, NMSettingConnectionMdns mdns) -{ - NM_IP4_CONFIG_GET_PRIVATE(self)->mdns = mdns; -} - -NMSettingConnectionLlmnr -nm_ip4_config_llmnr_get(const NMIP4Config *self) -{ - return NM_IP4_CONFIG_GET_PRIVATE(self)->llmnr; -} - -void -nm_ip4_config_llmnr_set(NMIP4Config *self, NMSettingConnectionLlmnr llmnr) -{ - NM_IP4_CONFIG_GET_PRIVATE(self)->llmnr = llmnr; -} - -/*****************************************************************************/ - -NMIPConfigFlags -nm_ip4_config_get_config_flags(const NMIP4Config *self) -{ - return NM_IP4_CONFIG_GET_PRIVATE(self)->config_flags; -} - -void -nm_ip4_config_set_config_flags(NMIP4Config *self, NMIPConfigFlags flags, NMIPConfigFlags mask) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - if (mask == 0) { - /* for convenience, accept 0 mask to set any flags. */ - mask = flags; - } - - nm_assert(!NM_FLAGS_ANY(flags, ~mask)); - priv->config_flags = (flags & mask) | (priv->config_flags & ~mask); -} - -/*****************************************************************************/ - -void -nm_ip4_config_set_dns_priority(NMIP4Config *self, int priority) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - if (priority != priv->dns_priority) { - priv->dns_priority = priority; - _notify(self, PROP_DNS_PRIORITY); - } -} - -int -nm_ip4_config_get_dns_priority(const NMIP4Config *self) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - return priv->dns_priority; -} - -/*****************************************************************************/ - -void -nm_ip4_config_reset_nis_servers(NMIP4Config *self) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - g_array_set_size(priv->nis, 0); -} - -void -nm_ip4_config_add_nis_server(NMIP4Config *self, guint32 nis) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - int i; - - for (i = 0; i < priv->nis->len; i++) - if (nis == g_array_index(priv->nis, guint32, i)) - return; - - g_array_append_val(priv->nis, nis); -} - -void -nm_ip4_config_del_nis_server(NMIP4Config *self, guint i) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - g_return_if_fail(i < priv->nis->len); - - g_array_remove_index(priv->nis, i); -} - -guint -nm_ip4_config_get_num_nis_servers(const NMIP4Config *self) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - return priv->nis->len; -} - -guint32 -nm_ip4_config_get_nis_server(const NMIP4Config *self, guint i) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - return g_array_index(priv->nis, guint32, i); -} - -void -nm_ip4_config_set_nis_domain(NMIP4Config *self, const char *domain) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - g_free(priv->nis_domain); - priv->nis_domain = g_strdup(domain); -} - -const char * -nm_ip4_config_get_nis_domain(const NMIP4Config *self) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - return priv->nis_domain; -} - -/*****************************************************************************/ - -void -nm_ip4_config_reset_wins(NMIP4Config *self) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - if (priv->wins->len != 0) { - g_array_set_size(priv->wins, 0); - nm_gobject_notify_together(self, PROP_WINS_SERVER_DATA, PROP_WINS_SERVERS); - } -} - -void -nm_ip4_config_add_wins(NMIP4Config *self, guint32 wins) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - int i; - - g_return_if_fail(wins != 0); - - for (i = 0; i < priv->wins->len; i++) - if (wins == g_array_index(priv->wins, guint32, i)) - return; - - g_array_append_val(priv->wins, wins); - nm_gobject_notify_together(self, PROP_WINS_SERVER_DATA, PROP_WINS_SERVERS); -} - -void -nm_ip4_config_del_wins(NMIP4Config *self, guint i) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - g_return_if_fail(i < priv->wins->len); - - g_array_remove_index(priv->wins, i); - nm_gobject_notify_together(self, PROP_WINS_SERVER_DATA, PROP_WINS_SERVERS); -} - -guint -nm_ip4_config_get_num_wins(const NMIP4Config *self) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - return priv->wins->len; -} - -guint32 -nm_ip4_config_get_wins(const NMIP4Config *self, guint i) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - return g_array_index(priv->wins, guint32, i); -} - -/*****************************************************************************/ - -void -nm_ip4_config_set_mtu(NMIP4Config *self, guint32 mtu, NMIPConfigSource source) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - if (!mtu) - source = NM_IP_CONFIG_SOURCE_UNKNOWN; - - priv->mtu = mtu; - priv->mtu_source = source; -} - -guint32 -nm_ip4_config_get_mtu(const NMIP4Config *self) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - return priv->mtu; -} - -NMIPConfigSource -nm_ip4_config_get_mtu_source(const NMIP4Config *self) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - return priv->mtu_source; -} - -/*****************************************************************************/ - -void -nm_ip4_config_set_metered(NMIP4Config *self, gboolean metered) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - priv->metered = metered; -} - -gboolean -nm_ip4_config_get_metered(const NMIP4Config *self) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - return priv->metered; -} - -/*****************************************************************************/ - -void -nm_ip4_config_set_never_default(NMIP4Config *self, gboolean never_default) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - priv->never_default = never_default; -} - -gboolean -nm_ip4_config_get_never_default(const NMIP4Config *self) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - return priv->never_default; -} - -/*****************************************************************************/ - -const NMPObject * -nm_ip4_config_nmpobj_lookup(const NMIP4Config *self, const NMPObject *needle) -{ - const NMIP4ConfigPrivate * priv; - const NMDedupMultiIdxType *idx_type; - - g_return_val_if_fail(NM_IS_IP4_CONFIG(self), NULL); - - priv = NM_IP4_CONFIG_GET_PRIVATE(self); - switch (NMP_OBJECT_GET_TYPE(needle)) { - case NMP_OBJECT_TYPE_IP4_ADDRESS: - idx_type = &priv->idx_ip4_addresses; - break; - case NMP_OBJECT_TYPE_IP4_ROUTE: - idx_type = &priv->idx_ip4_routes; - break; - default: - g_return_val_if_reached(NULL); - } - - return nm_dedup_multi_entry_get_obj( - nm_dedup_multi_index_lookup_obj(priv->multi_idx, idx_type, needle)); -} - -gboolean -nm_ip4_config_nmpobj_remove(NMIP4Config *self, const NMPObject *needle) -{ - NMIP4ConfigPrivate * priv; - NMDedupMultiIdxType *idx_type; - nm_auto_nmpobj const NMPObject *obj_old = NULL; - guint n; - - g_return_val_if_fail(NM_IS_IP4_CONFIG(self), FALSE); - - priv = NM_IP4_CONFIG_GET_PRIVATE(self); - switch (NMP_OBJECT_GET_TYPE(needle)) { - case NMP_OBJECT_TYPE_IP4_ADDRESS: - idx_type = &priv->idx_ip4_addresses; - break; - case NMP_OBJECT_TYPE_IP4_ROUTE: - idx_type = &priv->idx_ip4_routes; - break; - default: - g_return_val_if_reached(FALSE); - } - - n = nm_dedup_multi_index_remove_obj(priv->multi_idx, - idx_type, - needle, - (gconstpointer *) &obj_old); - if (n != 1) { - nm_assert(n == 0); - return FALSE; - } - - nm_assert(NMP_OBJECT_GET_TYPE(obj_old) == NMP_OBJECT_GET_TYPE(needle)); - - switch (NMP_OBJECT_GET_TYPE(obj_old)) { - case NMP_OBJECT_TYPE_IP4_ADDRESS: - _notify_addresses(self); - break; - case NMP_OBJECT_TYPE_IP4_ROUTE: - if (priv->best_default_route == obj_old) { - if (nmp_object_ref_set(&priv->best_default_route, - _nm_ip4_config_best_default_route_find(self))) - _notify(self, PROP_GATEWAY); - } - _notify_routes(self); - break; - default: - nm_assert_not_reached(); - } - return TRUE; -} - -/*****************************************************************************/ - -static void -hash_u32(GChecksum *sum, guint32 n) -{ - g_checksum_update(sum, (const guint8 *) &n, sizeof(n)); -} - -void -nm_ip4_config_hash(const NMIP4Config *self, GChecksum *sum, gboolean dns_only) -{ - guint i; - const char * s; - NMDedupMultiIter ipconf_iter; - const NMPlatformIP4Address *address; - const NMPlatformIP4Route * route; - int val; - - g_return_if_fail(self); - g_return_if_fail(sum); - - if (!dns_only) { - nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, self, &address) { - hash_u32(sum, address->address); - hash_u32(sum, address->plen); - hash_u32(sum, address->peer_address & _nm_utils_ip4_prefix_to_netmask(address->plen)); - } - - nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, self, &route) { - hash_u32(sum, route->network); - hash_u32(sum, route->plen); - hash_u32(sum, route->gateway); - hash_u32(sum, route->metric); - } - - for (i = 0; i < nm_ip4_config_get_num_nis_servers(self); i++) - hash_u32(sum, nm_ip4_config_get_nis_server(self, i)); - - s = nm_ip4_config_get_nis_domain(self); - if (s) - g_checksum_update(sum, (const guint8 *) s, strlen(s)); - } - - for (i = 0; i < nm_ip4_config_get_num_nameservers(self); i++) - hash_u32(sum, nm_ip4_config_get_nameserver(self, i)); - - for (i = 0; i < nm_ip4_config_get_num_wins(self); i++) - hash_u32(sum, nm_ip4_config_get_wins(self, i)); - - for (i = 0; i < nm_ip4_config_get_num_domains(self); i++) { - s = nm_ip4_config_get_domain(self, i); - g_checksum_update(sum, (const guint8 *) s, strlen(s)); - } - - for (i = 0; i < nm_ip4_config_get_num_searches(self); i++) { - s = nm_ip4_config_get_search(self, i); - g_checksum_update(sum, (const guint8 *) s, strlen(s)); - } - - for (i = 0; i < nm_ip4_config_get_num_dns_options(self); i++) { - s = nm_ip4_config_get_dns_option(self, i); - g_checksum_update(sum, (const guint8 *) s, strlen(s)); - } - - val = nm_ip4_config_mdns_get(self); - if (val != NM_SETTING_CONNECTION_MDNS_DEFAULT) - g_checksum_update(sum, (const guint8 *) &val, sizeof(val)); - - val = nm_ip4_config_llmnr_get(self); - if (val != NM_SETTING_CONNECTION_LLMNR_DEFAULT) - g_checksum_update(sum, (const guint8 *) &val, sizeof(val)); - - /* FIXME(ip-config-checksum): the DNS priority should be considered relevant - * and added into the checksum as well, but this can't be done right now - * because in the DNS manager we rely on the fact that an empty - * configuration (i.e. just created) has a zero checksum. This is needed to - * avoid rewriting resolv.conf when there is no change. - * - * The DNS priority initial value depends on the connection type (VPN or - * not), so it's a bit difficult to add it to checksum maintaining the - * assumption of checksum(empty)=0 - */ -} - -/** - * nm_ip4_config_equal: - * @a: first config to compare - * @b: second config to compare - * - * Compares two #NMIP4Configs for basic equality. This means that all - * attributes must exist in the same order in both configs (addresses, routes, - * domains, DNS servers, etc) but some attributes (address lifetimes, and address - * and route sources) are ignored. - * - * Returns: %TRUE if the configurations are basically equal to each other, - * %FALSE if not - */ -gboolean -nm_ip4_config_equal(const NMIP4Config *a, const NMIP4Config *b) -{ - nm_auto_free_checksum GChecksum *a_checksum = g_checksum_new(G_CHECKSUM_SHA1); - nm_auto_free_checksum GChecksum *b_checksum = g_checksum_new(G_CHECKSUM_SHA1); - guint8 a_data[NM_UTILS_CHECKSUM_LENGTH_SHA1]; - guint8 b_data[NM_UTILS_CHECKSUM_LENGTH_SHA1]; - - if (a) - nm_ip4_config_hash(a, a_checksum, FALSE); - if (b) - nm_ip4_config_hash(b, b_checksum, FALSE); - - nm_utils_checksum_get_digest(a_checksum, a_data); - nm_utils_checksum_get_digest(b_checksum, b_data); - return !memcmp(a_data, b_data, sizeof(a_data)); -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMIP4Config * self = NM_IP4_CONFIG(object); - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - char addr_str[NM_UTILS_INET_ADDRSTRLEN]; - GVariantBuilder builder_data; - guint i; - - switch (prop_id) { - case PROP_IFINDEX: - g_value_set_int(value, priv->ifindex); - break; - case PROP_ADDRESS_DATA: - case PROP_ADDRESSES: - nm_assert(!!priv->address_data_variant == !!priv->addresses_variant); - - if (!priv->address_data_variant) { - nm_utils_ip_addresses_to_dbus(AF_INET, - nm_ip4_config_lookup_addresses(self), - priv->best_default_route, - NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN, - &priv->address_data_variant, - &priv->addresses_variant); - g_variant_ref_sink(priv->address_data_variant); - g_variant_ref_sink(priv->addresses_variant); - } - - g_value_set_variant(value, - prop_id == PROP_ADDRESS_DATA ? priv->address_data_variant - : priv->addresses_variant); - break; - case PROP_ROUTE_DATA: - case PROP_ROUTES: - nm_assert(!!priv->route_data_variant == !!priv->routes_variant); - - if (!priv->route_data_variant) { - nm_utils_ip_routes_to_dbus(AF_INET, - nm_ip4_config_lookup_routes(self), - &priv->route_data_variant, - &priv->routes_variant); - g_variant_ref_sink(priv->route_data_variant); - g_variant_ref_sink(priv->routes_variant); - } - - g_value_set_variant(value, - prop_id == PROP_ROUTE_DATA ? priv->route_data_variant - : priv->routes_variant); - break; - case PROP_GATEWAY: - if (priv->best_default_route) { - g_value_take_string(value, - nm_utils_inet4_ntop_dup( - NMP_OBJECT_CAST_IP4_ROUTE(priv->best_default_route)->gateway)); - } else - g_value_set_string(value, NULL); - break; - case PROP_NAMESERVER_DATA: - g_variant_builder_init(&builder_data, G_VARIANT_TYPE("aa{sv}")); - - for (i = 0; i < priv->nameservers->len; i++) { - GVariantBuilder nested_builder; - - _nm_utils_inet4_ntop(g_array_index(priv->nameservers, in_addr_t, i), addr_str); - - g_variant_builder_init(&nested_builder, G_VARIANT_TYPE("a{sv}")); - g_variant_builder_add(&nested_builder, - "{sv}", - "address", - g_variant_new_string(addr_str)); - g_variant_builder_add(&builder_data, "a{sv}", &nested_builder); - } - - g_value_take_variant(value, g_variant_builder_end(&builder_data)); - break; - case PROP_NAMESERVERS: - 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); - break; - case PROP_SEARCHES: - nm_utils_g_value_set_strv(value, priv->searches); - break; - case PROP_DNS_OPTIONS: - nm_utils_g_value_set_strv(value, priv->dns_options); - break; - case PROP_DNS_PRIORITY: - g_value_set_int(value, priv->dns_priority); - break; - case PROP_WINS_SERVER_DATA: - g_variant_builder_init(&builder_data, G_VARIANT_TYPE("as")); - for (i = 0; i < priv->wins->len; i++) { - g_variant_builder_add( - &builder_data, - "s", - _nm_utils_inet4_ntop(g_array_index(priv->wins, in_addr_t, i), addr_str)); - } - g_value_take_variant(value, g_variant_builder_end(&builder_data)); - break; - case PROP_WINS_SERVERS: - 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); - break; - } -} - -static void -set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - NMIP4Config * self = NM_IP4_CONFIG(object); - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - switch (prop_id) { - case PROP_MULTI_IDX: - /* construct-only */ - priv->multi_idx = g_value_get_pointer(value); - if (!priv->multi_idx) - g_return_if_reached(); - nm_dedup_multi_index_ref(priv->multi_idx); - break; - case PROP_IFINDEX: - /* construct-only */ - priv->ifindex = g_value_get_int(value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_ip4_config_init(NMIP4Config *self) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - nm_ip_config_dedup_multi_idx_type_init((NMIPConfigDedupMultiIdxType *) &priv->idx_ip4_addresses, - NMP_OBJECT_TYPE_IP4_ADDRESS); - nm_ip_config_dedup_multi_idx_type_init((NMIPConfigDedupMultiIdxType *) &priv->idx_ip4_routes, - NMP_OBJECT_TYPE_IP4_ROUTE); - - priv->mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT; - priv->llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT; - priv->nameservers = g_array_new(FALSE, FALSE, sizeof(guint32)); - priv->domains = g_ptr_array_new_with_free_func(g_free); - priv->searches = g_ptr_array_new_with_free_func(g_free); - priv->dns_options = g_ptr_array_new_with_free_func(g_free); - priv->nis = g_array_new(FALSE, TRUE, sizeof(guint32)); - priv->wins = g_array_new(FALSE, TRUE, sizeof(guint32)); -} - -NMIP4Config * -nm_ip4_config_new(NMDedupMultiIndex *multi_idx, int ifindex) -{ - g_return_val_if_fail(ifindex >= -1, NULL); - return g_object_new(NM_TYPE_IP4_CONFIG, - NM_IP4_CONFIG_MULTI_IDX, - multi_idx, - NM_IP4_CONFIG_IFINDEX, - ifindex, - NULL); -} - -static void -finalize(GObject *object) -{ - NMIP4Config * self = NM_IP4_CONFIG(object); - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE(self); - - nm_clear_nmp_object(&priv->best_default_route); - - nm_dedup_multi_index_remove_idx(priv->multi_idx, &priv->idx_ip4_addresses); - nm_dedup_multi_index_remove_idx(priv->multi_idx, &priv->idx_ip4_routes); - - nm_clear_g_variant(&priv->address_data_variant); - nm_clear_g_variant(&priv->addresses_variant); - nm_clear_g_variant(&priv->route_data_variant); - nm_clear_g_variant(&priv->routes_variant); - - g_array_unref(priv->nameservers); - g_ptr_array_unref(priv->domains); - g_ptr_array_unref(priv->searches); - g_ptr_array_unref(priv->dns_options); - g_array_unref(priv->nis); - g_free(priv->nis_domain); - g_array_unref(priv->wins); - - G_OBJECT_CLASS(nm_ip4_config_parent_class)->finalize(object); - - nm_dedup_multi_index_unref(priv->multi_idx); -} - -static const NMDBusInterfaceInfoExtended interface_info_ip4_config = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_IP4_CONFIG, - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - 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("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("WinsServers", - "au", - NM_IP4_CONFIG_WINS_SERVERS), ), ), -}; - -static void -nm_ip4_config_class_init(NMIP4ConfigClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMIPConfigClass * ip_config_class = NM_IP_CONFIG_CLASS(klass); - - ip_config_class->is_ipv4 = TRUE; - ip_config_class->addr_family = AF_INET; - - dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED(NM_DBUS_PATH "/IP4Config"); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_ip4_config); - - object_class->get_property = get_property; - object_class->set_property = set_property; - object_class->finalize = finalize; - - obj_properties[PROP_MULTI_IDX] = - g_param_spec_pointer(NM_IP4_CONFIG_MULTI_IDX, - "", - "", - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_IFINDEX] = - g_param_spec_int(NM_IP4_CONFIG_IFINDEX, - "", - "", - -1, - G_MAXINT, - -1, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_ADDRESS_DATA] = - g_param_spec_variant(NM_IP4_CONFIG_ADDRESS_DATA, - "", - "", - G_VARIANT_TYPE("aa{sv}"), - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_ADDRESSES] = - g_param_spec_variant(NM_IP4_CONFIG_ADDRESSES, - "", - "", - G_VARIANT_TYPE("aau"), - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_ROUTE_DATA] = - g_param_spec_variant(NM_IP4_CONFIG_ROUTE_DATA, - "", - "", - G_VARIANT_TYPE("aa{sv}"), - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_ROUTES] = g_param_spec_variant(NM_IP4_CONFIG_ROUTES, - "", - "", - G_VARIANT_TYPE("aau"), - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_GATEWAY] = g_param_spec_string(NM_IP4_CONFIG_GATEWAY, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_NAMESERVER_DATA] = - g_param_spec_variant(NM_IP4_CONFIG_NAMESERVER_DATA, - "", - "", - G_VARIANT_TYPE("aa{sv}"), - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_NAMESERVERS] = - g_param_spec_variant(NM_IP4_CONFIG_NAMESERVERS, - "", - "", - G_VARIANT_TYPE("au"), - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_DOMAINS] = g_param_spec_boxed(NM_IP4_CONFIG_DOMAINS, - "", - "", - G_TYPE_STRV, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_SEARCHES] = g_param_spec_boxed(NM_IP4_CONFIG_SEARCHES, - "", - "", - G_TYPE_STRV, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_DNS_OPTIONS] = - g_param_spec_boxed(NM_IP4_CONFIG_DNS_OPTIONS, - "", - "", - G_TYPE_STRV, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_DNS_PRIORITY] = g_param_spec_int(NM_IP4_CONFIG_DNS_PRIORITY, - "", - "", - G_MININT32, - G_MAXINT32, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_WINS_SERVER_DATA] = - g_param_spec_variant(NM_IP4_CONFIG_WINS_SERVER_DATA, - "", - "", - G_VARIANT_TYPE("as"), - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_WINS_SERVERS] = - g_param_spec_variant(NM_IP4_CONFIG_WINS_SERVERS, - "", - "", - G_VARIANT_TYPE("au"), - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} diff --git a/src/core/nm-ip4-config.h b/src/core/nm-ip4-config.h deleted file mode 100644 index 7032a2385e..0000000000 --- a/src/core/nm-ip4-config.h +++ /dev/null @@ -1,667 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2008 - 2013 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_IP4_CONFIG_H__ -#define __NETWORKMANAGER_IP4_CONFIG_H__ - -#include "nm-setting-connection.h" - -#include "nm-setting-ip4-config.h" - -#include "libnm-glib-aux/nm-dedup-multi.h" -#include "libnm-platform/nmp-object.h" -#include "nm-ip-config.h" - -/*****************************************************************************/ - -typedef enum _NMIPConfigFlags { - NM_IP_CONFIG_FLAG_NONE = 0, - - /* if set, then the merge flag NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES gets - * ignored during merge. */ - NM_IP_CONFIG_FLAGS_IGNORE_MERGE_NO_DEFAULT_ROUTES = (1ull << 0), -} NMIPConfigFlags; - -typedef struct { - NMDedupMultiIdxType parent; - NMPObjectType obj_type; -} NMIPConfigDedupMultiIdxType; - -void nm_ip_config_dedup_multi_idx_type_init(NMIPConfigDedupMultiIdxType *idx_type, - NMPObjectType obj_type); - -/*****************************************************************************/ - -void nm_ip_config_iter_ip4_address_init(NMDedupMultiIter *iter, const NMIP4Config *self); -void nm_ip_config_iter_ip4_route_init(NMDedupMultiIter *iter, const NMIP4Config *self); - -#define nm_ip_config_iter_ip4_address_for_each(iter, self, address) \ - for (nm_ip_config_iter_ip4_address_init((iter), (self)); \ - nm_platform_dedup_multi_iter_next_ip4_address((iter), (address));) - -#define nm_ip_config_iter_ip4_route_for_each(iter, self, route) \ - for (nm_ip_config_iter_ip4_route_init((iter), (self)); \ - nm_platform_dedup_multi_iter_next_ip4_route((iter), (route));) - -/*****************************************************************************/ - -const NMPObject *_nm_ip_config_best_default_route_find_better(const NMPObject *obj_cur, - const NMPObject *obj_cmp); -gboolean _nm_ip_config_best_default_route_merge(const NMPObject **best_default_route, - const NMPObject * new_candidate); - -/*****************************************************************************/ - -gboolean _nm_ip_config_add_obj(NMDedupMultiIndex * multi_idx, - NMIPConfigDedupMultiIdxType *idx_type, - int ifindex, - const NMPObject * obj_new, - const NMPlatformObject * pl_new, - gboolean merge, - gboolean append_force, - const NMPObject ** out_obj_old, - const NMPObject ** out_obj_new); - -const NMDedupMultiEntry *_nm_ip_config_lookup_ip_route(const NMDedupMultiIndex * multi_idx, - const NMIPConfigDedupMultiIdxType *idx_type, - const NMPObject * needle, - NMPlatformIPRouteCmpType cmp_type); - -/*****************************************************************************/ - -#define NM_TYPE_IP4_CONFIG (nm_ip4_config_get_type()) -#define NM_IP4_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_IP4_CONFIG, NMIP4Config)) -#define NM_IP4_CONFIG_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_IP4_CONFIG, NMIP4ConfigClass)) -#define NM_IS_IP4_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_IP4_CONFIG)) -#define NM_IS_IP4_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_IP4_CONFIG)) -#define NM_IP4_CONFIG_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_IP4_CONFIG, NMIP4ConfigClass)) - -typedef struct _NMIP4ConfigClass NMIP4ConfigClass; - -/* internal */ -#define NM_IP4_CONFIG_MULTI_IDX "multi-idx" -#define NM_IP4_CONFIG_IFINDEX "ifindex" - -/* public*/ -#define NM_IP4_CONFIG_ADDRESS_DATA "address-data" -#define NM_IP4_CONFIG_ROUTE_DATA "route-data" -#define NM_IP4_CONFIG_GATEWAY "gateway" -#define NM_IP4_CONFIG_NAMESERVER_DATA "nameserver-data" -#define NM_IP4_CONFIG_DOMAINS "domains" -#define NM_IP4_CONFIG_SEARCHES "searches" -#define NM_IP4_CONFIG_DNS_OPTIONS "dns-options" -#define NM_IP4_CONFIG_DNS_PRIORITY "dns-priority" -#define NM_IP4_CONFIG_WINS_SERVER_DATA "wins-server-data" - -/* deprecated */ -#define NM_IP4_CONFIG_ADDRESSES "addresses" -#define NM_IP4_CONFIG_ROUTES "routes" -#define NM_IP4_CONFIG_NAMESERVERS "nameservers" -#define NM_IP4_CONFIG_WINS_SERVERS "wins-servers" - -GType nm_ip4_config_get_type(void); - -NMIP4Config *nm_ip4_config_new(NMDedupMultiIndex *multi_idx, int ifindex); - -NMIP4Config *nm_ip4_config_clone(const NMIP4Config *self); -int nm_ip4_config_get_ifindex(const NMIP4Config *self); - -NMDedupMultiIndex *nm_ip4_config_get_multi_idx(const NMIP4Config *self); - -NMIP4Config *nm_ip4_config_capture(NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex); - -void nm_ip4_config_add_dependent_routes(NMIP4Config *self, - guint32 route_table, - guint32 route_metric, - gboolean is_vrf, - GPtrArray ** out_ip4_dev_route_blacklist); - -gboolean nm_ip4_config_commit(const NMIP4Config * self, - NMPlatform * platform, - NMIPRouteTableSyncMode route_table_sync); - -void nm_ip4_config_merge_setting(NMIP4Config * self, - NMSettingIPConfig * setting, - NMSettingConnectionMdns mdns, - NMSettingConnectionLlmnr llmnr, - guint32 route_table, - guint32 route_metric); -NMSetting *nm_ip4_config_create_setting(const NMIP4Config *self); - -void nm_ip4_config_merge(NMIP4Config * dst, - const NMIP4Config * src, - NMIPConfigMergeFlags merge_flags, - guint32 default_route_metric_penalty); -void nm_ip4_config_subtract(NMIP4Config * dst, - const NMIP4Config *src, - guint32 default_route_metric_penalty); -void nm_ip4_config_intersect(NMIP4Config * dst, - const NMIP4Config *src, - gboolean intersect_addresses, - gboolean intersect_routes, - guint32 default_route_metric_penalty); -NMIP4Config *nm_ip4_config_intersect_alloc(const NMIP4Config *a, - const NMIP4Config *b, - gboolean intersect_addresses, - gboolean intersect_routes, - guint32 default_route_metric_penalty); -gboolean -nm_ip4_config_replace(NMIP4Config *dst, const NMIP4Config *src, gboolean *relevant_changes); - -const NMPObject *nm_ip4_config_best_default_route_get(const NMIP4Config *self); -const NMPObject *_nm_ip4_config_best_default_route_find(const NMIP4Config *self); - -in_addr_t nmtst_ip4_config_get_gateway(NMIP4Config *config); - -NMSettingConnectionMdns nm_ip4_config_mdns_get(const NMIP4Config *self); -void nm_ip4_config_mdns_set(NMIP4Config *self, NMSettingConnectionMdns mdns); -NMSettingConnectionLlmnr nm_ip4_config_llmnr_get(const NMIP4Config *self); -void nm_ip4_config_llmnr_set(NMIP4Config *self, NMSettingConnectionLlmnr llmnr); - -void nm_ip4_config_set_config_flags(NMIP4Config *self, NMIPConfigFlags flags, NMIPConfigFlags mask); -NMIPConfigFlags nm_ip4_config_get_config_flags(const NMIP4Config *self); - -const NMDedupMultiHeadEntry *nm_ip4_config_lookup_addresses(const NMIP4Config *self); -void nm_ip4_config_reset_addresses(NMIP4Config *self); -void nm_ip4_config_add_address(NMIP4Config *self, const NMPlatformIP4Address *address); -void _nmtst_ip4_config_del_address(NMIP4Config *self, guint i); -guint nm_ip4_config_get_num_addresses(const NMIP4Config *self); -const NMPlatformIP4Address *nm_ip4_config_get_first_address(const NMIP4Config *self); -const NMPlatformIP4Address *_nmtst_ip4_config_get_address(const NMIP4Config *self, guint i); -gboolean nm_ip4_config_address_exists(const NMIP4Config *self, const NMPlatformIP4Address *address); - -const NMDedupMultiHeadEntry *nm_ip4_config_lookup_routes(const NMIP4Config *self); -void nm_ip4_config_reset_routes(NMIP4Config *self); -void nm_ip4_config_add_route(NMIP4Config * self, - const NMPlatformIP4Route *route, - const NMPObject ** out_obj_new); -void _nmtst_ip4_config_del_route(NMIP4Config *self, guint i); -guint nm_ip4_config_get_num_routes(const NMIP4Config *self); -const NMPlatformIP4Route * _nmtst_ip4_config_get_route(const NMIP4Config *self, guint i); - -const NMPlatformIP4Route *nm_ip4_config_get_direct_route_for_host(const NMIP4Config *self, - in_addr_t host, - guint32 route_table); -void nm_ip4_config_update_routes_metric(NMIP4Config *self, gint64 metric); - -void nm_ip4_config_reset_nameservers(NMIP4Config *self); -void nm_ip4_config_add_nameserver(NMIP4Config *self, guint32 nameserver); - -static inline void -_nm_ip4_config_add_nameserver(NMIP4Config *self, const guint32 *nameserver) -{ - nm_ip4_config_add_nameserver(self, *nameserver); -} - -void nm_ip4_config_del_nameserver(NMIP4Config *self, guint i); -guint nm_ip4_config_get_num_nameservers(const NMIP4Config *self); -guint32 nm_ip4_config_get_nameserver(const NMIP4Config *self, guint i); -const in_addr_t *_nm_ip4_config_get_nameserver(const NMIP4Config *self, guint i); - -void nm_ip4_config_reset_domains(NMIP4Config *self); -void nm_ip4_config_add_domain(NMIP4Config *self, const char *domain); -void nm_ip4_config_del_domain(NMIP4Config *self, guint i); -guint nm_ip4_config_get_num_domains(const NMIP4Config *self); -const char *nm_ip4_config_get_domain(const NMIP4Config *self, guint i); - -void nm_ip4_config_reset_searches(NMIP4Config *self); -void nm_ip4_config_add_search(NMIP4Config *self, const char *search); -void nm_ip4_config_del_search(NMIP4Config *self, guint i); -guint nm_ip4_config_get_num_searches(const NMIP4Config *self); -const char *nm_ip4_config_get_search(const NMIP4Config *self, guint i); - -void nm_ip4_config_reset_dns_options(NMIP4Config *self); -void nm_ip4_config_add_dns_option(NMIP4Config *self, const char *option); -void nm_ip4_config_del_dns_option(NMIP4Config *self, guint i); -guint nm_ip4_config_get_num_dns_options(const NMIP4Config *self); -const char *nm_ip4_config_get_dns_option(const NMIP4Config *self, guint i); - -void nm_ip4_config_set_dns_priority(NMIP4Config *self, int priority); -int nm_ip4_config_get_dns_priority(const NMIP4Config *self); - -void nm_ip4_config_reset_nis_servers(NMIP4Config *self); -void nm_ip4_config_add_nis_server(NMIP4Config *self, guint32 nis); -void nm_ip4_config_del_nis_server(NMIP4Config *self, guint i); -guint nm_ip4_config_get_num_nis_servers(const NMIP4Config *self); -guint32 nm_ip4_config_get_nis_server(const NMIP4Config *self, guint i); -void nm_ip4_config_set_nis_domain(NMIP4Config *self, const char *domain); -const char *nm_ip4_config_get_nis_domain(const NMIP4Config *self); - -void nm_ip4_config_reset_wins(NMIP4Config *self); -void nm_ip4_config_add_wins(NMIP4Config *self, guint32 wins); -void nm_ip4_config_del_wins(NMIP4Config *self, guint i); -guint nm_ip4_config_get_num_wins(const NMIP4Config *self); -guint32 nm_ip4_config_get_wins(const NMIP4Config *self, guint i); - -void nm_ip4_config_set_mtu(NMIP4Config *self, guint32 mtu, NMIPConfigSource source); -guint32 nm_ip4_config_get_mtu(const NMIP4Config *self); -NMIPConfigSource nm_ip4_config_get_mtu_source(const NMIP4Config *self); - -void nm_ip4_config_set_metered(NMIP4Config *self, gboolean metered); -gboolean nm_ip4_config_get_metered(const NMIP4Config *self); - -void nm_ip4_config_set_never_default(NMIP4Config *self, gboolean never_default); -gboolean nm_ip4_config_get_never_default(const NMIP4Config *self); - -const NMPObject *nm_ip4_config_nmpobj_lookup(const NMIP4Config *self, const NMPObject *needle); -gboolean nm_ip4_config_nmpobj_remove(NMIP4Config *self, const NMPObject *needle); - -void nm_ip4_config_hash(const NMIP4Config *self, GChecksum *sum, gboolean dns_only); -gboolean nm_ip4_config_equal(const NMIP4Config *a, const NMIP4Config *b); - -gboolean _nm_ip_config_check_and_add_domain(GPtrArray *array, const char *domain); - -void -nm_ip_config_dump(const NMIPConfig *self, const char *detail, NMLogLevel level, NMLogDomain domain); - -/*****************************************************************************/ - -#include "nm-ip6-config.h" - -static inline gboolean -NM_IS_IP_CONFIG_ADDR_FAMILY(gconstpointer config, int addr_family) -{ - if (addr_family == AF_UNSPEC) - return NM_IS_IP4_CONFIG(config) || NM_IS_IP6_CONFIG(config); - if (addr_family == AF_INET) - return NM_IS_IP4_CONFIG(config); - if (addr_family == AF_INET6) - return NM_IS_IP6_CONFIG(config); - g_return_val_if_reached(FALSE); -} - -#if _NM_CC_SUPPORT_GENERIC - /* _NM_IS_IP_CONFIG() is a bit unusual. If _Generic() is supported, - * it checks whether @config is either NM_IS_IP4_CONFIG() or NM_IS_IP6_CONFIG(), - * depending on the pointer type of @config. - * - * For example, with _Generic() support, the following assertions would fail: - * NMIP6Config *ptr = (NMIP6Config *) nm_ip4_config_new(...); - * g_assert (_NM_IS_IP_CONFIG (ptr, ptr)); - * but the following would pass: - * NMIP4Config *ptr = nm_ip4_config_new(...); - * g_assert (_NM_IS_IP_CONFIG (ptr, ptr)); - */ - #define _NM_IS_IP_CONFIG(typeexpr, config) \ - ({ \ - const void *const _config = (config); \ - _Generic ((typeexpr), \ - const void *const: (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ - const void * : (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ - void *const: (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ - void * : (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ - const NMIPConfig *const: (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ - const NMIPConfig * : (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ - NMIPConfig *const: (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ - NMIPConfig * : (NM_IS_IP4_CONFIG (_config) || NM_IS_IP6_CONFIG (_config)), \ - const NMIP4Config *const: (NM_IS_IP4_CONFIG (_config)), \ - const NMIP4Config * : (NM_IS_IP4_CONFIG (_config)), \ - NMIP4Config *const: (NM_IS_IP4_CONFIG (_config)), \ - NMIP4Config * : (NM_IS_IP4_CONFIG (_config)), \ - const NMIP6Config *const: (NM_IS_IP6_CONFIG (_config)), \ - const NMIP6Config * : (NM_IS_IP6_CONFIG (_config)), \ - NMIP6Config *const: (NM_IS_IP6_CONFIG (_config)), \ - NMIP6Config * : (NM_IS_IP6_CONFIG (_config))); \ - }) -#else - #define _NM_IS_IP_CONFIG(typeexpr, config) NM_IS_IP_CONFIG(config) -#endif - -#define NM_IP_CONFIG_CAST(config) \ - ({ \ - const void *const _configx = (config); \ - \ - nm_assert(!_configx || _NM_IS_IP_CONFIG((config), _configx)); \ - NM_CONSTCAST_FULL(NMIPConfig, (config), _configx, NMIP4Config, NMIP6Config); \ - }) - -static inline gboolean -nm_ip_config_is_ipv4(const NMIPConfig *config) -{ - if (NM_IP_CONFIG_GET_CLASS(config)->is_ipv4) { - nm_assert(NM_IS_IP4_CONFIG(config)); - return TRUE; - } - nm_assert(NM_IS_IP6_CONFIG(config)); - return FALSE; -} - -static inline int -nm_ip_config_get_addr_family(const NMIPConfig *config) -{ - return nm_ip_config_is_ipv4(config) ? AF_INET : AF_INET6; -} - -#define _NM_IP_CONFIG_DISPATCH(config, v4_func, v6_func, ...) \ - G_STMT_START \ - { \ - gconstpointer _config = (config); \ - \ - if (nm_ip_config_is_ipv4(_config)) { \ - return v4_func((NMIP4Config *) _config, ##__VA_ARGS__); \ - } else { \ - return v6_func((NMIP6Config *) _config, ##__VA_ARGS__); \ - } \ - } \ - G_STMT_END - -#define _NM_IP_CONFIG_DISPATCH_VOID(config, v4_func, v6_func, ...) \ - G_STMT_START \ - { \ - gconstpointer _config = (config); \ - \ - if (nm_ip_config_is_ipv4(_config)) { \ - v4_func((NMIP4Config *) _config, ##__VA_ARGS__); \ - } else { \ - v6_func((NMIP6Config *) _config, ##__VA_ARGS__); \ - } \ - } \ - G_STMT_END - -static inline int -nm_ip_config_get_ifindex(const NMIPConfig *self) -{ - _NM_IP_CONFIG_DISPATCH(self, nm_ip4_config_get_ifindex, nm_ip6_config_get_ifindex); -} - -static inline void -nm_ip_config_hash(const NMIPConfig *self, GChecksum *sum, gboolean dns_only) -{ - _NM_IP_CONFIG_DISPATCH_VOID(self, nm_ip4_config_hash, nm_ip6_config_hash, sum, dns_only); -} - -static inline gconstpointer -nm_ip_config_get_first_address(NMIPConfig *self) -{ - _NM_IP_CONFIG_DISPATCH(self, nm_ip4_config_get_first_address, nm_ip6_config_get_first_address); -} - -static inline void -nm_ip_config_iter_ip_address_init(NMDedupMultiIter *iter, const NMIPConfig *self) -{ - if (nm_ip_config_is_ipv4(self)) - nm_ip_config_iter_ip4_address_init(iter, (const NMIP4Config *) self); - else - nm_ip_config_iter_ip6_address_init(iter, (const NMIP6Config *) self); -} - -#define nm_ip_config_iter_ip_address_for_each(iter, self, address) \ - for (nm_ip_config_iter_ip_address_init((iter), (self)); \ - nm_platform_dedup_multi_iter_next_ip_address((iter), (address));) - -static inline void -nm_ip_config_iter_ip_route_init(NMDedupMultiIter *iter, const NMIPConfig *self) -{ - if (nm_ip_config_is_ipv4(self)) - nm_ip_config_iter_ip4_route_init(iter, (const NMIP4Config *) self); - else - nm_ip_config_iter_ip6_route_init(iter, (const NMIP6Config *) self); -} - -#define nm_ip_config_iter_ip_route_for_each(iter, self, route) \ - for (nm_ip_config_iter_ip_route_init((iter), (self)); \ - nm_platform_dedup_multi_iter_next_ip_route((iter), (route));) - -static inline void -nm_ip_config_add_address(NMIPConfig *self, const NMPlatformIPAddress *address) -{ - _NM_IP_CONFIG_DISPATCH_VOID(self, - nm_ip4_config_add_address, - nm_ip6_config_add_address, - (gconstpointer) address); -} - -static inline void -nm_ip_config_reset_addresses(NMIPConfig *self) -{ - _NM_IP_CONFIG_DISPATCH_VOID(self, nm_ip4_config_reset_addresses, nm_ip6_config_reset_addresses); -} - -static inline void -nm_ip_config_add_route(NMIPConfig *self, - const NMPlatformIPRoute *new, - const NMPObject **out_obj_new) -{ - _NM_IP_CONFIG_DISPATCH_VOID(self, - nm_ip4_config_add_route, - nm_ip6_config_add_route, - (gpointer) new, - out_obj_new); -} - -static inline void -nm_ip_config_reset_routes(NMIPConfig *self) -{ - _NM_IP_CONFIG_DISPATCH_VOID(self, nm_ip4_config_reset_routes, nm_ip6_config_reset_routes); -} - -static inline int -nm_ip_config_get_dns_priority(const NMIPConfig *self) -{ - _NM_IP_CONFIG_DISPATCH(self, nm_ip4_config_get_dns_priority, nm_ip6_config_get_dns_priority); -} - -static inline void -nm_ip_config_set_dns_priority(NMIPConfig *self, int priority) -{ - _NM_IP_CONFIG_DISPATCH_VOID(self, - nm_ip4_config_set_dns_priority, - nm_ip6_config_set_dns_priority, - priority); -} - -static inline void -nm_ip_config_add_nameserver(NMIPConfig *self, const NMIPAddr *ns) -{ - _NM_IP_CONFIG_DISPATCH_VOID(self, - _nm_ip4_config_add_nameserver, - nm_ip6_config_add_nameserver, - (gconstpointer) ns); -} - -static inline void -nm_ip_config_reset_nameservers(const NMIPConfig *self) -{ - _NM_IP_CONFIG_DISPATCH_VOID(self, - nm_ip4_config_reset_nameservers, - nm_ip6_config_reset_nameservers); -} - -static inline guint -nm_ip_config_get_num_nameservers(const NMIPConfig *self) -{ - _NM_IP_CONFIG_DISPATCH(self, - nm_ip4_config_get_num_nameservers, - nm_ip6_config_get_num_nameservers); -} - -static inline gconstpointer -nm_ip_config_get_nameserver(const NMIPConfig *self, guint i) -{ - _NM_IP_CONFIG_DISPATCH(self, _nm_ip4_config_get_nameserver, nm_ip6_config_get_nameserver, i); -} - -static inline guint -nm_ip_config_get_num_domains(const NMIPConfig *self) -{ - _NM_IP_CONFIG_DISPATCH(self, nm_ip4_config_get_num_domains, nm_ip6_config_get_num_domains); -} - -static inline const char * -nm_ip_config_get_domain(const NMIPConfig *self, guint i) -{ - _NM_IP_CONFIG_DISPATCH(self, nm_ip4_config_get_domain, nm_ip6_config_get_domain, i); -} - -static inline void -nm_ip_config_reset_searches(const NMIPConfig *self) -{ - _NM_IP_CONFIG_DISPATCH_VOID(self, nm_ip4_config_reset_searches, nm_ip6_config_reset_searches); -} - -static inline void -nm_ip_config_add_search(const NMIPConfig *self, const char *new) -{ - _NM_IP_CONFIG_DISPATCH_VOID(self, nm_ip4_config_add_search, nm_ip6_config_add_search, new); -} - -static inline guint -nm_ip_config_get_num_searches(const NMIPConfig *self) -{ - _NM_IP_CONFIG_DISPATCH(self, nm_ip4_config_get_num_searches, nm_ip6_config_get_num_searches); -} - -static inline const char * -nm_ip_config_get_search(const NMIPConfig *self, guint i) -{ - _NM_IP_CONFIG_DISPATCH(self, nm_ip4_config_get_search, nm_ip6_config_get_search, i); -} - -static inline guint -nm_ip_config_get_num_dns_options(const NMIPConfig *self) -{ - _NM_IP_CONFIG_DISPATCH(self, - nm_ip4_config_get_num_dns_options, - nm_ip6_config_get_num_dns_options); -} - -static inline const char * -nm_ip_config_get_dns_option(const NMIPConfig *self, guint i) -{ - _NM_IP_CONFIG_DISPATCH(self, nm_ip4_config_get_dns_option, nm_ip6_config_get_dns_option, i); -} - -static inline const NMPObject * -nm_ip_config_best_default_route_get(const NMIPConfig *self) -{ - _NM_IP_CONFIG_DISPATCH(self, - nm_ip4_config_best_default_route_get, - nm_ip6_config_best_default_route_get); -} - -static inline NMIPConfigFlags -nm_ip_config_get_config_flags(const NMIPConfig *self) -{ - _NM_IP_CONFIG_DISPATCH(self, nm_ip4_config_get_config_flags, nm_ip6_config_get_config_flags); -} - -static inline void -nm_ip_config_set_config_flags(NMIPConfig *self, NMIPConfigFlags flags, NMIPConfigFlags mask) -{ - _NM_IP_CONFIG_DISPATCH_VOID(self, - nm_ip4_config_set_config_flags, - nm_ip6_config_set_config_flags, - flags, - mask); -} - -static inline gboolean -nm_ip_config_get_never_default(const NMIPConfig *self) -{ - _NM_IP_CONFIG_DISPATCH(self, nm_ip4_config_get_never_default, nm_ip6_config_get_never_default); -} - -static inline void -nm_ip_config_set_never_default(NMIPConfig *self, gboolean never_default) -{ - _NM_IP_CONFIG_DISPATCH_VOID(self, - nm_ip4_config_set_never_default, - nm_ip6_config_set_never_default, - never_default); -} - -#define _NM_IP_CONFIG_DISPATCH_SET_OP(_return, dst, src, v4_func, v6_func, ...) \ - G_STMT_START \ - { \ - gpointer _dst = (dst); \ - gconstpointer _src = (src); \ - \ - if (nm_ip_config_is_ipv4(_dst)) { \ - _return v4_func((NMIP4Config *) _dst, (const NMIP4Config *) _src, ##__VA_ARGS__); \ - } else { \ - _return v6_func((NMIP6Config *) _dst, (const NMIP6Config *) _src, ##__VA_ARGS__); \ - } \ - } \ - G_STMT_END - -static inline void -nm_ip_config_intersect(NMIPConfig * dst, - const NMIPConfig *src, - gboolean intersect_addresses, - gboolean intersect_routes, - guint32 default_route_metric_penalty) -{ - _NM_IP_CONFIG_DISPATCH_SET_OP(, - dst, - src, - nm_ip4_config_intersect, - nm_ip6_config_intersect, - intersect_addresses, - intersect_routes, - default_route_metric_penalty); -} - -static inline void -nm_ip_config_subtract(NMIPConfig *dst, const NMIPConfig *src, guint32 default_route_metric_penalty) -{ - _NM_IP_CONFIG_DISPATCH_SET_OP(, - dst, - src, - nm_ip4_config_subtract, - nm_ip6_config_subtract, - default_route_metric_penalty); -} - -static inline void -nm_ip_config_merge(NMIPConfig * dst, - const NMIPConfig * src, - NMIPConfigMergeFlags merge_flags, - guint32 default_route_metric_penalty) -{ - _NM_IP_CONFIG_DISPATCH_SET_OP(, - dst, - src, - nm_ip4_config_merge, - nm_ip6_config_merge, - merge_flags, - default_route_metric_penalty); -} - -static inline gboolean -nm_ip_config_replace(NMIPConfig *dst, const NMIPConfig *src, gboolean *relevant_changes) -{ - _NM_IP_CONFIG_DISPATCH_SET_OP( - return, dst, src, nm_ip4_config_replace, nm_ip6_config_replace, relevant_changes); -} - -static inline NMIPConfig * -nm_ip_config_intersect_alloc(const NMIPConfig *a, - const NMIPConfig *b, - gboolean intersect_addresses, - gboolean intersect_routes, - guint32 default_route_metric_penalty) -{ - if (nm_ip_config_is_ipv4(a)) { - nm_assert(NM_IS_IP4_CONFIG(a)); - nm_assert(NM_IS_IP4_CONFIG(b)); - return (NMIPConfig *) nm_ip4_config_intersect_alloc((const NMIP4Config *) a, - (const NMIP4Config *) b, - intersect_addresses, - intersect_routes, - default_route_metric_penalty); - } else { - nm_assert(NM_IS_IP6_CONFIG(a)); - nm_assert(NM_IS_IP6_CONFIG(b)); - return (NMIPConfig *) nm_ip6_config_intersect_alloc((const NMIP6Config *) a, - (const NMIP6Config *) b, - intersect_addresses, - intersect_routes, - default_route_metric_penalty); - } -} - -#endif /* __NETWORKMANAGER_IP4_CONFIG_H__ */ diff --git a/src/core/nm-ip6-config.c b/src/core/nm-ip6-config.c deleted file mode 100644 index 8793c1c27a..0000000000 --- a/src/core/nm-ip6-config.c +++ /dev/null @@ -1,2711 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2005 - 2017 Red Hat, Inc. - * Copyright (C) 2006 - 2008 Novell, Inc. - */ - -#include "src/core/nm-default-daemon.h" - -#include "nm-ip6-config.h" - -#include -#include -#include -#include - -#include "libnm-glib-aux/nm-dedup-multi.h" - -#include "nm-utils.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" -#include "nm-dbus-object.h" - -/*****************************************************************************/ - -static gboolean -_route_valid(const NMPlatformIP6Route *r) -{ - struct in6_addr n; - - return r && r->plen <= 128 - && (memcmp(&r->network, - nm_utils_ip6_address_clear_host_address(&n, &r->network, r->plen), - sizeof(n)) - == 0); -} - -/*****************************************************************************/ - -typedef struct { - int ifindex; - int dns_priority; - NMSettingIP6ConfigPrivacy privacy; - GArray * nameservers; - GPtrArray * domains; - GPtrArray * searches; - GPtrArray * dns_options; - GVariant * address_data_variant; - GVariant * addresses_variant; - GVariant * route_data_variant; - GVariant * routes_variant; - NMDedupMultiIndex * multi_idx; - const NMPObject * best_default_route; - union { - NMIPConfigDedupMultiIdxType idx_ip6_addresses_; - NMDedupMultiIdxType idx_ip6_addresses; - }; - union { - NMIPConfigDedupMultiIdxType idx_ip6_routes_; - NMDedupMultiIdxType idx_ip6_routes; - }; - NMIPConfigFlags config_flags; - bool never_default : 1; -} NMIP6ConfigPrivate; - -struct _NMIP6Config { - NMIPConfig parent; - NMIP6ConfigPrivate _priv; -}; - -struct _NMIP6ConfigClass { - NMIPConfigClass parent; -}; - -G_DEFINE_TYPE(NMIP6Config, nm_ip6_config, NM_TYPE_IP_CONFIG) - -#define NM_IP6_CONFIG_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMIP6Config, NM_IS_IP6_CONFIG) - -NM_GOBJECT_PROPERTIES_DEFINE(NMIP6Config, - PROP_MULTI_IDX, - PROP_IFINDEX, - PROP_ADDRESS_DATA, - PROP_ADDRESSES, - PROP_ROUTE_DATA, - PROP_ROUTES, - PROP_GATEWAY, - PROP_NAMESERVERS, - PROP_DOMAINS, - PROP_SEARCHES, - PROP_DNS_OPTIONS, - PROP_DNS_PRIORITY, ); - -/*****************************************************************************/ - -static void -_add_address(NMIP6Config *self, const NMPObject *obj_new, const NMPlatformIP6Address *new); -static void _add_route(NMIP6Config * self, - const NMPObject *obj_new, - const NMPlatformIP6Route *new, - const NMPObject **out_obj_new); -static const NMDedupMultiEntry * -_lookup_route(const NMIP6Config *self, const NMPObject *needle, NMPlatformIPRouteCmpType cmp_type); - -/*****************************************************************************/ - -int -nm_ip6_config_get_ifindex(const NMIP6Config *self) -{ - return NM_IP6_CONFIG_GET_PRIVATE(self)->ifindex; -} - -NMDedupMultiIndex * -nm_ip6_config_get_multi_idx(const NMIP6Config *self) -{ - return NM_IP6_CONFIG_GET_PRIVATE(self)->multi_idx; -} - -void -nm_ip6_config_set_privacy(NMIP6Config *self, NMSettingIP6ConfigPrivacy privacy) -{ - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - priv->privacy = privacy; -} - -/*****************************************************************************/ - -void -nm_ip6_config_set_never_default(NMIP6Config *self, gboolean never_default) -{ - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - priv->never_default = never_default; -} - -gboolean -nm_ip6_config_get_never_default(const NMIP6Config *self) -{ - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - return priv->never_default; -} - -/*****************************************************************************/ - -const NMDedupMultiHeadEntry * -nm_ip6_config_lookup_addresses(const NMIP6Config *self) -{ - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - return nm_dedup_multi_index_lookup_head(priv->multi_idx, &priv->idx_ip6_addresses, NULL); -} - -void -nm_ip_config_iter_ip6_address_init(NMDedupMultiIter *ipconf_iter, const NMIP6Config *self) -{ - nm_assert(NM_IS_IP6_CONFIG(self)); - - nm_dedup_multi_iter_init(ipconf_iter, nm_ip6_config_lookup_addresses(self)); -} - -/*****************************************************************************/ - -const NMDedupMultiHeadEntry * -nm_ip6_config_lookup_routes(const NMIP6Config *self) -{ - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - return nm_dedup_multi_index_lookup_head(priv->multi_idx, &priv->idx_ip6_routes, NULL); -} - -void -nm_ip_config_iter_ip6_route_init(NMDedupMultiIter *ipconf_iter, const NMIP6Config *self) -{ - nm_assert(NM_IS_IP6_CONFIG(self)); - - nm_dedup_multi_iter_init(ipconf_iter, nm_ip6_config_lookup_routes(self)); -} - -/*****************************************************************************/ - -const NMPObject * -nm_ip6_config_best_default_route_get(const NMIP6Config *self) -{ - g_return_val_if_fail(NM_IS_IP6_CONFIG(self), NULL); - - return NM_IP6_CONFIG_GET_PRIVATE(self)->best_default_route; -} - -const NMPObject * -_nm_ip6_config_best_default_route_find(const NMIP6Config *self) -{ - NMDedupMultiIter ipconf_iter; - const NMPObject *new_best_default_route = NULL; - - nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, self, NULL) { - new_best_default_route = - _nm_ip_config_best_default_route_find_better(new_best_default_route, - ipconf_iter.current->obj); - } - return new_best_default_route; -} - -/*****************************************************************************/ - -static void -_notify_addresses(NMIP6Config *self) -{ - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - nm_clear_g_variant(&priv->address_data_variant); - nm_clear_g_variant(&priv->addresses_variant); - nm_gobject_notify_together(self, PROP_ADDRESS_DATA, PROP_ADDRESSES); -} - -static void -_notify_routes(NMIP6Config *self) -{ - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - nm_assert(priv->best_default_route == _nm_ip6_config_best_default_route_find(self)); - nm_clear_g_variant(&priv->route_data_variant); - nm_clear_g_variant(&priv->routes_variant); - nm_gobject_notify_together(self, PROP_ROUTE_DATA, PROP_ROUTES); -} - -/*****************************************************************************/ - -static int -sort_captured_addresses(const CList *lst_a, const CList *lst_b, gconstpointer user_data) -{ - return nm_platform_ip6_address_pretty_sort_cmp( - NMP_OBJECT_CAST_IP6_ADDRESS(c_list_entry(lst_a, NMDedupMultiEntry, lst_entries)->obj), - NMP_OBJECT_CAST_IP6_ADDRESS(c_list_entry(lst_b, NMDedupMultiEntry, lst_entries)->obj), - (((NMSettingIP6ConfigPrivacy) GPOINTER_TO_INT(user_data)) - == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR)); -} - -gboolean -_nmtst_ip6_config_addresses_sort(NMIP6Config *self) -{ - NMIP6ConfigPrivate * priv; - const NMDedupMultiHeadEntry *head_entry; - - g_return_val_if_fail(NM_IS_IP6_CONFIG(self), FALSE); - - head_entry = nm_ip6_config_lookup_addresses(self); - if (head_entry && head_entry->len > 1) { - gboolean changed; - gs_free gconstpointer *addresses_old = NULL; - guint naddr, j; - NMDedupMultiIter iter; - - priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - addresses_old = nm_dedup_multi_objs_to_array_head(head_entry, NULL, NULL, &naddr); - nm_assert(addresses_old); - nm_assert(naddr > 0 && naddr == head_entry->len); - - nm_dedup_multi_head_entry_sort(head_entry, - sort_captured_addresses, - GINT_TO_POINTER(priv->privacy)); - - changed = FALSE; - j = 0; - nm_dedup_multi_iter_for_each (&iter, head_entry) { - nm_assert(j < naddr); - if (iter.current->obj != addresses_old[j++]) - changed = TRUE; - } - nm_assert(j == naddr); - - if (changed) { - _notify_addresses(self); - return TRUE; - } - } - return FALSE; -} - -NMIP6Config * -nm_ip6_config_clone(const NMIP6Config *self) -{ - NMIP6Config *copy; - - copy = nm_ip6_config_new(nm_ip6_config_get_multi_idx(self), -1); - nm_ip6_config_replace(copy, self, NULL); - - return copy; -} - -NMIP6Config * -nm_ip6_config_capture(NMDedupMultiIndex * multi_idx, - NMPlatform * platform, - int ifindex, - NMSettingIP6ConfigPrivacy use_temporary) -{ - NMIP6Config * self; - NMIP6ConfigPrivate * priv; - const NMDedupMultiHeadEntry *head_entry; - NMDedupMultiIter iter; - const NMPObject * plobj = NULL; - - nm_assert(ifindex > 0); - - /* Slaves have no IP configuration */ - if (nm_platform_link_get_master(platform, ifindex) > 0) - return NULL; - - self = nm_ip6_config_new(multi_idx, ifindex); - priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - head_entry = nm_platform_lookup_object(platform, NMP_OBJECT_TYPE_IP6_ADDRESS, ifindex); - if (head_entry) { - nmp_cache_iter_for_each (&iter, head_entry, &plobj) { - if (!_nm_ip_config_add_obj(priv->multi_idx, - &priv->idx_ip6_addresses_, - ifindex, - plobj, - NULL, - FALSE, - TRUE, - NULL, - NULL)) - nm_assert_not_reached(); - } - head_entry = nm_ip6_config_lookup_addresses(self); - nm_assert(head_entry); - nm_dedup_multi_head_entry_sort(head_entry, - sort_captured_addresses, - GINT_TO_POINTER(use_temporary)); - _notify_addresses(self); - } - - head_entry = nm_platform_lookup_object(platform, NMP_OBJECT_TYPE_IP6_ROUTE, ifindex); - - nmp_cache_iter_for_each (&iter, head_entry, &plobj) - _add_route(self, plobj, NULL, NULL); - - return self; -} - -void -nm_ip6_config_update_routes_metric(NMIP6Config *self, gint64 metric) -{ - gs_free NMPlatformIP6Route *routes = NULL; - gboolean need_update = FALSE; - const NMPlatformIP6Route * r; - NMDedupMultiIter iter; - guint num = 0, i = 0; - - nm_ip_config_iter_ip6_route_for_each (&iter, self, &r) { - if (r->metric != metric) - need_update = TRUE; - num++; - } - if (!need_update) - return; - - routes = g_new(NMPlatformIP6Route, num); - nm_ip_config_iter_ip6_route_for_each (&iter, self, &r) { - routes[i] = *r; - routes[i].metric = metric; - i++; - } - - g_object_freeze_notify(G_OBJECT(self)); - nm_ip6_config_reset_routes(self); - for (i = 0; i < num; i++) - nm_ip6_config_add_route(self, &routes[i], NULL); - g_object_thaw_notify(G_OBJECT(self)); -} - -void -nm_ip6_config_add_dependent_routes(NMIP6Config *self, - guint32 route_table, - guint32 route_metric, - gboolean is_vrf) -{ - const NMPlatformIP6Address *my_addr; - const NMPlatformIP6Route * my_route; - int ifindex; - NMDedupMultiIter iter; - - g_return_if_fail(NM_IS_IP6_CONFIG(self)); - - ifindex = nm_ip6_config_get_ifindex(self); - g_return_if_fail(ifindex > 0); - - /* For IPv6 addresses received via SLAAC/autoconf, we explicitly add the - * device-routes (onlink) to NMIP6Config. - * - * For manually added IPv6 routes, add the device routes explicitly. */ - - nm_ip_config_iter_ip6_address_for_each (&iter, self, &my_addr) { - NMPlatformIP6Route *route; - gboolean has_peer; - int routes_n, routes_i; - - if (my_addr->external) - continue; - - if (NM_FLAGS_HAS(my_addr->n_ifa_flags, IFA_F_NOPREFIXROUTE)) - continue; - if (my_addr->plen == 0) - continue; - - has_peer = !IN6_IS_ADDR_UNSPECIFIED(&my_addr->peer_address); - - /* If we have an IPv6 peer, we add two /128 routes - * (unless, both addresses are identical). */ - routes_n = - (has_peer && !IN6_ARE_ADDR_EQUAL(&my_addr->address, &my_addr->peer_address)) ? 2 : 1; - - for (routes_i = 0; routes_i < routes_n; routes_i++) { - nm_auto_nmpobj NMPObject *r = NULL; - - r = nmp_object_new(NMP_OBJECT_TYPE_IP6_ROUTE, NULL); - route = NMP_OBJECT_CAST_IP6_ROUTE(r); - - route->ifindex = ifindex; - route->rt_source = NM_IP_CONFIG_SOURCE_KERNEL; - route->table_coerced = nm_platform_route_table_coerce(route_table); - route->metric = route_metric; - - if (has_peer) { - if (routes_i == 0) - route->network = my_addr->address; - else - route->network = my_addr->peer_address; - route->plen = 128; - } else { - nm_utils_ip6_address_clear_host_address(&route->network, - &my_addr->address, - my_addr->plen); - route->plen = my_addr->plen; - } - - nm_platform_ip_route_normalize(AF_INET6, (NMPlatformIPRoute *) route); - - if (_lookup_route(self, r, NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID)) { - /* we already track this route. Don't add it again. */ - } else - _add_route(self, r, NULL, NULL); - } - } - -again: - nm_ip_config_iter_ip6_route_for_each (&iter, self, &my_route) { - NMPlatformIP6Route rt; - - if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT(my_route) - || IN6_IS_ADDR_UNSPECIFIED(&my_route->gateway) - || NM_IS_IP_CONFIG_SOURCE_RTPROT(my_route->rt_source) - || nm_ip6_config_get_direct_route_for_host( - self, - &my_route->gateway, - nm_platform_route_table_uncoerce(my_route->table_coerced, TRUE))) - continue; - - rt = *my_route; - rt.network = my_route->gateway; - rt.plen = 128; - rt.gateway = in6addr_any; - _add_route(self, NULL, &rt, NULL); - /* adding the route might have invalidated the iteration. Start again. */ - goto again; - } -} - -gboolean -nm_ip6_config_commit(const NMIP6Config * self, - NMPlatform * platform, - NMIPRouteTableSyncMode route_table_sync, - GPtrArray ** out_temporary_not_available) -{ - gs_unref_ptrarray GPtrArray *addresses = NULL; - gs_unref_ptrarray GPtrArray *routes = NULL; - gs_unref_ptrarray GPtrArray *routes_prune = NULL; - int ifindex; - gboolean success = TRUE; - - g_return_val_if_fail(NM_IS_IP6_CONFIG(self), FALSE); - - ifindex = nm_ip6_config_get_ifindex(self); - g_return_val_if_fail(ifindex > 0, FALSE); - - addresses = - nm_dedup_multi_objs_to_ptr_array_head(nm_ip6_config_lookup_addresses(self), NULL, NULL); - - routes = nm_dedup_multi_objs_to_ptr_array_head(nm_ip6_config_lookup_routes(self), NULL, NULL); - - routes_prune = - nm_platform_ip_route_get_prune_list(platform, AF_INET6, ifindex, route_table_sync); - - nm_platform_ip6_address_sync(platform, ifindex, addresses, FALSE); - - if (!nm_platform_ip_route_sync(platform, - AF_INET6, - ifindex, - routes, - routes_prune, - out_temporary_not_available)) - success = FALSE; - - return success; -} - -void -nm_ip6_config_merge_setting(NMIP6Config * self, - NMSettingIPConfig *setting, - guint32 route_table, - guint32 route_metric) -{ - guint naddresses, nroutes, nnameservers, nsearches; - const char * gateway_str; - struct in6_addr gateway_bin; - int i, priority; - - if (!setting) - return; - - g_return_if_fail(NM_IS_SETTING_IP6_CONFIG(setting)); - - naddresses = nm_setting_ip_config_get_num_addresses(setting); - nroutes = nm_setting_ip_config_get_num_routes(setting); - nnameservers = nm_setting_ip_config_get_num_dns(setting); - nsearches = nm_setting_ip_config_get_num_dns_searches(setting); - - g_object_freeze_notify(G_OBJECT(self)); - - /* Gateway */ - if (!nm_setting_ip_config_get_never_default(setting) - && (gateway_str = nm_setting_ip_config_get_gateway(setting)) - && inet_pton(AF_INET6, gateway_str, &gateway_bin) == 1 - && !IN6_IS_ADDR_UNSPECIFIED(&gateway_bin)) { - const NMPlatformIP6Route r = { - .rt_source = NM_IP_CONFIG_SOURCE_USER, - .gateway = gateway_bin, - .table_coerced = nm_platform_route_table_coerce(route_table), - .metric = route_metric, - }; - - _add_route(self, NULL, &r, NULL); - } - - /* Addresses */ - for (i = 0; i < naddresses; i++) { - NMIPAddress * s_addr = nm_setting_ip_config_get_address(setting, i); - NMPlatformIP6Address address; - - memset(&address, 0, sizeof(address)); - nm_ip_address_get_address_binary(s_addr, &address.address); - address.plen = nm_ip_address_get_prefix(s_addr); - nm_assert(address.plen <= 128); - address.lifetime = NM_PLATFORM_LIFETIME_PERMANENT; - address.preferred = NM_PLATFORM_LIFETIME_PERMANENT; - address.addr_source = NM_IP_CONFIG_SOURCE_USER; - - _add_address(self, NULL, &address); - } - - /* Routes */ - for (i = 0; i < nroutes; i++) { - NMIPRoute * s_route = nm_setting_ip_config_get_route(setting, i); - NMPlatformIP6Route route; - gint64 m; - - if (nm_ip_route_get_family(s_route) != AF_INET6) { - nm_assert_not_reached(); - continue; - } - - memset(&route, 0, sizeof(route)); - nm_ip_route_get_dest_binary(s_route, &route.network); - - route.plen = nm_ip_route_get_prefix(s_route); - nm_assert(route.plen <= 128); - - nm_ip_route_get_next_hop_binary(s_route, &route.gateway); - m = nm_ip_route_get_metric(s_route); - if (m < 0) - route.metric = route_metric; - else - route.metric = nm_utils_ip6_route_metric_normalize(m); - route.rt_source = NM_IP_CONFIG_SOURCE_USER; - - nm_utils_ip6_address_clear_host_address(&route.network, &route.network, route.plen); - - nm_utils_ip_route_attribute_to_platform(AF_INET6, - s_route, - NM_PLATFORM_IP_ROUTE_CAST(&route), - route_table); - _add_route(self, NULL, &route, NULL); - } - - /* DNS */ - if (nm_setting_ip_config_get_ignore_auto_dns(setting)) { - nm_ip6_config_reset_nameservers(self); - nm_ip6_config_reset_domains(self); - nm_ip6_config_reset_searches(self); - } - for (i = 0; i < nnameservers; i++) { - struct in6_addr ip; - - if (inet_pton(AF_INET6, nm_setting_ip_config_get_dns(setting, i), &ip) == 1) - nm_ip6_config_add_nameserver(self, &ip); - } - for (i = 0; i < nsearches; i++) - nm_ip6_config_add_search(self, nm_setting_ip_config_get_dns_search(setting, i)); - - i = 0; - while ((i = nm_setting_ip_config_next_valid_dns_option(setting, i)) >= 0) { - nm_ip6_config_add_dns_option(self, nm_setting_ip_config_get_dns_option(setting, i)); - i++; - } - - priority = nm_setting_ip_config_get_dns_priority(setting); - if (priority) - nm_ip6_config_set_dns_priority(self, priority); - - nm_ip6_config_set_never_default(self, nm_setting_ip_config_get_never_default(setting)); - - g_object_thaw_notify(G_OBJECT(self)); -} - -NMSetting * -nm_ip6_config_create_setting(const NMIP6Config *self, gboolean maybe_ipv6_disabled) -{ - const NMIP6ConfigPrivate * priv; - NMSettingIPConfig * s_ip6; - guint nnameservers, nsearches, noptions; - const char * method = NULL; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - int i; - NMDedupMultiIter ipconf_iter; - const NMPlatformIP6Address *address; - const NMPlatformIP6Route * route; - - s_ip6 = NM_SETTING_IP_CONFIG(nm_setting_ip6_config_new()); - - if (!self) { - g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL); - return NM_SETTING(s_ip6); - } - - priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - nnameservers = nm_ip6_config_get_num_nameservers(self); - nsearches = nm_ip6_config_get_num_searches(self); - noptions = nm_ip6_config_get_num_dns_options(self); - - /* Addresses */ - nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, self, &address) { - NMIPAddress *s_addr; - - /* Ignore link-local address. */ - if (IN6_IS_ADDR_LINKLOCAL(&address->address)) { - if (!method) - method = NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL; - continue; - } - - /* Detect dynamic address */ - if (address->lifetime != NM_PLATFORM_LIFETIME_PERMANENT) { - method = NM_SETTING_IP6_CONFIG_METHOD_AUTO; - continue; - } - - /* Static address found. */ - if (!method || strcmp(method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0) - method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL; - - s_addr = nm_ip_address_new_binary(AF_INET6, &address->address, address->plen, NULL); - nm_setting_ip_config_add_address(s_ip6, s_addr); - nm_ip_address_unref(s_addr); - } - - /* Gateway */ - if (priv->best_default_route && nm_setting_ip_config_get_num_addresses(s_ip6) > 0) { - g_object_set( - s_ip6, - NM_SETTING_IP_CONFIG_GATEWAY, - _nm_utils_inet6_ntop(&NMP_OBJECT_CAST_IP6_ROUTE(priv->best_default_route)->gateway, - sbuf), - NULL); - } - - /* Use 'ignore' if the method wasn't previously set */ - if (!method) { - method = maybe_ipv6_disabled ? NM_SETTING_IP6_CONFIG_METHOD_DISABLED - : NM_SETTING_IP6_CONFIG_METHOD_IGNORE; - } - - g_object_set(s_ip6, NM_SETTING_IP_CONFIG_METHOD, method, NULL); - - /* Routes */ - nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, self, &route) { - NMIPRoute *s_route; - - /* Ignore link-local route. */ - if (IN6_IS_ADDR_LINKLOCAL(&route->network)) - continue; - - if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(route)) - continue; - - /* Ignore routes provided by external sources */ - if (route->rt_source - != nmp_utils_ip_config_source_round_trip_rtprot(NM_IP_CONFIG_SOURCE_USER)) - continue; - - s_route = nm_ip_route_new_binary(AF_INET6, - &route->network, - route->plen, - &route->gateway, - route->metric, - NULL); - nm_setting_ip_config_add_route(s_ip6, s_route); - nm_ip_route_unref(s_route); - } - - /* DNS */ - for (i = 0; i < nnameservers; i++) { - const struct in6_addr *nameserver = nm_ip6_config_get_nameserver(self, i); - - nm_setting_ip_config_add_dns(s_ip6, _nm_utils_inet6_ntop(nameserver, sbuf)); - } - for (i = 0; i < nsearches; i++) { - const char *search = nm_ip6_config_get_search(self, i); - - nm_setting_ip_config_add_dns_search(s_ip6, search); - } - for (i = 0; i < noptions; i++) { - const char *option = nm_ip6_config_get_dns_option(self, i); - - nm_setting_ip_config_add_dns_option(s_ip6, option); - } - - g_object_set(s_ip6, - NM_SETTING_IP_CONFIG_DNS_PRIORITY, - nm_ip6_config_get_dns_priority(self), - NULL); - - return NM_SETTING(s_ip6); -} - -/*****************************************************************************/ - -void -nm_ip6_config_merge(NMIP6Config * dst, - const NMIP6Config * src, - NMIPConfigMergeFlags merge_flags, - guint32 default_route_metric_penalty) -{ - guint32 i; - NMDedupMultiIter ipconf_iter; - const NMPlatformIP6Address *address = NULL; - const NMIP6ConfigPrivate * src_priv; - - g_return_if_fail(src != NULL); - g_return_if_fail(dst != NULL); - - src_priv = NM_IP6_CONFIG_GET_PRIVATE(src); - - g_object_freeze_notify(G_OBJECT(dst)); - - /* addresses */ - nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, src, &address) { - if (NM_FLAGS_HAS(merge_flags, NM_IP_CONFIG_MERGE_EXTERNAL) && !address->external) { - NMPlatformIP6Address a; - - a = *address; - a.external = TRUE; - _add_address(dst, NULL, &a); - } else - _add_address(dst, NMP_OBJECT_UP_CAST(address), NULL); - } - - /* nameservers */ - if (!NM_FLAGS_HAS(merge_flags, NM_IP_CONFIG_MERGE_NO_DNS)) { - for (i = 0; i < nm_ip6_config_get_num_nameservers(src); i++) - nm_ip6_config_add_nameserver(dst, nm_ip6_config_get_nameserver(src, i)); - } - - /* routes */ - if (!NM_FLAGS_HAS(merge_flags, NM_IP_CONFIG_MERGE_NO_ROUTES)) { - const NMPlatformIP6Route *r_src; - - nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, src, &r_src) { - if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(r_src)) { - if (NM_FLAGS_HAS(merge_flags, NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES) - && !NM_FLAGS_HAS(src_priv->config_flags, - NM_IP_CONFIG_FLAGS_IGNORE_MERGE_NO_DEFAULT_ROUTES)) - continue; - if (default_route_metric_penalty) { - NMPlatformIP6Route r = *r_src; - - r.metric = - nm_utils_ip_route_metric_penalize(r.metric, default_route_metric_penalty); - _add_route(dst, NULL, &r, NULL); - continue; - } - } - _add_route(dst, ipconf_iter.current->obj, NULL, NULL); - } - } - - /* domains */ - if (!NM_FLAGS_HAS(merge_flags, NM_IP_CONFIG_MERGE_NO_DNS)) { - for (i = 0; i < nm_ip6_config_get_num_domains(src); i++) - nm_ip6_config_add_domain(dst, nm_ip6_config_get_domain(src, i)); - } - - /* dns searches */ - if (!NM_FLAGS_HAS(merge_flags, NM_IP_CONFIG_MERGE_NO_DNS)) { - for (i = 0; i < nm_ip6_config_get_num_searches(src); i++) - nm_ip6_config_add_search(dst, nm_ip6_config_get_search(src, i)); - } - - /* dns options */ - if (!NM_FLAGS_HAS(merge_flags, NM_IP_CONFIG_MERGE_NO_DNS)) { - for (i = 0; i < nm_ip6_config_get_num_dns_options(src); i++) - nm_ip6_config_add_dns_option(dst, nm_ip6_config_get_dns_option(src, i)); - } - - /* DNS priority */ - if (nm_ip6_config_get_dns_priority(src)) - nm_ip6_config_set_dns_priority(dst, nm_ip6_config_get_dns_priority(src)); - - g_object_thaw_notify(G_OBJECT(dst)); -} - -/*****************************************************************************/ - -static int -_nameservers_get_index(const NMIP6Config *self, const struct in6_addr *ns) -{ - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - guint i; - - for (i = 0; i < priv->nameservers->len; i++) { - const struct in6_addr *n = &g_array_index(priv->nameservers, struct in6_addr, i); - - if (IN6_ARE_ADDR_EQUAL(ns, n)) - return (int) i; - } - return -1; -} - -static int -_domains_get_index(const NMIP6Config *self, const char *domain) -{ - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - guint i; - - for (i = 0; i < priv->domains->len; i++) { - const char *d = g_ptr_array_index(priv->domains, i); - - if (g_strcmp0(domain, d) == 0) - return (int) i; - } - return -1; -} - -static int -_searches_get_index(const NMIP6Config *self, const char *search) -{ - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - guint i; - - for (i = 0; i < priv->searches->len; i++) { - const char *s = g_ptr_array_index(priv->searches, i); - - if (g_strcmp0(search, s) == 0) - return (int) i; - } - return -1; -} - -static int -_dns_options_get_index(const NMIP6Config *self, const char *option) -{ - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - guint i; - - for (i = 0; i < priv->dns_options->len; i++) { - const char *s = g_ptr_array_index(priv->dns_options, i); - - if (g_strcmp0(option, s) == 0) - return (int) i; - } - return -1; -} - -/*****************************************************************************/ - -/** - * nm_ip6_config_subtract: - * @dst: config from which to remove everything in @src - * @src: config to remove from @dst - * @default_route_metric_penalty: pretend that on source we applied - * a route penalty on the default-route. It means, for default routes - * we don't remove routes that match exactly, but those with a lower - * metric (with the penalty removed). -* - * Removes everything in @src from @dst. - */ -void -nm_ip6_config_subtract(NMIP6Config * dst, - const NMIP6Config *src, - guint32 default_route_metric_penalty) -{ - NMIP6ConfigPrivate * dst_priv; - guint i; - int idx; - const NMPlatformIP6Address *a; - const NMPlatformIP6Route * r; - NMDedupMultiIter ipconf_iter; - gboolean changed; - gboolean changed_default_route; - - g_return_if_fail(src != NULL); - g_return_if_fail(dst != NULL); - - dst_priv = NM_IP6_CONFIG_GET_PRIVATE(dst); - - g_object_freeze_notify(G_OBJECT(dst)); - - /* addresses */ - changed = FALSE; - nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, src, &a) { - if (nm_dedup_multi_index_remove_obj(dst_priv->multi_idx, - &dst_priv->idx_ip6_addresses, - NMP_OBJECT_UP_CAST(a), - NULL)) - changed = TRUE; - } - if (changed) - _notify_addresses(dst); - - /* nameservers */ - for (i = 0; i < nm_ip6_config_get_num_nameservers(src); i++) { - idx = _nameservers_get_index(dst, nm_ip6_config_get_nameserver(src, i)); - if (idx >= 0) - nm_ip6_config_del_nameserver(dst, idx); - } - - /* routes */ - changed = FALSE; - changed_default_route = FALSE; - nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, src, &r) { - const NMPObject * o_src = NMP_OBJECT_UP_CAST(r); - NMPObject o_lookup_copy; - const NMPObject * o_lookup; - nm_auto_nmpobj const NMPObject *obj_old = NULL; - - if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(r) && default_route_metric_penalty) { - NMPlatformIP6Route *rr; - - /* the default route was penalized when merging it to the combined ip-config. - * When subtracting the routes, we must re-do that process when comparing - * the routes. */ - o_lookup = nmp_object_stackinit_obj(&o_lookup_copy, o_src); - rr = NMP_OBJECT_CAST_IP6_ROUTE(&o_lookup_copy); - rr->metric = - nm_utils_ip_route_metric_penalize(rr->metric, default_route_metric_penalty); - } else - o_lookup = o_src; - - if (nm_dedup_multi_index_remove_obj(dst_priv->multi_idx, - &dst_priv->idx_ip6_routes, - o_lookup, - (gconstpointer *) &obj_old)) { - if (dst_priv->best_default_route == obj_old) { - nm_clear_nmp_object(&dst_priv->best_default_route); - changed_default_route = TRUE; - } - changed = TRUE; - } - } - if (changed_default_route) { - nmp_object_ref_set(&dst_priv->best_default_route, - _nm_ip6_config_best_default_route_find(dst)); - _notify(dst, PROP_GATEWAY); - } - if (changed) - _notify_routes(dst); - - /* domains */ - for (i = 0; i < nm_ip6_config_get_num_domains(src); i++) { - idx = _domains_get_index(dst, nm_ip6_config_get_domain(src, i)); - if (idx >= 0) - nm_ip6_config_del_domain(dst, idx); - } - - /* dns searches */ - for (i = 0; i < nm_ip6_config_get_num_searches(src); i++) { - idx = _searches_get_index(dst, nm_ip6_config_get_search(src, i)); - if (idx >= 0) - nm_ip6_config_del_search(dst, idx); - } - - /* dns options */ - for (i = 0; i < nm_ip6_config_get_num_dns_options(src); i++) { - idx = _dns_options_get_index(dst, nm_ip6_config_get_dns_option(src, i)); - if (idx >= 0) - nm_ip6_config_del_dns_option(dst, idx); - } - - /* DNS priority */ - if (nm_ip6_config_get_dns_priority(src) == nm_ip6_config_get_dns_priority(dst)) - nm_ip6_config_set_dns_priority(dst, 0); - - g_object_thaw_notify(G_OBJECT(dst)); -} - -static gboolean -_nm_ip6_config_intersect_helper(NMIP6Config * dst, - const NMIP6Config *src, - gboolean intersect_addresses, - gboolean intersect_routes, - guint32 default_route_metric_penalty, - gboolean update_dst) -{ - NMIP6ConfigPrivate * dst_priv; - const NMIP6ConfigPrivate * src_priv; - NMDedupMultiIter ipconf_iter; - const NMPlatformIP6Address *a; - const NMPlatformIP6Route * r; - gboolean changed, result = FALSE; - const NMPObject * new_best_default_route; - - g_return_val_if_fail(src, FALSE); - g_return_val_if_fail(dst, FALSE); - - dst_priv = NM_IP6_CONFIG_GET_PRIVATE(dst); - src_priv = NM_IP6_CONFIG_GET_PRIVATE(src); - - if (update_dst) - g_object_freeze_notify(G_OBJECT(dst)); - - /* addresses */ - if (intersect_addresses) { - changed = FALSE; - nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, dst, &a) { - if (nm_dedup_multi_index_lookup_obj(src_priv->multi_idx, - &src_priv->idx_ip6_addresses, - NMP_OBJECT_UP_CAST(a))) - continue; - - if (!update_dst) - return TRUE; - - if (nm_dedup_multi_index_remove_entry(dst_priv->multi_idx, ipconf_iter.current) != 1) - nm_assert_not_reached(); - changed = TRUE; - } - if (changed) { - _notify_addresses(dst); - result = TRUE; - } - } - - /* ignore nameservers */ - - /* routes */ - if (!intersect_routes) - goto skip_routes; - - changed = FALSE; - new_best_default_route = NULL; - nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, dst, &r) { - const NMPObject *o_dst = NMP_OBJECT_UP_CAST(r); - const NMPObject *o_lookup; - NMPObject o_lookup_copy; - - if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(r) && default_route_metric_penalty) { - NMPlatformIP6Route *rr; - - /* the default route was penalized when merging it to the combined ip-config. - * When intersecting the routes, we must re-do that process when comparing - * the routes. */ - o_lookup = nmp_object_stackinit_obj(&o_lookup_copy, o_dst); - rr = NMP_OBJECT_CAST_IP6_ROUTE(&o_lookup_copy); - rr->metric = - nm_utils_ip_route_metric_penalize(rr->metric, default_route_metric_penalty); - } else - o_lookup = o_dst; - - if (nm_dedup_multi_index_lookup_obj(src_priv->multi_idx, - &src_priv->idx_ip6_routes, - o_lookup)) { - new_best_default_route = - _nm_ip_config_best_default_route_find_better(new_best_default_route, o_dst); - continue; - } - - if (!update_dst) - return TRUE; - - if (nm_dedup_multi_index_remove_entry(dst_priv->multi_idx, ipconf_iter.current) != 1) - nm_assert_not_reached(); - changed = TRUE; - } - if (nmp_object_ref_set(&dst_priv->best_default_route, new_best_default_route)) { - nm_assert(changed); - _notify(dst, PROP_GATEWAY); - } - if (changed) { - _notify_routes(dst); - result = TRUE; - } - -skip_routes: - /* ignore domains */ - /* ignore dns searches */ - /* ignore dns options */ - - if (update_dst) - g_object_thaw_notify(G_OBJECT(dst)); - - return result; -} - -/** - * nm_ip6_config_intersect: - * @dst: a configuration to be updated - * @src: another configuration - * @intersect_addresses: whether addresses should be intersected - * @intersect_routes: whether routes should be intersected - * @default_route_metric_penalty: the default route metric penalty - * - * Computes the intersection between @src and @dst and updates @dst in place - * with the result. - */ -void -nm_ip6_config_intersect(NMIP6Config * dst, - const NMIP6Config *src, - gboolean intersect_addresses, - gboolean intersect_routes, - guint32 default_route_metric_penalty) -{ - _nm_ip6_config_intersect_helper(dst, - src, - intersect_addresses, - intersect_routes, - default_route_metric_penalty, - TRUE); -} - -/** - * nm_ip6_config_intersect_alloc: - * @a: a configuration - * @b: another configuration - * @intersect_addresses: whether addresses should be intersected - * @intersect_routes: whether routes should be intersected - * @default_route_metric_penalty: the default route metric penalty - * - * Computes the intersection between @a and @b and returns the result in a newly - * allocated configuration. As a special case, if @a and @b are identical (with - * respect to the only properties considered - addresses and routes) the - * functions returns NULL so that one of existing configuration can be reused - * without allocation. - * - * Returns: the intersection between @a and @b, or %NULL if the result is equal - * to @a and @b. - */ -NMIP6Config * -nm_ip6_config_intersect_alloc(const NMIP6Config *a, - const NMIP6Config *b, - gboolean intersect_addresses, - gboolean intersect_routes, - guint32 default_route_metric_penalty) -{ - NMIP6Config *a_copy; - - if (_nm_ip6_config_intersect_helper((NMIP6Config *) a, - b, - intersect_addresses, - intersect_routes, - default_route_metric_penalty, - FALSE)) { - a_copy = nm_ip6_config_clone(a); - _nm_ip6_config_intersect_helper(a_copy, - b, - intersect_addresses, - intersect_routes, - default_route_metric_penalty, - TRUE); - return a_copy; - } else - return NULL; -} - -/** - * nm_ip6_config_replace: - * @dst: config which will be replaced with everything in @src - * @src: config to copy over to @dst - * @relevant_changes: return whether there are changes to the - * destination object that are relevant. This is equal to - * nm_ip6_config_equal() showing any difference. - * - * Replaces everything in @dst with @src so that the two configurations - * contain the same content -- with the exception of the dbus path. - * - * Returns: whether the @dst instance changed in any way (including minor changes, - * that are not signaled by the output parameter @relevant_changes). - */ -gboolean -nm_ip6_config_replace(NMIP6Config *dst, const NMIP6Config *src, gboolean *relevant_changes) -{ -#if NM_MORE_ASSERTS - gboolean config_equal; -#endif - gboolean has_minor_changes = FALSE, has_relevant_changes = FALSE, are_equal; - guint i, num; - NMIP6ConfigPrivate * dst_priv; - const NMIP6ConfigPrivate * src_priv; - NMDedupMultiIter ipconf_iter_src, ipconf_iter_dst; - const NMDedupMultiHeadEntry *head_entry_src; - const NMPObject * new_best_default_route; - - g_return_val_if_fail(NM_IS_IP6_CONFIG(src), FALSE); - g_return_val_if_fail(NM_IS_IP6_CONFIG(dst), FALSE); - g_return_val_if_fail(src != dst, FALSE); - -#if NM_MORE_ASSERTS - config_equal = nm_ip6_config_equal(dst, src); -#endif - - dst_priv = NM_IP6_CONFIG_GET_PRIVATE(dst); - src_priv = NM_IP6_CONFIG_GET_PRIVATE(src); - - g_return_val_if_fail(src_priv->ifindex > 0, FALSE); - - g_object_freeze_notify(G_OBJECT(dst)); - - /* ifindex */ - if (src_priv->ifindex != dst_priv->ifindex) { - dst_priv->ifindex = src_priv->ifindex; - has_minor_changes = TRUE; - } - - /* addresses */ - head_entry_src = nm_ip6_config_lookup_addresses(src); - nm_dedup_multi_iter_init(&ipconf_iter_src, head_entry_src); - nm_ip_config_iter_ip6_address_init(&ipconf_iter_dst, dst); - are_equal = TRUE; - while (TRUE) { - gboolean has; - const NMPlatformIP6Address *r_src = NULL; - const NMPlatformIP6Address *r_dst = NULL; - - has = nm_platform_dedup_multi_iter_next_ip6_address(&ipconf_iter_src, &r_src); - if (has != nm_platform_dedup_multi_iter_next_ip6_address(&ipconf_iter_dst, &r_dst)) { - are_equal = FALSE; - has_relevant_changes = TRUE; - break; - } - if (!has) - break; - - if (nm_platform_ip6_address_cmp(r_src, r_dst) != 0) { - are_equal = FALSE; - if (!IN6_ARE_ADDR_EQUAL(&r_src->address, &r_dst->address) || r_src->plen != r_dst->plen - || !IN6_ARE_ADDR_EQUAL(nm_platform_ip6_address_get_peer(r_src), - nm_platform_ip6_address_get_peer(r_dst))) { - has_relevant_changes = TRUE; - break; - } - } - } - if (!are_equal) { - has_minor_changes = TRUE; - nm_dedup_multi_index_dirty_set_idx(dst_priv->multi_idx, &dst_priv->idx_ip6_addresses); - nm_dedup_multi_iter_for_each (&ipconf_iter_src, head_entry_src) { - _nm_ip_config_add_obj(dst_priv->multi_idx, - &dst_priv->idx_ip6_addresses_, - dst_priv->ifindex, - ipconf_iter_src.current->obj, - NULL, - FALSE, - TRUE, - NULL, - NULL); - } - nm_dedup_multi_index_dirty_remove_idx(dst_priv->multi_idx, - &dst_priv->idx_ip6_addresses, - FALSE); - _notify_addresses(dst); - } - - /* routes */ - head_entry_src = nm_ip6_config_lookup_routes(src); - nm_dedup_multi_iter_init(&ipconf_iter_src, head_entry_src); - nm_ip_config_iter_ip6_route_init(&ipconf_iter_dst, dst); - are_equal = TRUE; - while (TRUE) { - gboolean has; - const NMPlatformIP6Route *r_src = NULL; - const NMPlatformIP6Route *r_dst = NULL; - - has = nm_platform_dedup_multi_iter_next_ip6_route(&ipconf_iter_src, &r_src); - if (has != nm_platform_dedup_multi_iter_next_ip6_route(&ipconf_iter_dst, &r_dst)) { - are_equal = FALSE; - has_relevant_changes = TRUE; - break; - } - if (!has) - break; - - if (nm_platform_ip6_route_cmp_full(r_src, r_dst) != 0) { - are_equal = FALSE; - if (r_src->plen != r_dst->plen - || !nm_utils_ip6_address_same_prefix(&r_src->network, &r_dst->network, r_src->plen) - || r_src->metric != r_dst->metric - || !IN6_ARE_ADDR_EQUAL(&r_src->gateway, &r_dst->gateway)) { - has_relevant_changes = TRUE; - break; - } - } - } - if (!are_equal) { - has_minor_changes = TRUE; - new_best_default_route = NULL; - nm_dedup_multi_index_dirty_set_idx(dst_priv->multi_idx, &dst_priv->idx_ip6_routes); - nm_dedup_multi_iter_for_each (&ipconf_iter_src, head_entry_src) { - const NMPObject *o = ipconf_iter_src.current->obj; - const NMPObject *obj_new; - - _nm_ip_config_add_obj(dst_priv->multi_idx, - &dst_priv->idx_ip6_routes_, - dst_priv->ifindex, - o, - NULL, - FALSE, - TRUE, - NULL, - &obj_new); - new_best_default_route = - _nm_ip_config_best_default_route_find_better(new_best_default_route, obj_new); - } - nm_dedup_multi_index_dirty_remove_idx(dst_priv->multi_idx, - &dst_priv->idx_ip6_routes, - FALSE); - if (nmp_object_ref_set(&dst_priv->best_default_route, new_best_default_route)) - _notify(dst, PROP_GATEWAY); - _notify_routes(dst); - } - - /* nameservers */ - num = nm_ip6_config_get_num_nameservers(src); - are_equal = num == nm_ip6_config_get_num_nameservers(dst); - if (are_equal) { - for (i = 0; i < num; i++) { - if (!IN6_ARE_ADDR_EQUAL(nm_ip6_config_get_nameserver(src, i), - nm_ip6_config_get_nameserver(dst, i))) { - are_equal = FALSE; - break; - } - } - } - if (!are_equal) { - nm_ip6_config_reset_nameservers(dst); - for (i = 0; i < num; i++) - nm_ip6_config_add_nameserver(dst, nm_ip6_config_get_nameserver(src, i)); - has_relevant_changes = TRUE; - } - - /* domains */ - num = nm_ip6_config_get_num_domains(src); - are_equal = num == nm_ip6_config_get_num_domains(dst); - if (are_equal) { - for (i = 0; i < num; i++) { - if (g_strcmp0(nm_ip6_config_get_domain(src, i), nm_ip6_config_get_domain(dst, i))) { - are_equal = FALSE; - break; - } - } - } - if (!are_equal) { - nm_ip6_config_reset_domains(dst); - for (i = 0; i < num; i++) - nm_ip6_config_add_domain(dst, nm_ip6_config_get_domain(src, i)); - has_relevant_changes = TRUE; - } - - /* dns searches */ - num = nm_ip6_config_get_num_searches(src); - are_equal = num == nm_ip6_config_get_num_searches(dst); - if (are_equal) { - for (i = 0; i < num; i++) { - if (g_strcmp0(nm_ip6_config_get_search(src, i), nm_ip6_config_get_search(dst, i))) { - are_equal = FALSE; - break; - } - } - } - if (!are_equal) { - nm_ip6_config_reset_searches(dst); - for (i = 0; i < num; i++) - nm_ip6_config_add_search(dst, nm_ip6_config_get_search(src, i)); - has_relevant_changes = TRUE; - } - - /* dns options */ - num = nm_ip6_config_get_num_dns_options(src); - are_equal = num == nm_ip6_config_get_num_dns_options(dst); - if (are_equal) { - for (i = 0; i < num; i++) { - if (g_strcmp0(nm_ip6_config_get_dns_option(src, i), - nm_ip6_config_get_dns_option(dst, i))) { - are_equal = FALSE; - break; - } - } - } - if (!are_equal) { - nm_ip6_config_reset_dns_options(dst); - for (i = 0; i < num; i++) - nm_ip6_config_add_dns_option(dst, nm_ip6_config_get_dns_option(src, i)); - has_relevant_changes = TRUE; - } - - /* DNS priority */ - if (src_priv->dns_priority != dst_priv->dns_priority) { - nm_ip6_config_set_dns_priority(dst, src_priv->dns_priority); - has_minor_changes = TRUE; - } - - if (src_priv->privacy != dst_priv->privacy) { - nm_ip6_config_set_privacy(dst, src_priv->privacy); - has_minor_changes = TRUE; - } - -#if NM_MORE_ASSERTS - /* config_equal does not compare *all* the fields, therefore, we might have has_minor_changes - * regardless of config_equal. But config_equal must correspond to has_relevant_changes. */ - nm_assert(config_equal == !has_relevant_changes); -#endif - - g_object_thaw_notify(G_OBJECT(dst)); - - if (relevant_changes) - *relevant_changes = has_relevant_changes; - - return has_relevant_changes || has_minor_changes; -} - -/*****************************************************************************/ - -void -nm_ip6_config_reset_addresses_ndisc(NMIP6Config * self, - const NMNDiscAddress *addresses, - guint addresses_n, - guint8 plen, - guint32 ifa_flags) -{ - NMIP6ConfigPrivate *priv; - guint i; - gboolean changed = FALSE; - gint32 base_time_sec; - - g_return_if_fail(NM_IS_IP6_CONFIG(self)); - - priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - g_return_if_fail(priv->ifindex > 0); - - /* the base-timestamp doesn't matter it's only an anchor for the - * expiry. However, try to re-use the same base-time for a while - * by rounding it to 10000 seconds. - * - * That is because we deduplicate and NMPlatformIP6Address instances - * so using the same timestamps is preferable. */ - base_time_sec = nm_utils_get_monotonic_timestamp_sec(); - base_time_sec = (base_time_sec / 10000) * 10000; - base_time_sec = NM_MAX(1, base_time_sec); - - nm_dedup_multi_index_dirty_set_idx(priv->multi_idx, &priv->idx_ip6_addresses); - - for (i = 0; i < addresses_n; i++) { - const NMNDiscAddress *ndisc_addr = &addresses[i]; - NMPObject obj; - NMPlatformIP6Address *a; - - nmp_object_stackinit(&obj, NMP_OBJECT_TYPE_IP6_ADDRESS, NULL); - a = NMP_OBJECT_CAST_IP6_ADDRESS(&obj); - a->ifindex = priv->ifindex; - a->address = ndisc_addr->address; - a->plen = plen; - a->timestamp = base_time_sec, - a->lifetime = _nm_ndisc_lifetime_from_expiry(((gint64) base_time_sec) * 1000, - ndisc_addr->expiry_msec, - TRUE), - a->preferred = _nm_ndisc_lifetime_from_expiry(((gint64) base_time_sec) * 1000, - ndisc_addr->expiry_preferred_msec, - TRUE), - a->addr_source = NM_IP_CONFIG_SOURCE_NDISC; - a->n_ifa_flags = ifa_flags; - - if (_nm_ip_config_add_obj(priv->multi_idx, - &priv->idx_ip6_addresses_, - priv->ifindex, - &obj, - NULL, - FALSE, - TRUE, - NULL, - NULL)) - changed = TRUE; - } - - if (nm_dedup_multi_index_dirty_remove_idx(priv->multi_idx, &priv->idx_ip6_addresses, FALSE) > 0) - changed = TRUE; - - if (changed) - _notify_addresses(self); -} - -void -nm_ip6_config_reset_addresses(NMIP6Config *self) -{ - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - if (nm_dedup_multi_index_remove_idx(priv->multi_idx, &priv->idx_ip6_addresses) > 0) - _notify_addresses(self); -} - -static void -_add_address(NMIP6Config *self, const NMPObject *obj_new, const NMPlatformIP6Address *new) -{ - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - if (_nm_ip_config_add_obj(priv->multi_idx, - &priv->idx_ip6_addresses_, - priv->ifindex, - obj_new, - (const NMPlatformObject *) new, - TRUE, - FALSE, - NULL, - NULL)) - _notify_addresses(self); -} - -/** - * nm_ip6_config_add_address: - * @self: the #NMIP6Config - * @new: the new address to add to @self - * - * Adds the new address to @self. If an address with the same basic properties - * (address, prefix) already exists in @self, it is overwritten with the - * lifetime and preferred of @new. The source is also overwritten by the source - * from @new if that source is higher priority. - */ -void -nm_ip6_config_add_address(NMIP6Config *self, const NMPlatformIP6Address *new) -{ - g_return_if_fail(self); - g_return_if_fail(new); - g_return_if_fail(new->plen <= 128); - g_return_if_fail(NM_IP6_CONFIG_GET_PRIVATE(self)->ifindex > 0); - - _add_address(self, NULL, new); -} - -void -_nmtst_ip6_config_del_address(NMIP6Config *self, guint i) -{ - const NMPlatformIP6Address *a; - - a = _nmtst_ip6_config_get_address(self, i); - if (!nm_ip6_config_nmpobj_remove(self, NMP_OBJECT_UP_CAST(a))) - g_assert_not_reached(); -} - -guint -nm_ip6_config_get_num_addresses(const NMIP6Config *self) -{ - const NMDedupMultiHeadEntry *head_entry; - - head_entry = nm_ip6_config_lookup_addresses(self); - return head_entry ? head_entry->len : 0; -} - -const NMPlatformIP6Address * -nm_ip6_config_get_first_address(const NMIP6Config *self) -{ - NMDedupMultiIter iter; - const NMPlatformIP6Address *a = NULL; - - nm_ip_config_iter_ip6_address_for_each (&iter, self, &a) - return a; - return NULL; -} - -const NMPlatformIP6Address * -_nmtst_ip6_config_get_address(const NMIP6Config *self, guint i) -{ - NMDedupMultiIter iter; - const NMPlatformIP6Address *a = NULL; - guint j; - - j = 0; - nm_ip_config_iter_ip6_address_for_each (&iter, self, &a) { - if (i == j) - return a; - j++; - } - g_return_val_if_reached(NULL); -} - -const NMPlatformIP6Address * -nm_ip6_config_lookup_address(const NMIP6Config *self, const struct in6_addr *addr) -{ - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - NMPObject obj_stack; - const NMDedupMultiEntry * entry; - - nmp_object_stackinit_id_ip6_address(&obj_stack, priv->ifindex, addr); - entry = nm_dedup_multi_index_lookup_obj(priv->multi_idx, &priv->idx_ip6_addresses, &obj_stack); - 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 - * @candidates: configuration with the list of addresses we are - * interested in - * - * Check whether there are addresses with DAD pending in @self, that - * are also contained in @candidates. - * - * Returns: %TRUE if at least one matching address was found, %FALSE - * otherwise - */ -gboolean -nm_ip6_config_has_any_dad_pending(const NMIP6Config *self, const NMIP6Config *candidates) -{ - NMDedupMultiIter ipconf_iter; - const NMPlatformIP6Address *addr, *addr_c; - - nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, self, &addr) { - if (NM_FLAGS_HAS(addr->n_ifa_flags, IFA_F_TENTATIVE) - && !NM_FLAGS_HAS(addr->n_ifa_flags, IFA_F_DADFAILED) - && !NM_FLAGS_HAS(addr->n_ifa_flags, IFA_F_OPTIMISTIC)) { - addr_c = nm_ip6_config_lookup_address(candidates, &addr->address); - if (addr_c) { - if (addr->plen == addr_c->plen) - return TRUE; - } - } - } - - return FALSE; -} - -/*****************************************************************************/ - -static const NMDedupMultiEntry * -_lookup_route(const NMIP6Config *self, const NMPObject *needle, NMPlatformIPRouteCmpType cmp_type) -{ - const NMIP6ConfigPrivate *priv; - - nm_assert(NM_IS_IP6_CONFIG(self)); - nm_assert(NMP_OBJECT_GET_TYPE(needle) == NMP_OBJECT_TYPE_IP6_ROUTE); - - priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - return _nm_ip_config_lookup_ip_route(priv->multi_idx, &priv->idx_ip6_routes_, needle, cmp_type); -} - -void -nm_ip6_config_reset_routes_ndisc(NMIP6Config * self, - const NMNDiscGateway *gateways, - guint gateways_n, - const NMNDiscRoute * routes, - guint routes_n, - guint32 route_table, - guint32 route_metric, - gboolean kernel_support_rta_pref) -{ - NMIP6ConfigPrivate *priv; - guint i; - gboolean changed = FALSE; - const NMPObject * new_best_default_route; - - g_return_if_fail(NM_IS_IP6_CONFIG(self)); - - priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - g_return_if_fail(priv->ifindex > 0); - - nm_dedup_multi_index_dirty_set_idx(priv->multi_idx, &priv->idx_ip6_routes); - - new_best_default_route = NULL; - for (i = 0; i < routes_n; i++) { - const NMNDiscRoute *ndisc_route = &routes[i]; - NMPObject obj; - const NMPObject * obj_new; - NMPlatformIP6Route *r; - - nmp_object_stackinit(&obj, NMP_OBJECT_TYPE_IP6_ROUTE, NULL); - r = NMP_OBJECT_CAST_IP6_ROUTE(&obj); - r->ifindex = priv->ifindex; - r->network = ndisc_route->network; - r->plen = ndisc_route->plen; - r->gateway = ndisc_route->gateway; - r->rt_source = NM_IP_CONFIG_SOURCE_NDISC; - r->table_coerced = nm_platform_route_table_coerce(route_table); - r->metric = route_metric; - r->rt_pref = ndisc_route->preference; - nm_assert((NMIcmpv6RouterPref) r->rt_pref == ndisc_route->preference); - - if (_nm_ip_config_add_obj(priv->multi_idx, - &priv->idx_ip6_routes_, - priv->ifindex, - &obj, - NULL, - FALSE, - TRUE, - NULL, - &obj_new)) - changed = TRUE; - new_best_default_route = - _nm_ip_config_best_default_route_find_better(new_best_default_route, obj_new); - } - - if (gateways_n) { - const NMPObject * obj_new; - NMPlatformIP6Route r = { - .rt_source = NM_IP_CONFIG_SOURCE_NDISC, - .ifindex = priv->ifindex, - .table_coerced = nm_platform_route_table_coerce(route_table), - .metric = route_metric, - }; - const NMIcmpv6RouterPref first_pref = gateways[0].preference; - - for (i = 0; i < gateways_n; i++) { - r.gateway = gateways[i].address; - r.rt_pref = gateways[i].preference; - nm_assert((NMIcmpv6RouterPref) r.rt_pref == gateways[i].preference); - if (_nm_ip_config_add_obj(priv->multi_idx, - &priv->idx_ip6_routes_, - priv->ifindex, - NULL, - (const NMPlatformObject *) &r, - FALSE, - TRUE, - NULL, - &obj_new)) - changed = TRUE; - new_best_default_route = - _nm_ip_config_best_default_route_find_better(new_best_default_route, obj_new); - - if (first_pref != gateways[i].preference && !kernel_support_rta_pref) { - /* We are unable to configure a router preference. Hence, we skip all gateways - * with a different preference from the first gateway. Note, that the gateways - * are sorted in order of highest to lowest preference. */ - break; - } - } - } - - if (nm_dedup_multi_index_dirty_remove_idx(priv->multi_idx, &priv->idx_ip6_routes, FALSE) > 0) - changed = TRUE; - - if (nmp_object_ref_set(&priv->best_default_route, new_best_default_route)) { - changed = TRUE; - _notify(self, PROP_GATEWAY); - } - - if (changed) - _notify_routes(self); -} - -void -nm_ip6_config_reset_routes(NMIP6Config *self) -{ - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - if (nm_dedup_multi_index_remove_idx(priv->multi_idx, &priv->idx_ip6_routes) > 0) { - if (nm_clear_nmp_object(&priv->best_default_route)) - _notify(self, PROP_GATEWAY); - _notify_routes(self); - } -} - -static void -_add_route(NMIP6Config * self, - const NMPObject *obj_new, - const NMPlatformIP6Route *new, - const NMPObject **out_obj_new) -{ - NMIP6ConfigPrivate * priv = NM_IP6_CONFIG_GET_PRIVATE(self); - nm_auto_nmpobj const NMPObject *obj_old = NULL; - const NMPObject * obj_new_2; - - nm_assert((!new) != (!obj_new)); - nm_assert(!new || _route_valid(new)); - nm_assert(!obj_new || _route_valid(NMP_OBJECT_CAST_IP6_ROUTE(obj_new))); - - if (_nm_ip_config_add_obj(priv->multi_idx, - &priv->idx_ip6_routes_, - priv->ifindex, - obj_new, - (const NMPlatformObject *) new, - TRUE, - FALSE, - &obj_old, - &obj_new_2)) { - gboolean changed_default_route = FALSE; - - if (priv->best_default_route == obj_old && obj_old != obj_new_2) { - changed_default_route = TRUE; - nm_clear_nmp_object(&priv->best_default_route); - } - NM_SET_OUT(out_obj_new, nmp_object_ref(obj_new_2)); - if (_nm_ip_config_best_default_route_merge(&priv->best_default_route, obj_new_2)) - changed_default_route = TRUE; - - if (changed_default_route) - _notify(self, PROP_GATEWAY); - _notify_routes(self); - } else - NM_SET_OUT(out_obj_new, nmp_object_ref(obj_new_2)); -} - -/** - * nm_ip6_config_add_route: - * @self: the #NMIP6Config - * @new: the new route to add to @self - * @out_obj_new: (allow-none) (out): the added route object. Must be unrefed - * by caller. - * - * Adds the new route to @self. If a route with the same basic properties - * (network, prefix) already exists in @self, it is overwritten including the - * gateway and metric of @new. The source is also overwritten by the source - * from @new if that source is higher priority. - */ -void -nm_ip6_config_add_route(NMIP6Config *self, - const NMPlatformIP6Route *new, - const NMPObject **out_obj_new) -{ - g_return_if_fail(self); - g_return_if_fail(new); - g_return_if_fail(new->plen <= 128); - g_return_if_fail(NM_IP6_CONFIG_GET_PRIVATE(self)->ifindex > 0); - - _add_route(self, NULL, new, out_obj_new); -} - -void -_nmtst_ip6_config_del_route(NMIP6Config *self, guint i) -{ - const NMPlatformIP6Route *r; - - r = _nmtst_ip6_config_get_route(self, i); - if (!nm_ip6_config_nmpobj_remove(self, NMP_OBJECT_UP_CAST(r))) - g_assert_not_reached(); -} - -guint -nm_ip6_config_get_num_routes(const NMIP6Config *self) -{ - const NMDedupMultiHeadEntry *head_entry; - - head_entry = nm_ip6_config_lookup_routes(self); - nm_assert(!head_entry || head_entry->len == c_list_length(&head_entry->lst_entries_head)); - return head_entry ? head_entry->len : 0; -} - -const NMPlatformIP6Route * -_nmtst_ip6_config_get_route(const NMIP6Config *self, guint i) -{ - NMDedupMultiIter iter; - const NMPlatformIP6Route *r = NULL; - guint j; - - j = 0; - nm_ip_config_iter_ip6_route_for_each (&iter, self, &r) { - if (i == j) - return r; - j++; - } - g_return_val_if_reached(NULL); -} - -const NMPlatformIP6Route * -nm_ip6_config_get_direct_route_for_host(const NMIP6Config * self, - const struct in6_addr *host, - guint32 route_table) -{ - const NMPlatformIP6Route *best_route = NULL; - const NMPlatformIP6Route *item; - NMDedupMultiIter ipconf_iter; - - g_return_val_if_fail(host && !IN6_IS_ADDR_UNSPECIFIED(host), NULL); - - nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, self, &item) { - if (!IN6_IS_ADDR_UNSPECIFIED(&item->gateway)) - continue; - - if (best_route && best_route->plen > item->plen) - continue; - - if (nm_platform_route_table_uncoerce(item->table_coerced, TRUE) != route_table) - continue; - - if (!nm_utils_ip6_address_same_prefix(host, &item->network, item->plen)) - continue; - - if (best_route && best_route->metric <= item->metric) - continue; - - best_route = item; - } - return best_route; -} - -const NMPlatformIP6Address * -nm_ip6_config_get_subnet_for_host(const NMIP6Config *self, const struct in6_addr *host) -{ - NMDedupMultiIter iter; - const NMPlatformIP6Address *item; - const NMPlatformIP6Address *subnet = NULL; - struct in6_addr subnet2, host2; - - g_return_val_if_fail(host && !IN6_IS_ADDR_UNSPECIFIED(host), NULL); - - nm_ip_config_iter_ip6_address_for_each (&iter, self, &item) { - if (subnet && subnet->plen >= item->plen) - continue; - - nm_utils_ip6_address_clear_host_address(&host2, host, item->plen); - nm_utils_ip6_address_clear_host_address(&subnet2, &item->address, item->plen); - - if (IN6_ARE_ADDR_EQUAL(&subnet2, &host2)) - subnet = item; - } - - return subnet; -} - -/*****************************************************************************/ - -void -nm_ip6_config_reset_nameservers(NMIP6Config *self) -{ - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - if (priv->nameservers->len != 0) { - g_array_set_size(priv->nameservers, 0); - _notify(self, PROP_NAMESERVERS); - } -} - -void -nm_ip6_config_add_nameserver(NMIP6Config *self, const struct in6_addr *new) -{ - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - int i; - - g_return_if_fail(new != NULL); - - for (i = 0; i < priv->nameservers->len; i++) - if (IN6_ARE_ADDR_EQUAL(new, &g_array_index(priv->nameservers, struct in6_addr, i))) - return; - - g_array_append_val(priv->nameservers, *new); - _notify(self, PROP_NAMESERVERS); -} - -void -nm_ip6_config_del_nameserver(NMIP6Config *self, guint i) -{ - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - g_return_if_fail(i < priv->nameservers->len); - - g_array_remove_index(priv->nameservers, i); - _notify(self, PROP_NAMESERVERS); -} - -guint -nm_ip6_config_get_num_nameservers(const NMIP6Config *self) -{ - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - return priv->nameservers->len; -} - -const struct in6_addr * -nm_ip6_config_get_nameserver(const NMIP6Config *self, guint i) -{ - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - return &g_array_index(priv->nameservers, struct in6_addr, i); -} - -/*****************************************************************************/ - -void -nm_ip6_config_reset_domains(NMIP6Config *self) -{ - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - if (priv->domains->len != 0) { - g_ptr_array_set_size(priv->domains, 0); - _notify(self, PROP_DOMAINS); - } -} - -void -nm_ip6_config_add_domain(NMIP6Config *self, const char *domain) -{ - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - if (_nm_ip_config_check_and_add_domain(priv->domains, domain)) - _notify(self, PROP_DOMAINS); -} - -void -nm_ip6_config_del_domain(NMIP6Config *self, guint i) -{ - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - g_return_if_fail(i < priv->domains->len); - - g_ptr_array_remove_index(priv->domains, i); - _notify(self, PROP_DOMAINS); -} - -guint -nm_ip6_config_get_num_domains(const NMIP6Config *self) -{ - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - return priv->domains->len; -} - -const char * -nm_ip6_config_get_domain(const NMIP6Config *self, guint i) -{ - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - return g_ptr_array_index(priv->domains, i); -} - -/*****************************************************************************/ - -void -nm_ip6_config_reset_searches(NMIP6Config *self) -{ - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - if (priv->searches->len != 0) { - g_ptr_array_set_size(priv->searches, 0); - _notify(self, PROP_SEARCHES); - } -} - -void -nm_ip6_config_add_search(NMIP6Config *self, const char *search) -{ - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - if (_nm_ip_config_check_and_add_domain(priv->searches, search)) - _notify(self, PROP_SEARCHES); -} - -void -nm_ip6_config_del_search(NMIP6Config *self, guint i) -{ - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - g_return_if_fail(i < priv->searches->len); - - g_ptr_array_remove_index(priv->searches, i); - _notify(self, PROP_SEARCHES); -} - -guint -nm_ip6_config_get_num_searches(const NMIP6Config *self) -{ - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - return priv->searches->len; -} - -const char * -nm_ip6_config_get_search(const NMIP6Config *self, guint i) -{ - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - return g_ptr_array_index(priv->searches, i); -} - -/*****************************************************************************/ - -void -nm_ip6_config_reset_dns_options(NMIP6Config *self) -{ - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - if (priv->dns_options->len != 0) { - g_ptr_array_set_size(priv->dns_options, 0); - _notify(self, PROP_DNS_OPTIONS); - } -} - -void -nm_ip6_config_add_dns_option(NMIP6Config *self, const char *new) -{ - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - int i; - - g_return_if_fail(new != NULL); - g_return_if_fail(new[0] != '\0'); - - for (i = 0; i < priv->dns_options->len; i++) - if (!g_strcmp0(g_ptr_array_index(priv->dns_options, i), new)) - return; - - g_ptr_array_add(priv->dns_options, g_strdup(new)); - _notify(self, PROP_DNS_OPTIONS); -} - -void -nm_ip6_config_del_dns_option(NMIP6Config *self, guint i) -{ - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - g_return_if_fail(i < priv->dns_options->len); - - g_ptr_array_remove_index(priv->dns_options, i); - _notify(self, PROP_DNS_OPTIONS); -} - -guint -nm_ip6_config_get_num_dns_options(const NMIP6Config *self) -{ - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - return priv->dns_options->len; -} - -const char * -nm_ip6_config_get_dns_option(const NMIP6Config *self, guint i) -{ - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - return g_ptr_array_index(priv->dns_options, i); -} - -/*****************************************************************************/ - -NMIPConfigFlags -nm_ip6_config_get_config_flags(const NMIP6Config *self) -{ - return NM_IP6_CONFIG_GET_PRIVATE(self)->config_flags; -} - -void -nm_ip6_config_set_config_flags(NMIP6Config *self, NMIPConfigFlags flags, NMIPConfigFlags mask) -{ - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - if (mask == 0) { - /* for convenience, accept 0 mask to set any flags. */ - mask = flags; - } - - nm_assert(!NM_FLAGS_ANY(flags, ~mask)); - priv->config_flags = (flags & mask) | (priv->config_flags & ~mask); -} - -/*****************************************************************************/ - -void -nm_ip6_config_set_dns_priority(NMIP6Config *self, int priority) -{ - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - if (priority != priv->dns_priority) { - priv->dns_priority = priority; - _notify(self, PROP_DNS_PRIORITY); - } -} - -int -nm_ip6_config_get_dns_priority(const NMIP6Config *self) -{ - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - return priv->dns_priority; -} - -/*****************************************************************************/ - -const NMPObject * -nm_ip6_config_nmpobj_lookup(const NMIP6Config *self, const NMPObject *needle) -{ - const NMIP6ConfigPrivate * priv; - const NMDedupMultiIdxType *idx_type; - - g_return_val_if_fail(NM_IS_IP6_CONFIG(self), NULL); - - priv = NM_IP6_CONFIG_GET_PRIVATE(self); - switch (NMP_OBJECT_GET_TYPE(needle)) { - case NMP_OBJECT_TYPE_IP6_ADDRESS: - idx_type = &priv->idx_ip6_addresses; - break; - case NMP_OBJECT_TYPE_IP6_ROUTE: - idx_type = &priv->idx_ip6_routes; - break; - default: - g_return_val_if_reached(NULL); - } - - return nm_dedup_multi_entry_get_obj( - nm_dedup_multi_index_lookup_obj(priv->multi_idx, idx_type, needle)); -} - -gboolean -nm_ip6_config_nmpobj_remove(NMIP6Config *self, const NMPObject *needle) -{ - NMIP6ConfigPrivate * priv; - NMDedupMultiIdxType *idx_type; - nm_auto_nmpobj const NMPObject *obj_old = NULL; - guint n; - - g_return_val_if_fail(NM_IS_IP6_CONFIG(self), FALSE); - - priv = NM_IP6_CONFIG_GET_PRIVATE(self); - switch (NMP_OBJECT_GET_TYPE(needle)) { - case NMP_OBJECT_TYPE_IP6_ADDRESS: - idx_type = &priv->idx_ip6_addresses; - break; - case NMP_OBJECT_TYPE_IP6_ROUTE: - idx_type = &priv->idx_ip6_routes; - break; - default: - g_return_val_if_reached(FALSE); - } - - n = nm_dedup_multi_index_remove_obj(priv->multi_idx, - idx_type, - needle, - (gconstpointer *) &obj_old); - if (n != 1) { - nm_assert(n == 0); - return FALSE; - } - - nm_assert(NMP_OBJECT_GET_TYPE(obj_old) == NMP_OBJECT_GET_TYPE(needle)); - - switch (NMP_OBJECT_GET_TYPE(obj_old)) { - case NMP_OBJECT_TYPE_IP6_ADDRESS: - _notify_addresses(self); - break; - case NMP_OBJECT_TYPE_IP6_ROUTE: - if (priv->best_default_route == obj_old) { - if (nmp_object_ref_set(&priv->best_default_route, - _nm_ip6_config_best_default_route_find(self))) - _notify(self, PROP_GATEWAY); - } - _notify_routes(self); - break; - default: - nm_assert_not_reached(); - } - return TRUE; -} - -/*****************************************************************************/ - -static void -hash_u32(GChecksum *sum, guint32 n) -{ - g_checksum_update(sum, (const guint8 *) &n, sizeof(n)); -} - -static void -hash_in6addr(GChecksum *sum, const struct in6_addr *a) -{ - if (a) - g_checksum_update(sum, (const guint8 *) a, sizeof(*a)); - else - g_checksum_update(sum, (const guint8 *) &in6addr_any, sizeof(in6addr_any)); -} - -void -nm_ip6_config_hash(const NMIP6Config *self, GChecksum *sum, gboolean dns_only) -{ - guint32 i; - const char * s; - NMDedupMultiIter ipconf_iter; - const NMPlatformIP6Address *address; - const NMPlatformIP6Route * route; - - g_return_if_fail(self); - g_return_if_fail(sum); - - if (dns_only == FALSE) { - nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, self, &address) { - hash_in6addr(sum, &address->address); - hash_u32(sum, address->plen); - } - - nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, self, &route) { - hash_in6addr(sum, &route->network); - hash_u32(sum, route->plen); - hash_in6addr(sum, &route->gateway); - hash_u32(sum, route->metric); - } - } - - for (i = 0; i < nm_ip6_config_get_num_nameservers(self); i++) - hash_in6addr(sum, nm_ip6_config_get_nameserver(self, i)); - - for (i = 0; i < nm_ip6_config_get_num_domains(self); i++) { - s = nm_ip6_config_get_domain(self, i); - g_checksum_update(sum, (const guint8 *) s, strlen(s)); - } - - for (i = 0; i < nm_ip6_config_get_num_searches(self); i++) { - s = nm_ip6_config_get_search(self, i); - g_checksum_update(sum, (const guint8 *) s, strlen(s)); - } - - for (i = 0; i < nm_ip6_config_get_num_dns_options(self); i++) { - s = nm_ip6_config_get_dns_option(self, i); - g_checksum_update(sum, (const guint8 *) s, strlen(s)); - } -} - -/** - * nm_ip6_config_equal: - * @a: first config to compare - * @b: second config to compare - * - * Compares two #NMIP6Configs for basic equality. This means that all - * attributes must exist in the same order in both configs (addresses, routes, - * domains, DNS servers, etc) but some attributes (address lifetimes, and address - * and route sources) are ignored. - * - * Returns: %TRUE if the configurations are basically equal to each other, - * %FALSE if not - */ -gboolean -nm_ip6_config_equal(const NMIP6Config *a, const NMIP6Config *b) -{ - nm_auto_free_checksum GChecksum *a_checksum = g_checksum_new(G_CHECKSUM_SHA1); - nm_auto_free_checksum GChecksum *b_checksum = g_checksum_new(G_CHECKSUM_SHA1); - guint8 a_data[NM_UTILS_CHECKSUM_LENGTH_SHA1]; - guint8 b_data[NM_UTILS_CHECKSUM_LENGTH_SHA1]; - - if (a) - nm_ip6_config_hash(a, a_checksum, FALSE); - if (b) - nm_ip6_config_hash(b, b_checksum, FALSE); - - nm_utils_checksum_get_digest(a_checksum, a_data); - nm_utils_checksum_get_digest(b_checksum, b_data); - return !memcmp(a_data, b_data, sizeof(a_data)); -} - -/*****************************************************************************/ - -static void -nameservers_to_gvalue(GArray *array, GValue *value) -{ - GVariantBuilder builder; - guint i = 0; - - g_variant_builder_init(&builder, G_VARIANT_TYPE("aay")); - - while (array && (i < array->len)) { - struct in6_addr *addr; - - addr = &g_array_index(array, struct in6_addr, i++); - g_variant_builder_add(&builder, "@ay", nm_g_variant_new_ay_in6addr(addr)); - } - - g_value_take_variant(value, g_variant_builder_end(&builder)); -} - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMIP6Config * self = NM_IP6_CONFIG(object); - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - switch (prop_id) { - case PROP_IFINDEX: - g_value_set_int(value, priv->ifindex); - break; - case PROP_ADDRESS_DATA: - case PROP_ADDRESSES: - nm_assert(!!priv->address_data_variant == !!priv->addresses_variant); - - if (!priv->address_data_variant) { - nm_utils_ip_addresses_to_dbus(AF_INET6, - nm_ip6_config_lookup_addresses(self), - priv->best_default_route, - priv->privacy, - &priv->address_data_variant, - &priv->addresses_variant); - g_variant_ref_sink(priv->address_data_variant); - g_variant_ref_sink(priv->addresses_variant); - } - g_value_set_variant(value, - prop_id == PROP_ADDRESS_DATA ? priv->address_data_variant - : priv->addresses_variant); - break; - - case PROP_ROUTE_DATA: - case PROP_ROUTES: - nm_assert(!!priv->route_data_variant == !!priv->routes_variant); - - if (!priv->route_data_variant) { - nm_utils_ip_routes_to_dbus(AF_INET6, - nm_ip6_config_lookup_routes(self), - &priv->route_data_variant, - &priv->routes_variant); - g_variant_ref_sink(priv->route_data_variant); - g_variant_ref_sink(priv->routes_variant); - } - - g_value_set_variant(value, - prop_id == PROP_ROUTE_DATA ? priv->route_data_variant - : priv->routes_variant); - break; - case PROP_GATEWAY: - if (priv->best_default_route) { - g_value_take_string(value, - nm_utils_inet6_ntop_dup( - &NMP_OBJECT_CAST_IP6_ROUTE(priv->best_default_route)->gateway)); - } else - g_value_set_string(value, NULL); - break; - case PROP_NAMESERVERS: - nameservers_to_gvalue(priv->nameservers, value); - break; - case PROP_DOMAINS: - nm_utils_g_value_set_strv(value, priv->domains); - break; - case PROP_SEARCHES: - nm_utils_g_value_set_strv(value, priv->searches); - break; - case PROP_DNS_OPTIONS: - nm_utils_g_value_set_strv(value, priv->dns_options); - break; - case PROP_DNS_PRIORITY: - g_value_set_int(value, priv->dns_priority); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - NMIP6Config * self = NM_IP6_CONFIG(object); - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - switch (prop_id) { - case PROP_MULTI_IDX: - /* construct-only */ - priv->multi_idx = g_value_get_pointer(value); - if (!priv->multi_idx) - g_return_if_reached(); - nm_dedup_multi_index_ref(priv->multi_idx); - break; - case PROP_IFINDEX: - /* construct-only */ - priv->ifindex = g_value_get_int(value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_ip6_config_init(NMIP6Config *self) -{ - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - nm_ip_config_dedup_multi_idx_type_init((NMIPConfigDedupMultiIdxType *) &priv->idx_ip6_addresses, - NMP_OBJECT_TYPE_IP6_ADDRESS); - nm_ip_config_dedup_multi_idx_type_init((NMIPConfigDedupMultiIdxType *) &priv->idx_ip6_routes, - NMP_OBJECT_TYPE_IP6_ROUTE); - - priv->nameservers = g_array_new(FALSE, TRUE, sizeof(struct in6_addr)); - priv->domains = g_ptr_array_new_with_free_func(g_free); - priv->searches = g_ptr_array_new_with_free_func(g_free); - priv->dns_options = g_ptr_array_new_with_free_func(g_free); -} - -NMIP6Config * -nm_ip6_config_new(NMDedupMultiIndex *multi_idx, int ifindex) -{ - g_return_val_if_fail(ifindex >= -1, NULL); - return g_object_new(NM_TYPE_IP6_CONFIG, - NM_IP6_CONFIG_MULTI_IDX, - multi_idx, - NM_IP6_CONFIG_IFINDEX, - ifindex, - NULL); -} - -NMIP6Config * -nm_ip6_config_new_cloned(const NMIP6Config *src) -{ - NMIP6Config *new; - - g_return_val_if_fail(NM_IS_IP6_CONFIG(src), NULL); - - new = nm_ip6_config_new(nm_ip6_config_get_multi_idx(src), nm_ip6_config_get_ifindex(src)); - nm_ip6_config_replace(new, src, NULL); - return new; -} - -static void -finalize(GObject *object) -{ - NMIP6Config * self = NM_IP6_CONFIG(object); - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE(self); - - nm_clear_nmp_object(&priv->best_default_route); - - nm_dedup_multi_index_remove_idx(priv->multi_idx, &priv->idx_ip6_addresses); - nm_dedup_multi_index_remove_idx(priv->multi_idx, &priv->idx_ip6_routes); - - nm_clear_g_variant(&priv->address_data_variant); - nm_clear_g_variant(&priv->addresses_variant); - nm_clear_g_variant(&priv->route_data_variant); - nm_clear_g_variant(&priv->routes_variant); - - g_array_unref(priv->nameservers); - g_ptr_array_unref(priv->domains); - g_ptr_array_unref(priv->searches); - g_ptr_array_unref(priv->dns_options); - - G_OBJECT_CLASS(nm_ip6_config_parent_class)->finalize(object); - - nm_dedup_multi_index_unref(priv->multi_idx); -} - -static const NMDBusInterfaceInfoExtended interface_info_ip6_config = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_IP6_CONFIG, - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - 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 -nm_ip6_config_class_init(NMIP6ConfigClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMIPConfigClass * ip_config_class = NM_IP_CONFIG_CLASS(klass); - - ip_config_class->is_ipv4 = FALSE; - ip_config_class->addr_family = AF_INET6; - - dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED(NM_DBUS_PATH "/IP6Config"); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_ip6_config); - - object_class->get_property = get_property; - object_class->set_property = set_property; - object_class->finalize = finalize; - - obj_properties[PROP_MULTI_IDX] = - g_param_spec_pointer(NM_IP6_CONFIG_MULTI_IDX, - "", - "", - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_IFINDEX] = - g_param_spec_int(NM_IP6_CONFIG_IFINDEX, - "", - "", - -1, - G_MAXINT, - -1, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_ADDRESS_DATA] = - g_param_spec_variant(NM_IP6_CONFIG_ADDRESS_DATA, - "", - "", - G_VARIANT_TYPE("aa{sv}"), - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_ADDRESSES] = - g_param_spec_variant(NM_IP6_CONFIG_ADDRESSES, - "", - "", - G_VARIANT_TYPE("a(ayuay)"), - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_ROUTE_DATA] = - g_param_spec_variant(NM_IP6_CONFIG_ROUTE_DATA, - "", - "", - G_VARIANT_TYPE("aa{sv}"), - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_ROUTES] = g_param_spec_variant(NM_IP6_CONFIG_ROUTES, - "", - "", - G_VARIANT_TYPE("a(ayuayu)"), - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_GATEWAY] = g_param_spec_string(NM_IP6_CONFIG_GATEWAY, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_NAMESERVERS] = - g_param_spec_variant(NM_IP6_CONFIG_NAMESERVERS, - "", - "", - G_VARIANT_TYPE("aay"), - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_DOMAINS] = g_param_spec_boxed(NM_IP6_CONFIG_DOMAINS, - "", - "", - G_TYPE_STRV, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_SEARCHES] = g_param_spec_boxed(NM_IP6_CONFIG_SEARCHES, - "", - "", - G_TYPE_STRV, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_DNS_OPTIONS] = - g_param_spec_boxed(NM_IP6_CONFIG_DNS_OPTIONS, - "", - "", - G_TYPE_STRV, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_DNS_PRIORITY] = g_param_spec_int(NM_IP6_CONFIG_DNS_PRIORITY, - "", - "", - G_MININT32, - G_MAXINT32, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} diff --git a/src/core/nm-ip6-config.h b/src/core/nm-ip6-config.h deleted file mode 100644 index 4aa0ee4e58..0000000000 --- a/src/core/nm-ip6-config.h +++ /dev/null @@ -1,208 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2008 - 2013 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_IP6_CONFIG_H__ -#define __NETWORKMANAGER_IP6_CONFIG_H__ - -#include - -#include "nm-setting-ip6-config.h" - -#include "libnm-glib-aux/nm-dedup-multi.h" -#include "libnm-platform/nmp-object.h" -#include "nm-ip-config.h" - -/*****************************************************************************/ - -void nm_ip_config_iter_ip6_address_init(NMDedupMultiIter *iter, const NMIP6Config *self); -void nm_ip_config_iter_ip6_route_init(NMDedupMultiIter *iter, const NMIP6Config *self); - -#define nm_ip_config_iter_ip6_address_for_each(iter, self, address) \ - for (nm_ip_config_iter_ip6_address_init((iter), (self)); \ - nm_platform_dedup_multi_iter_next_ip6_address((iter), (address));) - -#define nm_ip_config_iter_ip6_route_for_each(iter, self, route) \ - for (nm_ip_config_iter_ip6_route_init((iter), (self)); \ - nm_platform_dedup_multi_iter_next_ip6_route((iter), (route));) - -/*****************************************************************************/ - -#define NM_TYPE_IP6_CONFIG (nm_ip6_config_get_type()) -#define NM_IP6_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_IP6_CONFIG, NMIP6Config)) -#define NM_IP6_CONFIG_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_IP6_CONFIG, NMIP6ConfigClass)) -#define NM_IS_IP6_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_IP6_CONFIG)) -#define NM_IS_IP6_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_IP6_CONFIG)) -#define NM_IP6_CONFIG_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_IP6_CONFIG, NMIP6ConfigClass)) - -typedef struct _NMIP6ConfigClass NMIP6ConfigClass; - -/* internal */ -#define NM_IP6_CONFIG_MULTI_IDX "multi-idx" -#define NM_IP6_CONFIG_IFINDEX "ifindex" - -/* public */ -#define NM_IP6_CONFIG_ADDRESS_DATA "address-data" -#define NM_IP6_CONFIG_ROUTE_DATA "route-data" -#define NM_IP6_CONFIG_GATEWAY "gateway" -#define NM_IP6_CONFIG_NAMESERVERS "nameservers" -#define NM_IP6_CONFIG_DOMAINS "domains" -#define NM_IP6_CONFIG_SEARCHES "searches" -#define NM_IP6_CONFIG_DNS_OPTIONS "dns-options" -#define NM_IP6_CONFIG_DNS_PRIORITY "dns-priority" - -/* deprecated */ -#define NM_IP6_CONFIG_ADDRESSES "addresses" -#define NM_IP6_CONFIG_ROUTES "routes" - -GType nm_ip6_config_get_type(void); - -NMIP6Config *nm_ip6_config_new(struct _NMDedupMultiIndex *multi_idx, int ifindex); -NMIP6Config *nm_ip6_config_new_cloned(const NMIP6Config *src); - -NMIP6Config *nm_ip6_config_clone(const NMIP6Config *self); -int nm_ip6_config_get_ifindex(const NMIP6Config *self); - -struct _NMDedupMultiIndex *nm_ip6_config_get_multi_idx(const NMIP6Config *self); - -NMIP6Config *nm_ip6_config_capture(struct _NMDedupMultiIndex *multi_idx, - NMPlatform * platform, - int ifindex, - NMSettingIP6ConfigPrivacy use_temporary); - -void nm_ip6_config_add_dependent_routes(NMIP6Config *self, - guint32 route_table, - guint32 route_metric, - gboolean is_vrf); - -gboolean nm_ip6_config_commit(const NMIP6Config * self, - NMPlatform * platform, - NMIPRouteTableSyncMode route_table_sync, - GPtrArray ** out_temporary_not_available); -void nm_ip6_config_merge_setting(NMIP6Config * self, - NMSettingIPConfig *setting, - guint32 route_table, - guint32 route_metric); -NMSetting *nm_ip6_config_create_setting(const NMIP6Config *self, gboolean maybe_ipv6_disabled); - -void nm_ip6_config_merge(NMIP6Config * dst, - const NMIP6Config * src, - NMIPConfigMergeFlags merge_flags, - guint32 default_route_metric_penalty); -void nm_ip6_config_subtract(NMIP6Config * dst, - const NMIP6Config *src, - guint32 default_route_metric_penalty); -void nm_ip6_config_intersect(NMIP6Config * dst, - const NMIP6Config *src, - gboolean intersect_addresses, - gboolean intersect_routes, - guint32 default_route_metric_penalty); -NMIP6Config *nm_ip6_config_intersect_alloc(const NMIP6Config *a, - const NMIP6Config *b, - gboolean intersect_addresses, - gboolean intersect_routes, - guint32 default_route_metric_penalty); -gboolean -nm_ip6_config_replace(NMIP6Config *dst, const NMIP6Config *src, gboolean *relevant_changes); - -const NMPObject *nm_ip6_config_best_default_route_get(const NMIP6Config *self); -const NMPObject *_nm_ip6_config_best_default_route_find(const NMIP6Config *self); - -enum _NMIPConfigFlags; - -void nm_ip6_config_set_config_flags(NMIP6Config * self, - enum _NMIPConfigFlags flags, - enum _NMIPConfigFlags mask); -enum _NMIPConfigFlags nm_ip6_config_get_config_flags(const NMIP6Config *self); - -const NMDedupMultiHeadEntry *nm_ip6_config_lookup_addresses(const NMIP6Config *self); -void nm_ip6_config_reset_addresses(NMIP6Config *self); -void nm_ip6_config_add_address(NMIP6Config *self, const NMPlatformIP6Address *address); -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); -gboolean _nmtst_ip6_config_addresses_sort(NMIP6Config *self); -gboolean nm_ip6_config_has_any_dad_pending(const NMIP6Config *self, const NMIP6Config *candidates); - -const NMDedupMultiHeadEntry *nm_ip6_config_lookup_routes(const NMIP6Config *self); -void nm_ip6_config_reset_routes(NMIP6Config *self); -void nm_ip6_config_add_route(NMIP6Config * self, - const NMPlatformIP6Route *route, - const NMPObject ** out_obj_new); -void _nmtst_ip6_config_del_route(NMIP6Config *self, guint i); -guint nm_ip6_config_get_num_routes(const NMIP6Config *self); -const NMPlatformIP6Route * _nmtst_ip6_config_get_route(const NMIP6Config *self, guint i); - -const NMPlatformIP6Route * nm_ip6_config_get_direct_route_for_host(const NMIP6Config * self, - const struct in6_addr *host, - guint32 route_table); -const NMPlatformIP6Address *nm_ip6_config_get_subnet_for_host(const NMIP6Config * self, - const struct in6_addr *host); - -void nm_ip6_config_reset_nameservers(NMIP6Config *self); -void nm_ip6_config_add_nameserver(NMIP6Config *self, const struct in6_addr *nameserver); -void nm_ip6_config_del_nameserver(NMIP6Config *self, guint i); -guint nm_ip6_config_get_num_nameservers(const NMIP6Config *self); -const struct in6_addr *nm_ip6_config_get_nameserver(const NMIP6Config *self, guint i); - -void nm_ip6_config_reset_domains(NMIP6Config *self); -void nm_ip6_config_add_domain(NMIP6Config *self, const char *domain); -void nm_ip6_config_del_domain(NMIP6Config *self, guint i); -guint nm_ip6_config_get_num_domains(const NMIP6Config *self); -const char *nm_ip6_config_get_domain(const NMIP6Config *self, guint i); - -void nm_ip6_config_reset_searches(NMIP6Config *self); -void nm_ip6_config_add_search(NMIP6Config *self, const char *search); -void nm_ip6_config_del_search(NMIP6Config *self, guint i); -guint nm_ip6_config_get_num_searches(const NMIP6Config *self); -const char *nm_ip6_config_get_search(const NMIP6Config *self, guint i); - -void nm_ip6_config_reset_dns_options(NMIP6Config *self); -void nm_ip6_config_add_dns_option(NMIP6Config *self, const char *option); -void nm_ip6_config_del_dns_option(NMIP6Config *self, guint i); -guint nm_ip6_config_get_num_dns_options(const NMIP6Config *self); -const char *nm_ip6_config_get_dns_option(const NMIP6Config *self, guint i); - -void nm_ip6_config_set_dns_priority(NMIP6Config *self, int priority); -int nm_ip6_config_get_dns_priority(const NMIP6Config *self); - -void nm_ip6_config_set_never_default(NMIP6Config *self, gboolean never_default); -gboolean nm_ip6_config_get_never_default(const NMIP6Config *self); - -const NMPObject *nm_ip6_config_nmpobj_lookup(const NMIP6Config *self, const NMPObject *needle); -gboolean nm_ip6_config_nmpobj_remove(NMIP6Config *self, const NMPObject *needle); - -void nm_ip6_config_hash(const NMIP6Config *self, GChecksum *sum, gboolean dns_only); -gboolean nm_ip6_config_equal(const NMIP6Config *a, const NMIP6Config *b); - -void nm_ip6_config_set_privacy(NMIP6Config *self, NMSettingIP6ConfigPrivacy privacy); - -struct _NMNDiscAddress; -void nm_ip6_config_reset_addresses_ndisc(NMIP6Config * self, - const struct _NMNDiscAddress *addresses, - guint addresses_n, - guint8 plen, - guint32 ifa_flags); -struct _NMNDiscRoute; -struct _NMNDiscGateway; -void nm_ip6_config_reset_routes_ndisc(NMIP6Config * self, - const struct _NMNDiscGateway *gateways, - guint gateways_n, - const struct _NMNDiscRoute * routes, - guint routes_n, - guint32 route_table, - guint32 route_metric, - gboolean kernel_support_rta_pref); - -void nm_ip6_config_update_routes_metric(NMIP6Config *self, gint64 metric); - -#endif /* __NETWORKMANAGER_IP6_CONFIG_H__ */ diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c index 419ce88dfe..35e95d0c21 100644 --- a/src/core/nm-manager.c +++ b/src/core/nm-manager.c @@ -2605,8 +2605,6 @@ get_existing_connection(NMManager *self, NMDevice *device, gboolean *out_generat if (out_generated) *out_generated = FALSE; - nm_device_capture_initial_config(device); - if (ifindex) { int master_ifindex = nm_platform_link_get_master(priv->platform, ifindex); diff --git a/src/core/nm-pacrunner-manager.c b/src/core/nm-pacrunner-manager.c index 67930dbae0..acf9269eb9 100644 --- a/src/core/nm-pacrunner-manager.c +++ b/src/core/nm-pacrunner-manager.c @@ -7,15 +7,14 @@ #include "nm-pacrunner-manager.h" -#include "nm-utils.h" -#include "NetworkManagerUtils.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 "libnm-glib-aux/nm-dbus-aux.h" +#include "libnm-platform/nm-platform.h" + +#include "NetworkManagerUtils.h" +#include "nm-dbus-manager.h" +#include "nm-l3-config-data.h" +#include "nm-utils.h" #define PACRUNNER_DBUS_SERVICE "org.pacrunner" #define PACRUNNER_DBUS_INTERFACE "org.pacrunner.Manager" @@ -124,58 +123,50 @@ NM_AUTO_DEFINE_FCN0(NMPacrunnerConfId *, _nm_auto_unref_conf_id, conf_id_unref); /*****************************************************************************/ static void -get_ip_domains(GPtrArray *domains, NMIPConfig *ip_config) +get_ip_domains(GPtrArray *domains, const NML3ConfigData *l3cd, int addr_family) { NMDedupMultiIter ipconf_iter; char * cidr; - guint i, num; + guint num; + guint i; char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - int addr_family; const NMPlatformIPAddress *address; - const NMPlatformIPRoute * routes; - - if (!ip_config) - return; + const NMPlatformIPRoute * route; + const char *const * strv; - addr_family = nm_ip_config_get_addr_family(ip_config); - - num = nm_ip_config_get_num_searches(ip_config); + strv = nm_l3_config_data_get_searches(l3cd, addr_family, &num); for (i = 0; i < num; i++) - g_ptr_array_add(domains, g_strdup(nm_ip_config_get_search(ip_config, i))); + g_ptr_array_add(domains, g_strdup(strv[i])); - num = nm_ip_config_get_num_domains(ip_config); + strv = nm_l3_config_data_get_domains(l3cd, addr_family, &num); for (i = 0; i < num; i++) - g_ptr_array_add(domains, g_strdup(nm_ip_config_get_domain(ip_config, i))); + g_ptr_array_add(domains, g_strdup(strv[i])); - nm_ip_config_iter_ip_address_for_each (&ipconf_iter, ip_config, &address) { + nm_l3_config_data_iter_ip_address_for_each (&ipconf_iter, l3cd, addr_family, &address) { cidr = g_strdup_printf("%s/%u", nm_utils_inet_ntop(addr_family, address->address_ptr, sbuf), address->plen); g_ptr_array_add(domains, cidr); } - nm_ip_config_iter_ip_route_for_each (&ipconf_iter, ip_config, &routes) { - if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(routes)) + nm_l3_config_data_iter_ip_route_for_each (&ipconf_iter, l3cd, addr_family, &route) { + if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(route)) continue; cidr = g_strdup_printf("%s/%u", - nm_utils_inet_ntop(addr_family, routes->network_ptr, sbuf), - routes->plen); + nm_utils_inet_ntop(addr_family, route->network_ptr, sbuf), + route->plen); g_ptr_array_add(domains, cidr); } } static GVariant * -_make_request_create_proxy_configuration(NMProxyConfig *proxy_config, - const char * iface, - NMIP4Config * ip4_config, - NMIP6Config * ip6_config) +_make_request_create_proxy_configuration(const char *iface, const NML3ConfigData *l3cd) { GVariantBuilder builder; NMProxyConfigMethod method; - const char * pac_url; - const char * pac_script; + const char * s; - nm_assert(NM_IS_PROXY_CONFIG(proxy_config)); + nm_assert(NM_IS_L3_CONFIG_DATA(l3cd)); g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); @@ -183,20 +174,18 @@ _make_request_create_proxy_configuration(NMProxyConfig *proxy_config, g_variant_builder_add(&builder, "{sv}", "Interface", g_variant_new_string(iface)); } - method = nm_proxy_config_get_method(proxy_config); + method = nm_l3_config_data_get_proxy_method(l3cd); switch (method) { case NM_PROXY_CONFIG_METHOD_AUTO: g_variant_builder_add(&builder, "{sv}", "Method", g_variant_new_string("auto")); - pac_url = nm_proxy_config_get_pac_url(proxy_config); - if (pac_url) { - g_variant_builder_add(&builder, "{sv}", "URL", g_variant_new_string(pac_url)); - } + s = nm_l3_config_data_get_proxy_pac_url(l3cd); + if (s) + g_variant_builder_add(&builder, "{sv}", "URL", g_variant_new_string(s)); - pac_script = nm_proxy_config_get_pac_script(proxy_config); - if (pac_script) { - g_variant_builder_add(&builder, "{sv}", "Script", g_variant_new_string(pac_script)); - } + s = nm_l3_config_data_get_proxy_pac_script(l3cd); + if (s) + g_variant_builder_add(&builder, "{sv}", "Script", g_variant_new_string(s)); break; case NM_PROXY_CONFIG_METHOD_UNKNOWN: case NM_PROXY_CONFIG_METHOD_NONE: @@ -207,15 +196,15 @@ _make_request_create_proxy_configuration(NMProxyConfig *proxy_config, g_variant_builder_add(&builder, "{sv}", "BrowserOnly", - g_variant_new_boolean(nm_proxy_config_get_browser_only(proxy_config))); + g_variant_new_boolean(!!nm_l3_config_data_get_proxy_browser_only(l3cd))); - if (ip4_config || ip6_config) { + if (l3cd) { gs_unref_ptrarray GPtrArray *domains = NULL; domains = g_ptr_array_new_with_free_func(g_free); - get_ip_domains(domains, NM_IP_CONFIG_CAST(ip4_config)); - get_ip_domains(domains, NM_IP_CONFIG_CAST(ip6_config)); + get_ip_domains(domains, l3cd, AF_INET); + get_ip_domains(domains, l3cd, AF_INET6); if (domains->len > 0) { g_variant_builder_add( @@ -356,10 +345,8 @@ _try_start_service_by_name(NMPacrunnerManager *self) /** * nm_pacrunner_manager_add: * @self: the #NMPacrunnerManager - * @proxy_config: proxy config of the connection * @iface: the iface for the connection or %NULL - * @ip4_config: IP4 config of the connection to extract domain info from - * @ip6_config: IP6 config of the connection to extract domain info from + * @l3cd: the #NML3ConfigData of the connection to extract domain info from * * Returns: a #NMPacrunnerConfId id. The function cannot * fail and always returns a non NULL pointer. The conf-id may @@ -367,18 +354,14 @@ _try_start_service_by_name(NMPacrunnerManager *self) * Note that the conf-id keeps the @self instance alive. */ NMPacrunnerConfId * -nm_pacrunner_manager_add(NMPacrunnerManager *self, - NMProxyConfig * proxy_config, - const char * iface, - NMIP4Config * ip4_config, - NMIP6Config * ip6_config) +nm_pacrunner_manager_add(NMPacrunnerManager *self, const char *iface, const NML3ConfigData *l3cd) { NMPacrunnerManagerPrivate *priv; NMPacrunnerConfId * conf_id; gs_free char * log_msg = NULL; g_return_val_if_fail(NM_IS_PACRUNNER_MANAGER(self), NULL); - g_return_val_if_fail(proxy_config, NULL); + g_return_val_if_fail(NM_IS_L3_CONFIG_DATA(l3cd), NULL); priv = NM_PACRUNNER_MANAGER_GET_PRIVATE(self); @@ -387,8 +370,7 @@ nm_pacrunner_manager_add(NMPacrunnerManager *self, .log_id = ++priv->log_id_counter, .refcount = 1, .self = g_object_ref(self), - .parameters = g_variant_ref_sink( - _make_request_create_proxy_configuration(proxy_config, iface, ip4_config, ip6_config)), + .parameters = g_variant_ref_sink(_make_request_create_proxy_configuration(iface, l3cd)), }; c_list_link_tail(&priv->conf_id_lst_head, &conf_id->conf_id_lst); diff --git a/src/core/nm-pacrunner-manager.h b/src/core/nm-pacrunner-manager.h index fd40f1204d..3f16908f4e 100644 --- a/src/core/nm-pacrunner-manager.h +++ b/src/core/nm-pacrunner-manager.h @@ -26,11 +26,8 @@ GType nm_pacrunner_manager_get_type(void); NMPacrunnerManager *nm_pacrunner_manager_get(void); -NMPacrunnerConfId *nm_pacrunner_manager_add(NMPacrunnerManager *self, - NMProxyConfig * proxy_config, - const char * iface, - NMIP4Config * ip4_config, - NMIP6Config * ip6_config); +NMPacrunnerConfId * +nm_pacrunner_manager_add(NMPacrunnerManager *self, const char *iface, const NML3ConfigData *l3cd); void nm_pacrunner_manager_remove(NMPacrunnerConfId *conf_id); diff --git a/src/core/nm-policy.c b/src/core/nm-policy.c index c2ab9b2d0d..34dfc62abe 100644 --- a/src/core/nm-policy.c +++ b/src/core/nm-policy.c @@ -11,28 +11,31 @@ #include #include +#include "libnm-core-intern/nm-core-internal.h" +#include "libnm-platform/nm-platform.h" +#include "libnm-platform/nmp-object.h" + #include "NetworkManagerUtils.h" -#include "nm-act-request.h" -#include "nm-keep-alive.h" #include "devices/nm-device.h" -#include "nm-setting-ip4-config.h" -#include "nm-setting-connection.h" -#include "libnm-platform/nm-platform.h" #include "dns/nm-dns-manager.h" -#include "vpn/nm-vpn-manager.h" +#include "nm-act-request.h" #include "nm-auth-utils.h" -#include "nm-firewalld-manager.h" +#include "nm-config.h" +#include "nm-dhcp-config.h" #include "nm-dispatcher.h" -#include "nm-utils.h" -#include "libnm-core-intern/nm-core-internal.h" +#include "nm-firewalld-manager.h" +#include "nm-hostname-manager.h" +#include "nm-keep-alive.h" +#include "nm-l3-config-data.h" #include "nm-manager.h" -#include "settings/nm-settings.h" -#include "settings/nm-settings-connection.h" -#include "settings/nm-agent-manager.h" -#include "nm-dhcp-config.h" -#include "nm-config.h" #include "nm-netns.h" -#include "nm-hostname-manager.h" +#include "nm-setting-connection.h" +#include "nm-setting-ip4-config.h" +#include "nm-utils.h" +#include "settings/nm-agent-manager.h" +#include "settings/nm-settings-connection.h" +#include "settings/nm-settings.h" +#include "vpn/nm-vpn-manager.h" /*****************************************************************************/ @@ -136,30 +139,6 @@ static NMDevice *get_default_device(NMPolicy *self, int addr_family); /*****************************************************************************/ -static void -_dns_manager_set_ip_config(NMDnsManager * dns_manager, - NMIPConfig * ip_config, - NMDnsIPConfigType ip_config_type, - NMDevice * device) -{ - if (device && nm_device_sys_iface_state_is_external(device)) { - nm_dns_manager_set_ip_config(dns_manager, ip_config, NM_DNS_IP_CONFIG_TYPE_REMOVED); - return; - } - - if (NM_IN_SET(ip_config_type, NM_DNS_IP_CONFIG_TYPE_DEFAULT, NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE) - && device - && nm_device_get_route_metric_default(nm_device_get_device_type(device)) - == NM_VPN_ROUTE_METRIC_DEFAULT) { - /* some device types are inherently VPN. */ - ip_config_type = NM_DNS_IP_CONFIG_TYPE_VPN; - } - - nm_dns_manager_set_ip_config(dns_manager, ip_config, ip_config_type); -} - -/*****************************************************************************/ - typedef struct { NMPlatformIP6Address prefix; NMDevice * device; /* The requesting ("uplink") device */ @@ -971,7 +950,7 @@ update_default_ac(NMPolicy *self, int addr_family, NMActiveConnection *best) nm_active_connection_set_default(best, addr_family, TRUE); } -static gpointer +static const NML3ConfigData * get_best_ip_config(NMPolicy * self, int addr_family, const char ** out_ip_iface, @@ -979,20 +958,21 @@ get_best_ip_config(NMPolicy * self, NMDevice ** out_device, NMVpnConnection ** out_vpn) { - NMPolicyPrivate * priv = NM_POLICY_GET_PRIVATE(self); - gpointer conf, best_conf = NULL; - const CList * tmp_list; - NMActiveConnection *ac; - guint64 best_metric = G_MAXUINT64; - NMVpnConnection * best_vpn = NULL; + NMPolicyPrivate * priv = NM_POLICY_GET_PRIVATE(self); + const NML3ConfigData *l3cd_best = NULL; + const CList * tmp_list; + NMActiveConnection * ac; + guint64 best_metric = G_MAXUINT64; + NMVpnConnection * best_vpn = NULL; nm_assert(NM_IN_SET(addr_family, AF_INET, AF_INET6)); nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { - NMVpnConnection * candidate; - NMVpnConnectionState vpn_state; - const NMPObject * obj; - guint32 metric; + const NML3ConfigData *l3cd; + NMVpnConnection * candidate; + NMVpnConnectionState vpn_state; + const NMPObject * obj; + guint32 metric; if (!NM_IS_VPN_CONNECTION(ac)) continue; @@ -1003,24 +983,18 @@ get_best_ip_config(NMPolicy * self, if (vpn_state != NM_VPN_CONNECTION_STATE_ACTIVATED) continue; - if (addr_family == AF_INET) - conf = nm_vpn_connection_get_ip4_config(candidate); - else - conf = nm_vpn_connection_get_ip6_config(candidate); - if (!conf) + l3cd = nm_vpn_connection_get_l3cd(candidate, addr_family); + if (!l3cd) continue; - if (addr_family == AF_INET) - obj = nm_ip4_config_best_default_route_get(conf); - else - obj = nm_ip6_config_best_default_route_get(conf); + obj = nm_l3_config_data_get_best_default_route(l3cd, addr_family); if (!obj) continue; metric = NMP_OBJECT_CAST_IPX_ROUTE(obj)->rx.metric; if (metric <= best_metric) { best_metric = metric; - best_conf = conf; + l3cd_best = l3cd; best_vpn = candidate; } } @@ -1030,25 +1004,20 @@ get_best_ip_config(NMPolicy * self, NM_SET_OUT(out_vpn, best_vpn); NM_SET_OUT(out_ac, NM_ACTIVE_CONNECTION(best_vpn)); NM_SET_OUT(out_ip_iface, nm_vpn_connection_get_ip_iface(best_vpn, TRUE)); - return best_conf; + return l3cd_best; } ac = get_best_active_connection(self, addr_family, TRUE); if (ac) { NMDevice *device = nm_active_connection_get_device(ac); - nm_assert(device); - - if (addr_family == AF_INET) - conf = nm_device_get_ip4_config(device); - else - conf = nm_device_get_ip6_config(device); + nm_assert(NM_IS_DEVICE(device)); NM_SET_OUT(out_device, device); NM_SET_OUT(out_vpn, NULL); NM_SET_OUT(out_ac, ac); NM_SET_OUT(out_ip_iface, nm_device_get_ip_iface(device)); - return conf; + return nm_device_get_l3cd(device, TRUE); } NM_SET_OUT(out_device, NULL); @@ -1066,8 +1035,6 @@ update_ip4_routing(NMPolicy *self, gboolean force_update) NMVpnConnection * vpn = NULL; NMActiveConnection *best_ac = NULL; const char * ip_iface = NULL; - const CList * tmp_list; - NMActiveConnection *ac; /* Note that we might have an IPv4 VPN tunneled over an IPv6-only device, * so we can get (vpn != NULL && best == NULL). @@ -1085,11 +1052,11 @@ update_ip4_routing(NMPolicy *self, gboolean force_update) return; if (best) { - nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { - if (NM_IS_VPN_CONNECTION(ac) && nm_vpn_connection_get_ip4_config(NM_VPN_CONNECTION(ac)) - && !nm_active_connection_get_device(ac)) - nm_active_connection_set_device(ac, best); - } + //XXX nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { + //XXX if (NM_IS_VPN_CONNECTION(ac) && nm_vpn_connection_get_ip4_config(NM_VPN_CONNECTION(ac)) + //XXX && !nm_active_connection_get_device(ac)) + //XXX nm_active_connection_set_device(ac, best); + //XXX } } update_default_ac(self, AF_INET, best_ac); @@ -1129,8 +1096,6 @@ update_ip6_routing(NMPolicy *self, gboolean force_update) NMVpnConnection * vpn = NULL; NMActiveConnection *best_ac = NULL; const char * ip_iface = NULL; - NMActiveConnection *ac; - const CList * tmp_list; /* Note that we might have an IPv6 VPN tunneled over an IPv4-only device, * so we can get (vpn != NULL && best == NULL). @@ -1148,11 +1113,11 @@ update_ip6_routing(NMPolicy *self, gboolean force_update) return; if (best) { - nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { - if (NM_IS_VPN_CONNECTION(ac) && nm_vpn_connection_get_ip6_config(NM_VPN_CONNECTION(ac)) - && !nm_active_connection_get_device(ac)) - nm_active_connection_set_device(ac, best); - } + //XXX nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { + //XXX if (NM_IS_VPN_CONNECTION(ac) && nm_vpn_connection_get_ip6_config(NM_VPN_CONNECTION(ac)) + //XXX && !nm_active_connection_get_device(ac)) + //XXX nm_active_connection_set_device(ac, best); + //XXX } } update_default_ac(self, AF_INET6, best_ac); @@ -1173,25 +1138,38 @@ update_ip6_routing(NMPolicy *self, gboolean force_update) static void update_ip_dns(NMPolicy *self, int addr_family, NMDevice *changed_device) { - NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE(self); - gpointer ip_config; - const char * ip_iface = NULL; - NMVpnConnection *vpn = NULL; - NMDevice * device = NULL; + NMPolicyPrivate * priv = NM_POLICY_GET_PRIVATE(self); + const NML3ConfigData *l3cd; + const char * ip_iface = NULL; + NMVpnConnection * vpn = NULL; + NMDevice * device = NULL; nm_assert_addr_family(addr_family); - ip_config = get_best_ip_config(self, addr_family, &ip_iface, NULL, &device, &vpn); - if (ip_config) { + l3cd = get_best_ip_config(self, addr_family, &ip_iface, NULL, &device, &vpn); + if (l3cd) { + NMDnsIPConfigType ip_config_type; + + nm_assert(!device || NM_IS_DEVICE(device)); + nm_assert(!vpn || NM_IS_VPN_CONNECTION(vpn)); + nm_assert((!!device) != (!!vpn)); + /* Tell the DNS manager this config is preferred by re-adding it with * a different IP config type. */ - _dns_manager_set_ip_config(NM_POLICY_GET_PRIVATE(self)->dns_manager, - ip_config, - (vpn || (device && nm_device_is_vpn(device))) - ? NM_DNS_IP_CONFIG_TYPE_VPN - : NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE, - device); + if (device && nm_device_sys_iface_state_is_external(device)) + ip_config_type = NM_DNS_IP_CONFIG_TYPE_REMOVED; + else if (vpn || (device && nm_device_is_vpn(device))) + ip_config_type = NM_DNS_IP_CONFIG_TYPE_VPN; + else + ip_config_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE; + + nm_dns_manager_set_ip_config(NM_POLICY_GET_PRIVATE(self)->dns_manager, + addr_family, + ((gconstpointer) device) ?: ((gconstpointer) vpn), + l3cd, + ip_config_type, + TRUE); } if (addr_family == AF_INET6) { @@ -1906,9 +1884,7 @@ device_state_changed(NMDevice * device, NMPolicy * self = _PRIV_TO_SELF(priv); NMActiveConnection * ac; NMSettingsConnection *sett_conn = nm_device_get_settings_connection(device); - NMIP4Config * ip4_config; - NMIP6Config * ip6_config; - NMSettingConnection * s_con = NULL; + NMSettingConnection * s_con = NULL; switch (nm_device_state_reason_check(reason)) { case NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED: @@ -2010,27 +1986,6 @@ device_state_changed(NMDevice * device, /* Reset auto retries back to default since connection was successful */ nm_settings_connection_autoconnect_retries_reset(sett_conn); } - - /* Add device's new IPv4 and IPv6 configs to DNS */ - - nm_dns_manager_begin_updates(priv->dns_manager, __func__); - - ip4_config = nm_device_get_ip4_config(device); - if (ip4_config) - _dns_manager_set_ip_config(priv->dns_manager, - NM_IP_CONFIG_CAST(ip4_config), - NM_DNS_IP_CONFIG_TYPE_DEFAULT, - device); - ip6_config = nm_device_get_ip6_config(device); - if (ip6_config) - _dns_manager_set_ip_config(priv->dns_manager, - NM_IP_CONFIG_CAST(ip6_config), - NM_DNS_IP_CONFIG_TYPE_DEFAULT, - device); - - update_routing_and_dns(self, FALSE, device); - - nm_dns_manager_end_updates(priv->dns_manager, __func__); break; case NM_DEVICE_STATE_UNMANAGED: case NM_DEVICE_STATE_UNAVAILABLE: @@ -2132,24 +2087,16 @@ device_state_changed(NMDevice * device, } static void -device_ip_config_changed(NMDevice * device, - NMIPConfig *new_config, - NMIPConfig *old_config, - gpointer user_data) +device_l3cd_changed(NMDevice * device, + const NML3ConfigData *l3cd_old, + const NML3ConfigData *l3cd_new, + gpointer user_data) { NMPolicyPrivate *priv = user_data; NMPolicy * self = _PRIV_TO_SELF(priv); - int addr_family; - nm_assert(new_config || old_config); - nm_assert(!new_config || NM_IS_IP_CONFIG(new_config)); - nm_assert(!old_config || NM_IS_IP_CONFIG(old_config)); - - if (new_config) { - addr_family = nm_ip_config_get_addr_family(new_config); - nm_assert(!old_config || addr_family == nm_ip_config_get_addr_family(old_config)); - } else - addr_family = nm_ip_config_get_addr_family(old_config); + nm_assert(!l3cd_new || NM_IS_L3_CONFIG_DATA(l3cd_new)); + nm_assert(!l3cd_old || NM_IS_L3_CONFIG_DATA(l3cd_old)); nm_dns_manager_begin_updates(priv->dns_manager, __func__); @@ -2158,30 +2105,25 @@ device_ip_config_changed(NMDevice * device, * ignore IP config changes but when the device is in activated state. * Prevents unnecessary changes to DNS information. */ - if (nm_device_get_state(device) == NM_DEVICE_STATE_ACTIVATED) { - if (old_config != new_config) { - if (new_config) - _dns_manager_set_ip_config(priv->dns_manager, - new_config, - NM_DNS_IP_CONFIG_TYPE_DEFAULT, - device); - if (old_config) - nm_dns_manager_set_ip_config(priv->dns_manager, - old_config, - NM_DNS_IP_CONFIG_TYPE_REMOVED); - } - update_ip_dns(self, addr_family, device); - if (addr_family == AF_INET) - update_ip4_routing(self, TRUE); - else - update_ip6_routing(self, TRUE); - update_system_hostname(self, addr_family == AF_INET ? "ip4 conf" : "ip6 conf"); + if (nm_device_get_state(device) < NM_DEVICE_STATE_DEACTIVATING) { + nm_dns_manager_set_ip_config(priv->dns_manager, + AF_UNSPEC, + device, + l3cd_new, + NM_DNS_IP_CONFIG_TYPE_DEFAULT, + TRUE); + update_ip_dns(self, AF_INET, device); + update_ip_dns(self, AF_INET6, device); + update_ip4_routing(self, TRUE); + update_ip6_routing(self, TRUE); + update_system_hostname(self, "ip conf"); } else { - /* Old configs get removed immediately */ - if (old_config) - nm_dns_manager_set_ip_config(priv->dns_manager, - old_config, - NM_DNS_IP_CONFIG_TYPE_REMOVED); + nm_dns_manager_set_ip_config(priv->dns_manager, + AF_UNSPEC, + device, + l3cd_old, + NM_DNS_IP_CONFIG_TYPE_REMOVED, + TRUE); } nm_dns_manager_end_updates(priv->dns_manager, __func__); @@ -2222,14 +2164,7 @@ devices_list_register(NMPolicy *self, NMDevice *device) /* Connect state-changed with _after, so that the handler is invoked after other handlers. */ g_signal_connect_after(device, NM_DEVICE_STATE_CHANGED, (GCallback) device_state_changed, priv); - g_signal_connect(device, - NM_DEVICE_IP4_CONFIG_CHANGED, - (GCallback) device_ip_config_changed, - priv); - g_signal_connect(device, - NM_DEVICE_IP6_CONFIG_CHANGED, - (GCallback) device_ip_config_changed, - priv); + g_signal_connect(device, NM_DEVICE_L3CD_CHANGED, (GCallback) device_l3cd_changed, priv); g_signal_connect(device, NM_DEVICE_IP6_PREFIX_DELEGATED, (GCallback) device_ip6_prefix_delegated, @@ -2291,51 +2226,26 @@ device_removed(NMManager *manager, NMDevice *device, gpointer user_data) /*****************************************************************************/ static void -vpn_connection_activated(NMPolicy *self, NMVpnConnection *vpn) -{ - NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE(self); - NMIP4Config * ip4_config; - NMIP6Config * ip6_config; - - nm_dns_manager_begin_updates(priv->dns_manager, __func__); - - ip4_config = nm_vpn_connection_get_ip4_config(vpn); - if (ip4_config) - nm_dns_manager_set_ip_config(priv->dns_manager, - NM_IP_CONFIG_CAST(ip4_config), - NM_DNS_IP_CONFIG_TYPE_VPN); - - ip6_config = nm_vpn_connection_get_ip6_config(vpn); - if (ip6_config) - nm_dns_manager_set_ip_config(priv->dns_manager, - NM_IP_CONFIG_CAST(ip6_config), - NM_DNS_IP_CONFIG_TYPE_VPN); - - update_routing_and_dns(self, TRUE, NULL); - - nm_dns_manager_end_updates(priv->dns_manager, __func__); -} - -static void -vpn_connection_deactivated(NMPolicy *self, NMVpnConnection *vpn) +vpn_connection_update_dns(NMPolicy *self, NMVpnConnection *vpn, gboolean remove) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE(self); - NMIP4Config * ip4_config; - NMIP6Config * ip6_config; + int IS_IPv4; nm_dns_manager_begin_updates(priv->dns_manager, __func__); - ip4_config = nm_vpn_connection_get_ip4_config(vpn); - if (ip4_config) - nm_dns_manager_set_ip_config(priv->dns_manager, - NM_IP_CONFIG_CAST(ip4_config), - NM_DNS_IP_CONFIG_TYPE_REMOVED); + for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) { + int addr_family = IS_IPv4 ? AF_INET : AF_INET6; + const NML3ConfigData *l3cd; - ip6_config = nm_vpn_connection_get_ip6_config(vpn); - if (ip6_config) + l3cd = nm_vpn_connection_get_l3cd(vpn, addr_family); nm_dns_manager_set_ip_config(priv->dns_manager, - NM_IP_CONFIG_CAST(ip6_config), - NM_DNS_IP_CONFIG_TYPE_REMOVED); + addr_family, + vpn, + l3cd, + remove ? NM_DNS_IP_CONFIG_TYPE_REMOVED + : NM_DNS_IP_CONFIG_TYPE_VPN, + TRUE); + } update_routing_and_dns(self, TRUE, NULL); @@ -2349,13 +2259,14 @@ vpn_connection_state_changed(NMVpnConnection * vpn, NMActiveConnectionStateReason reason, NMPolicy * self) { + /* FIXME: we need to track changes to nm_vpn_connection_get_l3cd(). */ if (new_state == NM_VPN_CONNECTION_STATE_ACTIVATED) - vpn_connection_activated(self, vpn); + vpn_connection_update_dns(self, vpn, FALSE); else if (new_state >= NM_VPN_CONNECTION_STATE_FAILED) { /* Only clean up IP/DNS if the connection ever got past IP_CONFIG */ if (old_state >= NM_VPN_CONNECTION_STATE_IP_CONFIG_GET && old_state <= NM_VPN_CONNECTION_STATE_ACTIVATED) - vpn_connection_deactivated(self, vpn); + vpn_connection_update_dns(self, vpn, TRUE); } } diff --git a/src/core/nm-proxy-config.c b/src/core/nm-proxy-config.c deleted file mode 100644 index 49156dfae0..0000000000 --- a/src/core/nm-proxy-config.c +++ /dev/null @@ -1,172 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2016 Atul Anand . - */ - -#include "src/core/nm-default-daemon.h" - -#include "nm-proxy-config.h" - -#include - -#include "libnm-core-intern/nm-core-internal.h" - -/*****************************************************************************/ - -typedef struct { - NMProxyConfigMethod method; - gboolean browser_only; - char * pac_url; - char * pac_script; -} NMProxyConfigPrivate; - -struct _NMProxyConfig { - GObject parent; - NMProxyConfigPrivate _priv; -}; - -struct _NMProxyConfigClass { - GObjectClass parent; -}; - -G_DEFINE_TYPE(NMProxyConfig, nm_proxy_config, G_TYPE_OBJECT) - -#define NM_PROXY_CONFIG_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMProxyConfig, NM_IS_PROXY_CONFIG) - -/*****************************************************************************/ - -void -nm_proxy_config_set_method(NMProxyConfig *config, NMProxyConfigMethod method) -{ - NMProxyConfigPrivate *priv = NM_PROXY_CONFIG_GET_PRIVATE(config); - - priv->method = method; -} - -NMProxyConfigMethod -nm_proxy_config_get_method(const NMProxyConfig *config) -{ - const NMProxyConfigPrivate *priv = NM_PROXY_CONFIG_GET_PRIVATE(config); - - return priv->method; -} - -void -nm_proxy_config_merge_setting(NMProxyConfig *config, NMSettingProxy *setting) -{ - const char * tmp = NULL; - NMProxyConfigPrivate *priv; - NMSettingProxyMethod method; - - if (!setting) - return; - - g_return_if_fail(NM_IS_SETTING_PROXY(setting)); - - priv = NM_PROXY_CONFIG_GET_PRIVATE(config); - - nm_clear_g_free(&priv->pac_script); - - method = nm_setting_proxy_get_method(setting); - switch (method) { - case NM_SETTING_PROXY_METHOD_AUTO: - priv->method = NM_PROXY_CONFIG_METHOD_AUTO; - - /* Free DHCP Obtained PAC Url (i.e Option 252) - * only when libnm overrides it. - */ - tmp = nm_setting_proxy_get_pac_url(setting); - if (tmp) { - g_free(priv->pac_url); - priv->pac_url = g_strdup(tmp); - } - - tmp = nm_setting_proxy_get_pac_script(setting); - priv->pac_script = g_strdup(tmp); - - break; - case NM_SETTING_PROXY_METHOD_NONE: - priv->method = NM_PROXY_CONFIG_METHOD_NONE; - break; - } - - priv->browser_only = nm_setting_proxy_get_browser_only(setting); -} - -gboolean -nm_proxy_config_get_browser_only(const NMProxyConfig *config) -{ - const NMProxyConfigPrivate *priv = NM_PROXY_CONFIG_GET_PRIVATE(config); - - return priv->browser_only; -} - -void -nm_proxy_config_set_pac_url(NMProxyConfig *config, const char *url) -{ - NMProxyConfigPrivate *priv = NM_PROXY_CONFIG_GET_PRIVATE(config); - - g_free(priv->pac_url); - priv->pac_url = g_strdup(url); -} - -const char * -nm_proxy_config_get_pac_url(const NMProxyConfig *config) -{ - const NMProxyConfigPrivate *priv = NM_PROXY_CONFIG_GET_PRIVATE(config); - - return priv->pac_url; -} - -void -nm_proxy_config_set_pac_script(NMProxyConfig *config, const char *script) -{ - NMProxyConfigPrivate *priv = NM_PROXY_CONFIG_GET_PRIVATE(config); - - g_free(priv->pac_script); - priv->pac_script = g_strdup(script); -} - -const char * -nm_proxy_config_get_pac_script(const NMProxyConfig *config) -{ - const NMProxyConfigPrivate *priv = NM_PROXY_CONFIG_GET_PRIVATE(config); - - return priv->pac_script; -} - -/*****************************************************************************/ - -static void -nm_proxy_config_init(NMProxyConfig *config) -{ - NMProxyConfigPrivate *priv = NM_PROXY_CONFIG_GET_PRIVATE(config); - - priv->method = NM_PROXY_CONFIG_METHOD_NONE; -} - -NMProxyConfig * -nm_proxy_config_new(void) -{ - return g_object_new(NM_TYPE_PROXY_CONFIG, NULL); -} - -static void -finalize(GObject *object) -{ - NMProxyConfig * self = NM_PROXY_CONFIG(object); - NMProxyConfigPrivate *priv = NM_PROXY_CONFIG_GET_PRIVATE(self); - - g_free(priv->pac_url); - g_free(priv->pac_script); - - G_OBJECT_CLASS(nm_proxy_config_parent_class)->finalize(object); -} - -static void -nm_proxy_config_class_init(NMProxyConfigClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - - object_class->finalize = finalize; -} diff --git a/src/core/nm-proxy-config.h b/src/core/nm-proxy-config.h deleted file mode 100644 index 7b6241f849..0000000000 --- a/src/core/nm-proxy-config.h +++ /dev/null @@ -1,41 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2016 Atul Anand . - */ - -#ifndef __NETWORKMANAGER_PROXY_CONFIG_H__ -#define __NETWORKMANAGER_PROXY_CONFIG_H__ - -#include "nm-setting-proxy.h" -#include "nm-l3-config-data.h" - -#define NM_TYPE_PROXY_CONFIG (nm_proxy_config_get_type()) -#define NM_PROXY_CONFIG(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_PROXY_CONFIG, NMProxyConfig)) -#define NM_PROXY_CONFIG_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_PROXY_CONFIG, NMProxyConfigClass)) -#define NM_IS_PROXY_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_PROXY_CONFIG)) -#define NM_IS_PROXY_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_PROXY_CONFIG)) -#define NM_PROXY_CONFIG_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_PROXY_CONFIG, NMProxyConfigClass)) - -typedef struct _NMProxyConfigClass NMProxyConfigClass; - -GType nm_proxy_config_get_type(void); - -NMProxyConfig *nm_proxy_config_new(void); - -void nm_proxy_config_set_method(NMProxyConfig *config, NMProxyConfigMethod method); -NMProxyConfigMethod nm_proxy_config_get_method(const NMProxyConfig *config); - -void nm_proxy_config_merge_setting(NMProxyConfig *config, NMSettingProxy *setting); - -gboolean nm_proxy_config_get_browser_only(const NMProxyConfig *config); - -void nm_proxy_config_set_pac_url(NMProxyConfig *config, const char *url); -const char *nm_proxy_config_get_pac_url(const NMProxyConfig *config); - -void nm_proxy_config_set_pac_script(NMProxyConfig *config, const char *script); -const char *nm_proxy_config_get_pac_script(const NMProxyConfig *config); - -#endif /* __NETWORKMANAGER_PROXY_CONFIG_H__ */ diff --git a/src/core/nm-types.h b/src/core/nm-types.h index 7ad5aee15a..72320fe132 100644 --- a/src/core/nm-types.h +++ b/src/core/nm-types.h @@ -25,10 +25,7 @@ typedef struct _NML3Cfg NML3Cfg; typedef struct _NML3ConfigData NML3ConfigData; typedef struct _NMDevice NMDevice; typedef struct _NMDhcpConfig NMDhcpConfig; -typedef struct _NMProxyConfig NMProxyConfig; typedef struct _NMIPConfig NMIPConfig; -typedef struct _NMIP4Config NMIP4Config; -typedef struct _NMIP6Config NMIP6Config; typedef struct _NMManager NMManager; typedef struct _NMNetns NMNetns; typedef struct _NMPolicy NMPolicy; diff --git a/src/core/ppp/nm-ppp-manager-call.c b/src/core/ppp/nm-ppp-manager-call.c index 5e84f59610..8adeb8adbe 100644 --- a/src/core/ppp/nm-ppp-manager-call.c +++ b/src/core/ppp/nm-ppp-manager-call.c @@ -94,24 +94,6 @@ again: return ret; } -void -nm_ppp_manager_set_route_parameters(NMPPPManager *self, - guint32 ip4_route_table, - guint32 ip4_route_metric, - 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, - ip4_route_table, - ip4_route_metric, - ip6_route_table, - ip6_route_metric); -} - gboolean nm_ppp_manager_start(NMPPPManager *self, NMActRequest *req, diff --git a/src/core/ppp/nm-ppp-manager-call.h b/src/core/ppp/nm-ppp-manager-call.h index c831cf0d61..87d2f93f55 100644 --- a/src/core/ppp/nm-ppp-manager-call.h +++ b/src/core/ppp/nm-ppp-manager-call.h @@ -10,12 +10,6 @@ NMPPPManager *nm_ppp_manager_create(const char *iface, GError **error); -void nm_ppp_manager_set_route_parameters(NMPPPManager *ppp_manager, - guint32 ip4_route_table, - guint32 ip4_route_metric, - guint32 ip6_route_table, - guint32 ip6_route_metric); - gboolean nm_ppp_manager_start(NMPPPManager *self, NMActRequest *req, const char * ppp_name, diff --git a/src/core/ppp/nm-ppp-manager.c b/src/core/ppp/nm-ppp-manager.c index fefc5d613d..25c5217980 100644 --- a/src/core/ppp/nm-ppp-manager.c +++ b/src/core/ppp/nm-ppp-manager.c @@ -32,8 +32,7 @@ #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" +#include "nm-l3-config-data.h" #include "nm-dbus-object.h" #include "nm-pppd-plugin.h" @@ -62,8 +61,7 @@ GType nm_ppp_manager_get_type(void); enum { STATE_CHANGED, IFINDEX_SET, - IP4_CONFIG, - IP6_CONFIG, + NEW_CONFIG, STATS, LAST_SIGNAL @@ -91,11 +89,6 @@ typedef struct { /* Monitoring */ int monitor_fd; guint monitor_id; - - guint32 ip4_route_table; - guint32 ip4_route_metric; - guint32 ip6_route_table; - guint32 ip6_route_metric; } NMPPPManagerPrivate; struct _NMPPPManager { @@ -131,30 +124,19 @@ static void _ppp_manager_stop_cancel(NMPPPManagerStopHandle *handle); /*****************************************************************************/ static void -_ppp_manager_set_route_parameters(NMPPPManager *self, - guint32 ip4_route_table, - guint32 ip4_route_metric, - guint32 ip6_route_table, - guint32 ip6_route_metric) +_emit_signal_new_config(NMPPPManager * self, + int addr_family, + const NML3ConfigData * l3cd, + const NMUtilsIPv6IfaceId *iid) { - NMPPPManagerPrivate *priv; + nm_assert(NM_IS_PPP_MANAGER(self)); + nm_assert_addr_family(addr_family); + nm_assert(NM_IS_L3_CONFIG_DATA(l3cd)); + nm_assert((!!iid) == (addr_family == AF_INET6)); - g_return_if_fail(NM_IS_PPP_MANAGER(self)); + nm_l3_config_data_seal(l3cd); - priv = NM_PPP_MANAGER_GET_PRIVATE(self); - if (priv->ip4_route_table != ip4_route_table || priv->ip4_route_metric != ip4_route_metric - || priv->ip6_route_table != ip6_route_table || priv->ip6_route_metric != ip6_route_metric) { - priv->ip4_route_table = ip4_route_table; - priv->ip4_route_metric = ip4_route_metric; - priv->ip6_route_table = ip6_route_table; - priv->ip6_route_metric = ip6_route_metric; - - _LOGT("route-parameters: table-v4: %u, metric-v4: %u, table-v6: %u, metric-v6: %u", - priv->ip4_route_table, - priv->ip4_route_metric, - priv->ip6_route_table, - priv->ip6_route_metric); - } + g_signal_emit(self, signals[NEW_CONFIG], 0, addr_family, l3cd, iid); } /*****************************************************************************/ @@ -510,12 +492,12 @@ impl_ppp_manager_set_ip4_config(NMDBusObject * obj, GDBusMethodInvocation * invocation, GVariant * parameters) { - NMPPPManager * self = NM_PPP_MANAGER(obj); - NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE(self); - gs_unref_object NMIP4Config *config = NULL; - NMPlatformIP4Address address; - guint32 u32, mtu; - GVariantIter * iter; + NMPPPManager * self = NM_PPP_MANAGER(obj); + NMPPPManagerPrivate * priv = NM_PPP_MANAGER_GET_PRIVATE(self); + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + NMPlatformIP4Address address; + guint32 u32, mtu; + GVariantIter * iter; gs_unref_variant GVariant *config_dict = NULL; _LOGI("(IPv4 Config Get) reply received."); @@ -527,37 +509,40 @@ impl_ppp_manager_set_ip4_config(NMDBusObject * obj, if (!set_ip_config_common(self, config_dict, &mtu)) goto out; - config = nm_ip4_config_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), priv->ifindex); + l3cd = nm_l3_config_data_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), priv->ifindex); - if (mtu) - nm_ip4_config_set_mtu(config, mtu, NM_IP_CONFIG_SOURCE_PPP); + nm_l3_config_data_set_source(l3cd, NM_IP_CONFIG_SOURCE_PPP); + nm_l3_config_data_set_mtu(l3cd, mtu); - memset(&address, 0, sizeof(address)); - address.plen = 32; + address = (NMPlatformIP4Address){ + .plen = 32, + }; if (g_variant_lookup(config_dict, NM_PPP_IP4_CONFIG_ADDRESS, "u", &u32)) address.address = u32; + if (g_variant_lookup(config_dict, NM_PPP_IP4_CONFIG_PREFIX, "u", &u32)) + address.plen = u32; + if (g_variant_lookup(config_dict, NM_PPP_IP4_CONFIG_GATEWAY, "u", &u32)) { const NMPlatformIP4Route r = { .ifindex = priv->ifindex, .rt_source = NM_IP_CONFIG_SOURCE_PPP, .gateway = u32, - .table_coerced = nm_platform_route_table_coerce(priv->ip4_route_table), - .metric = priv->ip4_route_metric, + .table_any = TRUE, + .table_coerced = 0, + .metric_any = TRUE, + .metric = 0, }; - nm_ip4_config_add_route(config, &r, NULL); + nm_l3_config_data_add_route_4(l3cd, &r); address.peer_address = u32; } else address.peer_address = address.address; - if (g_variant_lookup(config_dict, NM_PPP_IP4_CONFIG_PREFIX, "u", &u32)) - address.plen = u32; - - if (address.address && address.plen && address.plen <= 32) { + if (address.address && address.plen > 0 && address.plen <= 32) { address.addr_source = NM_IP_CONFIG_SOURCE_PPP; - nm_ip4_config_add_address(config, &address); + nm_l3_config_data_add_address_4(l3cd, &address); } else { _LOGE("invalid IPv4 address received!"); goto out; @@ -565,18 +550,17 @@ impl_ppp_manager_set_ip4_config(NMDBusObject * obj, if (g_variant_lookup(config_dict, NM_PPP_IP4_CONFIG_DNS, "au", &iter)) { while (g_variant_iter_next(iter, "u", &u32)) - nm_ip4_config_add_nameserver(config, u32); + nm_l3_config_data_add_nameserver(l3cd, AF_INET, &u32); g_variant_iter_free(iter); } if (g_variant_lookup(config_dict, NM_PPP_IP4_CONFIG_WINS, "au", &iter)) { while (g_variant_iter_next(iter, "u", &u32)) - nm_ip4_config_add_wins(config, u32); + nm_l3_config_data_add_wins(l3cd, u32); g_variant_iter_free(iter); } - /* Push the IP4 config up to the device */ - g_signal_emit(self, signals[IP4_CONFIG], 0, config); + _emit_signal_new_config(self, AF_INET, l3cd, NULL); out: g_dbus_method_invocation_return_value(invocation, NULL); @@ -620,14 +604,14 @@ impl_ppp_manager_set_ip6_config(NMDBusObject * obj, GDBusMethodInvocation * invocation, GVariant * parameters) { - NMPPPManager * self = NM_PPP_MANAGER(obj); - NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE(self); - gs_unref_object NMIP6Config *config = NULL; - NMPlatformIP6Address addr; - struct in6_addr a; - NMUtilsIPv6IfaceId iid = NM_UTILS_IPV6_IFACE_ID_INIT; - gboolean has_peer = FALSE; - gs_unref_variant GVariant *config_dict = NULL; + NMPPPManager * self = NM_PPP_MANAGER(obj); + NMPPPManagerPrivate * priv = NM_PPP_MANAGER_GET_PRIVATE(self); + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + NMPlatformIP6Address address; + struct in6_addr a; + NMUtilsIPv6IfaceId iid = NM_UTILS_IPV6_IFACE_ID_INIT; + gboolean has_peer = FALSE; + gs_unref_variant GVariant *config_dict = NULL; _LOGI("(IPv6 Config Get) reply received."); @@ -638,32 +622,34 @@ impl_ppp_manager_set_ip6_config(NMDBusObject * obj, if (!set_ip_config_common(self, config_dict, NULL)) goto out; - config = nm_ip6_config_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), priv->ifindex); + l3cd = nm_l3_config_data_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), priv->ifindex); - memset(&addr, 0, sizeof(addr)); - addr.plen = 64; + address = (NMPlatformIP6Address){ + .plen = 64, + }; if (iid_value_to_ll6_addr(config_dict, NM_PPP_IP6_CONFIG_PEER_IID, &a, NULL)) { const NMPlatformIP6Route r = { .ifindex = priv->ifindex, .rt_source = NM_IP_CONFIG_SOURCE_PPP, .gateway = a, - .table_coerced = nm_platform_route_table_coerce(priv->ip6_route_table), - .metric = priv->ip6_route_metric, + .table_any = TRUE, + .table_coerced = 0, + .metric_any = TRUE, + .metric = 0, }; - nm_ip6_config_add_route(config, &r, NULL); - addr.peer_address = a; - has_peer = TRUE; + nm_l3_config_data_add_route_6(l3cd, &r); + address.peer_address = a; + has_peer = TRUE; } - if (iid_value_to_ll6_addr(config_dict, NM_PPP_IP6_CONFIG_OUR_IID, &addr.address, &iid)) { + if (iid_value_to_ll6_addr(config_dict, NM_PPP_IP6_CONFIG_OUR_IID, &address.address, &iid)) { if (!has_peer) - addr.peer_address = addr.address; - nm_ip6_config_add_address(config, &addr); + address.peer_address = address.address; + nm_l3_config_data_add_address_6(l3cd, &address); - /* Push the IPv6 config and interface identifier up to the device */ - g_signal_emit(self, signals[IP6_CONFIG], 0, &iid, config); + _emit_signal_new_config(self, AF_INET6, l3cd, &iid); } else _LOGE("invalid IPv6 address received!"); @@ -1290,12 +1276,8 @@ nm_ppp_manager_init(NMPPPManager *self) { NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE(self); - priv->ifindex = -1; - priv->monitor_fd = -1; - priv->ip4_route_table = RT_TABLE_MAIN; - priv->ip4_route_metric = 460; - priv->ip6_route_table = RT_TABLE_MAIN; - priv->ip6_route_metric = 460; + priv->ifindex = -1; + priv->monitor_fd = -1; } static NMPPPManager * @@ -1414,18 +1396,7 @@ nm_ppp_manager_class_init(NMPPPManagerClass *manager_class) G_TYPE_INT, G_TYPE_STRING); - signals[IP4_CONFIG] = g_signal_new(NM_PPP_MANAGER_SIGNAL_IP4_CONFIG, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 1, - G_TYPE_OBJECT); - - signals[IP6_CONFIG] = g_signal_new(NM_PPP_MANAGER_SIGNAL_IP6_CONFIG, + signals[NEW_CONFIG] = g_signal_new(NM_PPP_MANAGER_SIGNAL_NEW_CONFIG, G_OBJECT_CLASS_TYPE(object_class), G_SIGNAL_RUN_FIRST, 0, @@ -1433,9 +1404,10 @@ nm_ppp_manager_class_init(NMPPPManagerClass *manager_class) NULL, NULL, G_TYPE_NONE, - 2, - G_TYPE_POINTER, - G_TYPE_OBJECT); + 3, + G_TYPE_INT, /* addr_family */ + G_TYPE_POINTER, /* (const NML3ConfigData *) */ + G_TYPE_POINTER); /* (const NMUtilsIPv6IfaceId *) */ signals[STATS] = g_signal_new(NM_PPP_MANAGER_SIGNAL_STATS, G_OBJECT_CLASS_TYPE(object_class), @@ -1451,9 +1423,8 @@ nm_ppp_manager_class_init(NMPPPManagerClass *manager_class) } const NMPPPOps ppp_ops = { - .create = _ppp_manager_new, - .set_route_parameters = _ppp_manager_set_route_parameters, - .start = _ppp_manager_start, - .stop = _ppp_manager_stop, - .stop_cancel = _ppp_manager_stop_cancel, + .create = _ppp_manager_new, + .start = _ppp_manager_start, + .stop = _ppp_manager_stop, + .stop_cancel = _ppp_manager_stop_cancel, }; diff --git a/src/core/ppp/nm-ppp-manager.h b/src/core/ppp/nm-ppp-manager.h index c41dda2074..9cf465517c 100644 --- a/src/core/ppp/nm-ppp-manager.h +++ b/src/core/ppp/nm-ppp-manager.h @@ -11,8 +11,7 @@ #define NM_PPP_MANAGER_SIGNAL_STATE_CHANGED "state-changed" #define NM_PPP_MANAGER_SIGNAL_IFINDEX_SET "ifindex-set" -#define NM_PPP_MANAGER_SIGNAL_IP4_CONFIG "ip4-config" -#define NM_PPP_MANAGER_SIGNAL_IP6_CONFIG "ip6-config" +#define NM_PPP_MANAGER_SIGNAL_NEW_CONFIG "new-config" #define NM_PPP_MANAGER_SIGNAL_STATS "stats" typedef struct _NMPPPManager NMPPPManager; diff --git a/src/core/ppp/nm-ppp-plugin-api.h b/src/core/ppp/nm-ppp-plugin-api.h index 647e1c240e..a867b94920 100644 --- a/src/core/ppp/nm-ppp-plugin-api.h +++ b/src/core/ppp/nm-ppp-plugin-api.h @@ -11,12 +11,6 @@ typedef const struct { NMPPPManager *(*create)(const char *iface); - void (*set_route_parameters)(NMPPPManager *manager, - guint32 route_table_v4, - guint32 route_metric_v4, - guint32 route_table_v6, - guint32 route_metric_v6); - gboolean (*start)(NMPPPManager *manager, NMActRequest *req, const char * ppp_name, diff --git a/src/core/tests/test-ip4-config.c b/src/core/tests/test-ip4-config.c index 3a095d4ad9..1b38bb2f31 100644 --- a/src/core/tests/test-ip4-config.c +++ b/src/core/tests/test-ip4-config.c @@ -7,7 +7,6 @@ #include -#include "nm-ip4-config.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 ddf4c789c8..5982726f9f 100644 --- a/src/core/tests/test-ip6-config.c +++ b/src/core/tests/test-ip6-config.c @@ -8,8 +8,6 @@ #include #include -#include "nm-ip6-config.h" - #include "libnm-platform/nm-platform.h" #include "nm-test-utils-core.h" diff --git a/src/core/vpn/nm-vpn-connection.c b/src/core/vpn/nm-vpn-connection.c index d06ca46adc..a63428e2fa 100644 --- a/src/core/vpn/nm-vpn-connection.c +++ b/src/core/vpn/nm-vpn-connection.c @@ -17,9 +17,6 @@ #include #include -#include "nm-proxy-config.h" -#include "nm-ip4-config.h" -#include "nm-ip6-config.h" #include "libnm-platform/nm-platform.h" #include "nm-active-connection.h" #include "NetworkManagerUtils.h" @@ -34,6 +31,7 @@ #include "nm-vpn-plugin-info.h" #include "nm-vpn-manager.h" #include "dns/nm-dns-manager.h" +#include "nm-l3-config-data.h" typedef enum { /* Only system secrets */ @@ -100,26 +98,25 @@ typedef struct { NMNetns *netns; - GPtrArray *ip4_dev_route_blacklist; + NML3Cfg *l3cfg; GDBusProxy * proxy; GCancellable * cancellable; GVariant * connect_hash; guint connect_timeout; - NMProxyConfig * proxy_config; NMPacrunnerConfId *pacrunner_conf_id; gboolean has_ip4; - NMIP4Config * ip4_config; - guint32 ip4_internal_gw; - guint32 ip4_external_gw; - gboolean has_ip6; - NMIP6Config * ip6_config; - - /* These config instances are passed on to NMDevice and modified by NMDevice. - * This pointer is only useful for nm_device_replace_vpn4_config() to clear the - * previous configuration. Consider these instances to be owned by NMDevice. */ - NMIP4Config *last_device_ip4_config; - NMIP6Config *last_device_ip6_config; + + union { + struct { + const NML3ConfigData *l3cd_6; + const NML3ConfigData *l3cd_4; + }; + const NML3ConfigData *l3cd_x[2]; + }; + guint32 ip4_internal_gw; + guint32 ip4_external_gw; + gboolean has_ip6; struct in6_addr *ip6_internal_gw; struct in6_addr *ip6_external_gw; @@ -351,6 +348,8 @@ fw_call_cleanup(NMVpnConnection *self) static void remove_parent_device_config(NMVpnConnection *connection, NMDevice *device) { + /* FIXME(l3cfg) */ +#if 0 NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(connection); if (priv->last_device_ip4_config) { @@ -362,6 +361,7 @@ remove_parent_device_config(NMVpnConnection *connection, NMDevice *device) nm_device_replace_vpn6_config(device, priv->last_device_ip6_config, NULL); g_clear_object(&priv->last_device_ip6_config); } +#endif } static void @@ -514,9 +514,7 @@ _set_vpn_state(NMVpnConnection * self, _get_applied_connection(self), parent_dev, priv->ip_iface, - priv->proxy_config, - priv->ip4_config, - priv->ip6_config, + NULL, //XXX dispatcher_pre_up_done, self, &priv->dispatcher_id)) { @@ -536,21 +534,19 @@ _set_vpn_state(NMVpnConnection * self, applied, parent_dev, priv->ip_iface, - priv->proxy_config, - priv->ip4_config, - priv->ip6_config, + NULL, //XXX NULL, NULL, NULL); - if (priv->proxy_config) { - nm_pacrunner_manager_remove_clear(&priv->pacrunner_conf_id); - priv->pacrunner_conf_id = nm_pacrunner_manager_add(nm_pacrunner_manager_get(), - priv->proxy_config, - priv->ip_iface, - priv->ip4_config, - priv->ip6_config); - } + //XXX if (priv->proxy_config) { + //XXX nm_pacrunner_manager_remove_clear(&priv->pacrunner_conf_id); + //XXX priv->pacrunner_conf_id = nm_pacrunner_manager_add(nm_pacrunner_manager_get(), + //XXX priv->proxy_config, + //XXX priv->ip_iface, + //XXX priv->ip4_config, + //XXX priv->ip6_config); + //XXX } break; case STATE_DEACTIVATING: applied = _get_applied_connection(self); @@ -560,18 +556,15 @@ _set_vpn_state(NMVpnConnection * self, applied, parent_dev, priv->ip_iface, - priv->proxy_config, - priv->ip4_config, - priv->ip6_config); + NULL //XXX + ); } else { if (!nm_dispatcher_call_vpn(NM_DISPATCHER_ACTION_VPN_PRE_DOWN, _get_settings_connection(self, FALSE), applied, parent_dev, priv->ip_iface, - priv->proxy_config, - priv->ip4_config, - priv->ip6_config, + NULL, //XXX dispatcher_pre_down_done, self, &priv->dispatcher_id)) { @@ -592,8 +585,6 @@ _set_vpn_state(NMVpnConnection * self, _get_applied_connection(self), parent_dev, priv->ip_iface, - NULL, - NULL, NULL); } else { nm_dispatcher_call_vpn(NM_DISPATCHER_ACTION_VPN_DOWN, @@ -604,8 +595,6 @@ _set_vpn_state(NMVpnConnection * self, NULL, NULL, NULL, - NULL, - NULL, NULL); } } @@ -678,11 +667,12 @@ device_state_changed(NMActiveConnection *active, */ } -static void -add_ip4_vpn_gateway_route(NMIP4Config *config, - NMDevice * parent_device, - in_addr_t vpn_gw, - NMPlatform * platform) +//XXX +_nm_unused static void +add_ip4_vpn_gateway_route(NML3ConfigData *l3cd, + NMDevice * parent_device, + in_addr_t vpn_gw, + NMPlatform * platform) { guint32 parent_gw = 0; gboolean has_parent_gw = FALSE; @@ -691,11 +681,11 @@ add_ip4_vpn_gateway_route(NMIP4Config *config, guint32 route_metric; nm_auto_nmpobj const NMPObject *route_resolved = NULL; - g_return_if_fail(NM_IS_IP4_CONFIG(config)); + nm_assert(NM_IS_L3_CONFIG_DATA(l3cd)); g_return_if_fail(NM_IS_DEVICE(parent_device)); g_return_if_fail(vpn_gw != 0); - ifindex = nm_ip4_config_get_ifindex(config); + ifindex = nm_l3_config_data_get_ifindex(l3cd); nm_assert(ifindex > 0); nm_assert(ifindex == nm_device_get_ip_ifindex(parent_device)); @@ -737,14 +727,15 @@ add_ip4_vpn_gateway_route(NMIP4Config *config, route_metric = nm_device_get_route_metric(parent_device, AF_INET); - memset(&route, 0, sizeof(route)); - route.ifindex = ifindex; - route.network = vpn_gw; - route.plen = 32; - route.gateway = parent_gw; - route.rt_source = NM_IP_CONFIG_SOURCE_VPN; - route.metric = route_metric; - nm_ip4_config_add_route(config, &route, NULL); + route = (NMPlatformIP4Route){ + .ifindex = ifindex, + .network = vpn_gw, + .plen = 32, + .gateway = parent_gw, + .rt_source = NM_IP_CONFIG_SOURCE_VPN, + .metric = route_metric, + }; + nm_l3_config_data_add_route_4(l3cd, &route); if (parent_gw) { /* Ensure there's a route to the parent device's gateway through the @@ -752,17 +743,19 @@ add_ip4_vpn_gateway_route(NMIP4Config *config, * routes include a subnet that matches the parent device's subnet, * the parent device's gateway would get routed through the VPN and fail. */ - memset(&route, 0, sizeof(route)); - route.network = parent_gw; - route.plen = 32; - route.rt_source = NM_IP_CONFIG_SOURCE_VPN; - route.metric = route_metric; - nm_ip4_config_add_route(config, &route, NULL); + route = (NMPlatformIP4Route){ + .network = parent_gw, + .plen = 32, + .rt_source = NM_IP_CONFIG_SOURCE_VPN, + .metric = route_metric, + }; + nm_l3_config_data_add_route_4(l3cd, &route); } } -static void -add_ip6_vpn_gateway_route(NMIP6Config * config, +//XXX +_nm_unused static void +add_ip6_vpn_gateway_route(NML3ConfigData * l3cd, NMDevice * parent_device, const struct in6_addr *vpn_gw, NMPlatform * platform) @@ -774,11 +767,11 @@ add_ip6_vpn_gateway_route(NMIP6Config * config, guint32 route_metric; nm_auto_nmpobj const NMPObject *route_resolved = NULL; - g_return_if_fail(NM_IS_IP6_CONFIG(config)); + nm_assert(NM_IS_L3_CONFIG_DATA(l3cd)); g_return_if_fail(NM_IS_DEVICE(parent_device)); g_return_if_fail(vpn_gw != NULL); - ifindex = nm_ip6_config_get_ifindex(config); + ifindex = nm_l3_config_data_get_ifindex(l3cd); nm_assert(ifindex > 0); nm_assert(ifindex == nm_device_get_ip_ifindex(parent_device)); @@ -820,15 +813,15 @@ add_ip6_vpn_gateway_route(NMIP6Config * config, route_metric = nm_device_get_route_metric(parent_device, AF_INET6); - memset(&route, 0, sizeof(route)); - route.ifindex = ifindex; - route.network = *vpn_gw; - route.plen = 128; - if (parent_gw) - route.gateway = *parent_gw; - route.rt_source = NM_IP_CONFIG_SOURCE_VPN; - route.metric = route_metric; - nm_ip6_config_add_route(config, &route, NULL); + route = (NMPlatformIP6Route){ + .ifindex = ifindex, + .network = *vpn_gw, + .plen = 128, + .gateway = (parent_gw ? *parent_gw : in6addr_any), + .rt_source = NM_IP_CONFIG_SOURCE_VPN, + .metric = route_metric, + }; + nm_l3_config_data_add_route_6(l3cd, &route); /* Ensure there's a route to the parent device's gateway through the * parent device, since if the VPN claims the default route and the VPN @@ -836,12 +829,13 @@ add_ip6_vpn_gateway_route(NMIP6Config * config, * the parent device's gateway would get routed through the VPN and fail. */ if (parent_gw && !IN6_IS_ADDR_UNSPECIFIED(parent_gw)) { - memset(&route, 0, sizeof(route)); - route.network = *parent_gw; - route.plen = 128; - route.rt_source = NM_IP_CONFIG_SOURCE_VPN; - route.metric = route_metric; - nm_ip6_config_add_route(config, &route, NULL); + route = (NMPlatformIP6Route){ + .network = *parent_gw, + .plen = 128, + .rt_source = NM_IP_CONFIG_SOURCE_VPN, + .metric = route_metric, + }; + nm_l3_config_data_add_route_6(l3cd, &route); } } @@ -988,14 +982,13 @@ plugin_state_changed(NMVpnConnection *self, NMVpnServiceState new_service_state) static void print_vpn_config(NMVpnConnection *self) { - NMVpnConnectionPrivate * priv = NM_VPN_CONNECTION_GET_PRIVATE(self); - const NMPlatformIP4Address *address4; - const NMPlatformIP6Address *address6; - char * dns_domain = NULL; - guint32 num, i; - char b1[NM_UTILS_INET_ADDRSTRLEN]; - char b2[NM_UTILS_INET_ADDRSTRLEN]; - NMDedupMultiIter ipconf_iter; + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + const char *const * strv; + guint num; + guint i; + char b1[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf1[sizeof(_nm_utils_to_string_buffer)]; + NMDedupMultiIter ipconf_iter; if (priv->ip4_external_gw) { _LOGI("Data: VPN Gateway: %s", _nm_utils_inet4_ntop(priv->ip4_external_gw, b1)); @@ -1005,78 +998,57 @@ print_vpn_config(NMVpnConnection *self) _LOGI("Data: Tunnel Device: %s%s%s", NM_PRINT_FMT_QUOTE_STRING(priv->ip_iface)); - if (priv->ip4_config) { - const NMPlatformIP4Route *route; - - _LOGI("Data: IPv4 configuration:"); + for (i = 0; i < 2; i++) { + const gboolean IS_IPv4 = (i == 0); + const int addr_family = IS_IPv4 ? AF_INET : AF_INET6; + const NML3ConfigData *l3cd = priv->l3cd_x[IS_IPv4]; + const NMPObject * plobj; + const guint8 * p_addrs; - address4 = nm_ip4_config_get_first_address(priv->ip4_config); - nm_assert(address4); + if (!l3cd) { + _LOGI("Data: No IPv%c configuration", nm_utils_addr_family_to_char(addr_family)); + continue; + } - if (priv->ip4_internal_gw) - _LOGI("Data: Internal Gateway: %s", _nm_utils_inet4_ntop(priv->ip4_internal_gw, b1)); - _LOGI("Data: Internal Address: %s", - address4 ? _nm_utils_inet4_ntop(address4->address, b1) : "??"); - _LOGI("Data: Internal Prefix: %d", address4 ? (int) address4->plen : -1); - _LOGI("Data: Internal Point-to-Point Address: %s", - _nm_utils_inet4_ntop(address4->peer_address, b1)); + _LOGI("Data: IPv%c configuration:", nm_utils_addr_family_to_char(addr_family)); - nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, priv->ip4_config, &route) { - _LOGI("Data: Static Route: %s/%d Next Hop: %s", - _nm_utils_inet4_ntop(route->network, b1), - route->plen, - _nm_utils_inet4_ntop(route->gateway, b2)); + nm_l3_config_data_iter_obj_for_each (&ipconf_iter, + l3cd, + &plobj, + NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4)) { + _LOGI("Data: Internal Address: %s", + nmp_object_to_string(plobj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf1, sizeof(sbuf1))); } - num = nm_ip4_config_get_num_nameservers(priv->ip4_config); - for (i = 0; i < num; i++) { - _LOGI("Data: Internal DNS: %s", - _nm_utils_inet4_ntop(nm_ip4_config_get_nameserver(priv->ip4_config, i), b1)); + if (IS_IPv4) { + if (priv->ip4_internal_gw) + _LOGI("Data: Internal Gateway: %s", + _nm_utils_inet4_ntop(priv->ip4_internal_gw, b1)); + } else { + if (priv->ip6_internal_gw) + _LOGI("Data: Internal Gateway: %s", + _nm_utils_inet6_ntop(priv->ip6_internal_gw, b1)); } - if (nm_ip4_config_get_num_domains(priv->ip4_config) > 0) - dns_domain = (char *) nm_ip4_config_get_domain(priv->ip4_config, 0); - - _LOGI("Data: DNS Domain: '%s'", dns_domain ?: "(none)"); - } else - _LOGI("Data: No IPv4 configuration"); - - if (priv->ip6_config) { - const NMPlatformIP6Route *route; - - _LOGI("Data: IPv6 configuration:"); - - address6 = nm_ip6_config_get_first_address(priv->ip6_config); - nm_assert(address6); - - if (priv->ip6_internal_gw) - _LOGI("Data: Internal Gateway: %s", _nm_utils_inet6_ntop(priv->ip6_internal_gw, b1)); - _LOGI("Data: Internal Address: %s", _nm_utils_inet6_ntop(&address6->address, b1)); - _LOGI("Data: Internal Prefix: %d", address6->plen); - _LOGI("Data: Internal Point-to-Point Address: %s", - _nm_utils_inet6_ntop(&address6->peer_address, b1)); - - nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, priv->ip6_config, &route) { - _LOGI("Data: Static Route: %s/%d Next Hop: %s", - _nm_utils_inet6_ntop(&route->network, b1), - route->plen, - _nm_utils_inet6_ntop(&route->gateway, b2)); + nm_l3_config_data_iter_obj_for_each (&ipconf_iter, + l3cd, + &plobj, + NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4)) { + _LOGI("Data: Static Route: %s", + nmp_object_to_string(plobj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf1, sizeof(sbuf1))); } - num = nm_ip6_config_get_num_nameservers(priv->ip6_config); - for (i = 0; i < num; i++) { - _LOGI("Data: Internal DNS: %s", - _nm_utils_inet6_ntop(nm_ip6_config_get_nameserver(priv->ip6_config, i), b1)); + p_addrs = nm_l3_config_data_get_nameservers(l3cd, addr_family, &num); + for (i = 0; i < num; i++, p_addrs += nm_utils_addr_family_to_size(addr_family)) { + _LOGI("Data: Internal DNS: %s", nm_utils_inet_ntop(addr_family, p_addrs, b1)); } - if (nm_ip6_config_get_num_domains(priv->ip6_config) > 0) - dns_domain = (char *) nm_ip6_config_get_domain(priv->ip6_config, 0); - - _LOGI("Data: DNS Domain: '%s'", dns_domain ?: "(none)"); - } else - _LOGI("Data: No IPv6 configuration"); + strv = nm_l3_config_data_get_domains(l3cd, addr_family, &num); + for (i = 0; i < num; i++) + _LOGI("Data: DNS Domain: '%s'", strv[i]); + } - if (priv->banner && strlen(priv->banner)) { + if (!nm_str_is_empty(priv->banner)) { _LOGI("Data: Login Banner:"); _LOGI("Data: -----------------------------------------"); _LOGI("Data: %s", priv->banner); @@ -1087,62 +1059,63 @@ print_vpn_config(NMVpnConnection *self) static void apply_parent_device_config(NMVpnConnection *self) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); - NMDevice * parent_dev = nm_active_connection_get_device(NM_ACTIVE_CONNECTION(self)); - int ifindex; - NMIP4Config *vpn4_parent_config = NULL; - NMIP6Config *vpn6_parent_config = NULL; +#if 0 + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + NMDevice *parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (self)); + int ifindex; + NMIP4Config *vpn4_parent_config = NULL; + NMIP6Config *vpn6_parent_config = NULL; - ifindex = nm_device_get_ip_ifindex(parent_dev); - if (ifindex > 0) { - /* If the VPN didn't return a network interface, it is a route-based + ifindex = nm_device_get_ip_ifindex (parent_dev); + if (ifindex > 0) { + /* If the VPN didn't return a network interface, it is a route-based * VPN (like kernel IPSec) and all IP addressing and routing should * be done on the parent interface instead. */ - if (priv->ip4_config) { - vpn4_parent_config = nm_ip4_config_new(nm_netns_get_multi_idx(priv->netns), ifindex); - if (priv->ip_ifindex <= 0) - nm_ip4_config_merge(vpn4_parent_config, - priv->ip4_config, - NM_IP_CONFIG_MERGE_NO_DNS, - 0); - } - if (priv->ip6_config) { - vpn6_parent_config = nm_ip6_config_new(nm_netns_get_multi_idx(priv->netns), ifindex); - if (priv->ip_ifindex <= 0) - nm_ip6_config_merge(vpn6_parent_config, - priv->ip6_config, - NM_IP_CONFIG_MERGE_NO_DNS, - 0); - } - } - - /* Add any explicit route to the VPN gateway through the parent device */ - if (vpn4_parent_config && priv->ip4_external_gw) { - add_ip4_vpn_gateway_route(vpn4_parent_config, - parent_dev, - priv->ip4_external_gw, - nm_netns_get_platform(priv->netns)); - } - if (vpn6_parent_config && priv->ip6_external_gw) { - add_ip6_vpn_gateway_route(vpn6_parent_config, - parent_dev, - priv->ip6_external_gw, - nm_netns_get_platform(priv->netns)); - } - - nm_device_replace_vpn4_config(parent_dev, priv->last_device_ip4_config, vpn4_parent_config); - g_clear_object(&priv->last_device_ip4_config); - priv->last_device_ip4_config = vpn4_parent_config; - - nm_device_replace_vpn6_config(parent_dev, priv->last_device_ip6_config, vpn6_parent_config); - g_clear_object(&priv->last_device_ip6_config); - priv->last_device_ip6_config = vpn6_parent_config; + if (priv->ip4_config) { + vpn4_parent_config = nm_ip4_config_new (nm_netns_get_multi_idx (priv->netns), + ifindex); + if (priv->ip_ifindex <= 0) + nm_ip4_config_merge (vpn4_parent_config, priv->ip4_config, NM_IP_CONFIG_MERGE_NO_DNS, 0); + } + if (priv->ip6_config) { + vpn6_parent_config = nm_ip6_config_new (nm_netns_get_multi_idx (priv->netns), + ifindex); + if (priv->ip_ifindex <= 0) + nm_ip6_config_merge (vpn6_parent_config, priv->ip6_config, NM_IP_CONFIG_MERGE_NO_DNS, 0); + } + } + + /* Add any explicit route to the VPN gateway through the parent device */ + if ( vpn4_parent_config + && priv->ip4_external_gw) { + add_ip4_vpn_gateway_route (vpn4_parent_config, + parent_dev, + priv->ip4_external_gw, + nm_netns_get_platform (priv->netns)); + } + if ( vpn6_parent_config + && priv->ip6_external_gw) { + add_ip6_vpn_gateway_route (vpn6_parent_config, + parent_dev, + priv->ip6_external_gw, + nm_netns_get_platform (priv->netns)); + } + + nm_device_replace_vpn4_config (parent_dev, priv->last_device_ip4_config, vpn4_parent_config); + g_clear_object (&priv->last_device_ip4_config); + priv->last_device_ip4_config = vpn4_parent_config; + + nm_device_replace_vpn6_config (parent_dev, priv->last_device_ip6_config, vpn6_parent_config); + g_clear_object (&priv->last_device_ip6_config); + priv->last_device_ip6_config = vpn6_parent_config; +#endif } static gboolean nm_vpn_connection_apply_config(NMVpnConnection *self) { +#if 0 NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); apply_parent_device_config(self); @@ -1189,16 +1162,15 @@ nm_vpn_connection_apply_config(NMVpnConnection *self) _LOGI("VPN connection: (IP Config Get) complete"); if (priv->vpn_state < STATE_PRE_UP) _set_vpn_state(self, STATE_PRE_UP, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE); +#endif return TRUE; } static void _cleanup_failed_config(NMVpnConnection *self) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); - - nm_dbus_object_clear_and_unexport(&priv->ip4_config); - nm_dbus_object_clear_and_unexport(&priv->ip6_config); + //XXX nm_dbus_object_clear_and_unexport(&priv->ip4_config); + //XXX nm_dbus_object_clear_and_unexport(&priv->ip6_config); _LOGW("VPN connection: did not receive valid IP config information"); _set_vpn_state(self, STATE_FAILED, NM_ACTIVE_CONNECTION_STATE_REASON_IP_CONFIG_INVALID, FALSE); @@ -1243,10 +1215,10 @@ nm_vpn_connection_config_maybe_complete(NMVpnConnection *self, gboolean success) return; if (success) { - if ((priv->has_ip4 && !priv->ip4_config) || (priv->has_ip6 && !priv->ip6_config)) { - /* Need to wait for other config */ - return; - } + //XXX if ((priv->has_ip4 && !priv->ip4_config) || (priv->has_ip6 && !priv->ip6_config)) { + //XXX /* Need to wait for other config */ + //XXX return; + //XXX } } nm_clear_g_source(&priv->connect_timeout); @@ -1286,26 +1258,23 @@ ip6_addr_from_variant(GVariant *v, struct in6_addr *addr) g_return_val_if_fail(v, FALSE); g_return_val_if_fail(addr, FALSE); + nm_assert(g_variant_is_of_type(v, G_VARIANT_TYPE("ay"))); - if (g_variant_is_of_type(v, G_VARIANT_TYPE("ay"))) { - bytes = g_variant_get_fixed_array(v, &len, sizeof(guint8)); - if (len == sizeof(struct in6_addr) && !IN6_IS_ADDR_UNSPECIFIED(bytes)) { - memcpy(addr, bytes, len); - return TRUE; - } + bytes = g_variant_get_fixed_array(v, &len, sizeof(guint8)); + if (len == sizeof(struct in6_addr) && !IN6_IS_ADDR_UNSPECIFIED(bytes)) { + memcpy(addr, bytes, len); + return TRUE; } return FALSE; } static struct in6_addr * -ip6_addr_dup_from_variant(GVariant *v) +ip6_addr_from_variant_dup(GVariant *v) { - struct in6_addr *addr; + struct in6_addr addr; - addr = g_malloc0(sizeof(*addr)); - if (ip6_addr_from_variant(v, addr)) - return addr; - g_free(addr); + if (ip6_addr_from_variant(v, &addr)) + return nm_memdup(&addr, sizeof(addr)); return NULL; } @@ -1356,19 +1325,15 @@ process_generic_config(NMVpnConnection *self, GVariant *dict) _notify(self, PROP_BANNER); } - /* Proxy Config */ - g_clear_object(&priv->proxy_config); - priv->proxy_config = nm_proxy_config_new(); + //XXX if (g_variant_lookup(dict, NM_VPN_PLUGIN_CONFIG_PROXY_PAC, "&s", &str)) { + //XXX nm_proxy_config_set_method(priv->proxy_config, NM_PROXY_CONFIG_METHOD_AUTO); + //XXX nm_proxy_config_set_pac_url(priv->proxy_config, str); + //XXX } else + //XXX nm_proxy_config_set_method(priv->proxy_config, NM_PROXY_CONFIG_METHOD_NONE); - if (g_variant_lookup(dict, NM_VPN_PLUGIN_CONFIG_PROXY_PAC, "&s", &str)) { - nm_proxy_config_set_method(priv->proxy_config, NM_PROXY_CONFIG_METHOD_AUTO); - nm_proxy_config_set_pac_url(priv->proxy_config, str); - } else - nm_proxy_config_set_method(priv->proxy_config, NM_PROXY_CONFIG_METHOD_NONE); - - /* User overrides if any from the NMConnection's Proxy settings */ - nm_proxy_config_merge_setting(priv->proxy_config, - nm_connection_get_setting_proxy(_get_applied_connection(self))); + //XXX /* User overrides if any from the NMConnection's Proxy settings */ + //XXX nm_proxy_config_merge_setting(priv->proxy_config, + //XXX nm_connection_get_setting_proxy(_get_applied_connection(self))); /* External world-visible address of the VPN server */ priv->ip4_external_gw = 0; @@ -1377,7 +1342,7 @@ process_generic_config(NMVpnConnection *self, GVariant *dict) if (g_variant_lookup(dict, NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY, "u", &u32)) { priv->ip4_external_gw = u32; } else if (g_variant_lookup(dict, NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY, "@ay", &v)) { - priv->ip6_external_gw = ip6_addr_dup_from_variant(v); + priv->ip6_external_gw = ip6_addr_from_variant_dup(v); g_variant_unref(v); if (!priv->ip6_external_gw) { @@ -1414,12 +1379,12 @@ nm_vpn_connection_config_get(NMVpnConnection *self, GVariant *dict) priv->has_ip4 = FALSE; if (g_variant_lookup(dict, NM_VPN_PLUGIN_CONFIG_HAS_IP4, "b", &b)) priv->has_ip4 = b; - nm_dbus_object_clear_and_unexport(&priv->ip4_config); + //XXX nm_dbus_object_clear_and_unexport(&priv->ip4_config); priv->has_ip6 = FALSE; if (g_variant_lookup(dict, NM_VPN_PLUGIN_CONFIG_HAS_IP6, "b", &b)) priv->has_ip6 = b; - nm_dbus_object_clear_and_unexport(&priv->ip6_config); + //XXX nm_dbus_object_clear_and_unexport(&priv->ip6_config); nm_vpn_connection_config_maybe_complete(self, TRUE); } @@ -1486,20 +1451,20 @@ _is_device_vrf(NMVpnConnection *self) static void nm_vpn_connection_ip4_config_get(NMVpnConnection *self, GVariant *dict) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); - NMPlatformIP4Address address; - guint32 u32, route_metric; - NMSettingIPConfig * s_ip; - NMSettingConnection * s_con; - guint32 route_table; - NMIP4Config * config; - GVariantIter * iter; - const char * str; - GVariant * v; - gboolean b; - int ip_ifindex; - guint32 mss = 0; - gboolean never_default = FALSE; + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + NMPlatformIP4Address address; + guint32 u32, route_metric; + NMSettingIPConfig * s_ip; + NMSettingConnection * s_con; + guint32 route_table; + GVariantIter * iter; + const char * str; + GVariant * v; + gboolean b; + int ip_ifindex; + guint32 mss = 0; + gboolean never_default = FALSE; g_return_if_fail(dict && g_variant_is_of_type(dict, G_VARIANT_TYPE_VARDICT)); @@ -1536,11 +1501,13 @@ nm_vpn_connection_ip4_config_get(NMVpnConnection *self, GVariant *dict) if (ip_ifindex <= 0) g_return_if_reached(); - config = nm_ip4_config_new(nm_netns_get_multi_idx(priv->netns), ip_ifindex); - nm_ip4_config_set_dns_priority(config, NM_DNS_PRIORITY_DEFAULT_VPN); + l3cd = nm_l3_config_data_new(nm_netns_get_multi_idx(priv->netns), ip_ifindex); + nm_l3_config_data_set_source(l3cd, NM_IP_CONFIG_SOURCE_VPN); + nm_l3_config_data_set_dns_priority(l3cd, AF_INET, NM_DNS_PRIORITY_DEFAULT_VPN); - memset(&address, 0, sizeof(address)); - address.plen = 24; + address = (NMPlatformIP4Address){ + .plen = 24, + }; /* Internal address of the VPN subnet's gateway */ if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_INT_GATEWAY, "u", &u32)) @@ -1559,23 +1526,22 @@ nm_vpn_connection_ip4_config_get(NMVpnConnection *self, GVariant *dict) if (address.address && address.plen && address.plen <= 32) { address.addr_source = NM_IP_CONFIG_SOURCE_VPN; - nm_ip4_config_add_address(config, &address); + nm_l3_config_data_add_address_4(l3cd, &address); } else { _LOGW("invalid IP4 config received!"); - g_object_unref(config); nm_vpn_connection_config_maybe_complete(self, FALSE); return; } if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_DNS, "au", &iter)) { while (g_variant_iter_next(iter, "u", &u32)) - nm_ip4_config_add_nameserver(config, u32); + nm_l3_config_data_add_nameserver(l3cd, AF_INET, &u32); g_variant_iter_free(iter); } if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_NBNS, "au", &iter)) { while (g_variant_iter_next(iter, "u", &u32)) - nm_ip4_config_add_wins(config, u32); + nm_l3_config_data_add_wins(l3cd, u32); g_variant_iter_free(iter); } @@ -1583,11 +1549,11 @@ nm_vpn_connection_ip4_config_get(NMVpnConnection *self, GVariant *dict) mss = u32; if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_DOMAIN, "&s", &str)) - nm_ip4_config_add_domain(config, str); + nm_l3_config_data_add_domain(l3cd, AF_INET, str); if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_DOMAINS, "as", &iter)) { while (g_variant_iter_next(iter, "&s", &str)) - nm_ip4_config_add_domain(config, str); + nm_l3_config_data_add_domain(l3cd, AF_INET, str); g_variant_iter_free(iter); } @@ -1599,12 +1565,12 @@ nm_vpn_connection_ip4_config_get(NMVpnConnection *self, GVariant *dict) if (nm_setting_ip_config_get_ignore_auto_routes(s_ip)) { /* ignore VPN routes */ } else if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_PRESERVE_ROUTES, "b", &b) && b) { - if (priv->ip4_config) { - NMDedupMultiIter ipconf_iter; + if (priv->l3cd_4) { const NMPlatformIP4Route *route; + NMDedupMultiIter ipconf_iter; - nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, priv->ip4_config, &route) - nm_ip4_config_add_route(config, route, NULL); + nm_l3_config_data_iter_ip4_route_for_each (&ipconf_iter, priv->l3cd_4, &route) + nm_l3_config_data_add_route_4(l3cd, route); } } else if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_ROUTES, "aau", &iter)) { while (g_variant_iter_next(iter, "@au", &v)) { @@ -1641,7 +1607,7 @@ nm_vpn_connection_ip4_config_get(NMVpnConnection *self, GVariant *dict) break; } - nm_ip4_config_add_route(config, &route, NULL); + nm_l3_config_data_add_route_4(l3cd, &route); break; default: break; @@ -1655,12 +1621,14 @@ nm_vpn_connection_ip4_config_get(NMVpnConnection *self, GVariant *dict) never_default = b; /* Merge in user overrides from the NMConnection's IPv4 setting */ - nm_ip4_config_merge_setting(config, - s_ip, - nm_setting_connection_get_mdns(s_con), - nm_setting_connection_get_llmnr(s_con), - route_table, - route_metric); + (void) s_con; + //XXX + //nm_ip4_config_merge_setting (config, + // s_ip, + // nm_setting_connection_get_mdns (s_con), + // nm_setting_connection_get_llmnr (s_con), + // route_table, + // route_metric); if (!never_default && !nm_setting_ip_config_get_never_default(s_ip)) { const NMPlatformIP4Route r = { @@ -1672,45 +1640,47 @@ nm_vpn_connection_ip4_config_get(NMVpnConnection *self, GVariant *dict) .mss = mss, }; - nm_ip4_config_add_route(config, &r, NULL); + nm_l3_config_data_add_route_4(l3cd, &r); } - nm_clear_pointer(&priv->ip4_dev_route_blacklist, g_ptr_array_unref); + nm_l3_config_data_add_dependent_routes(l3cd, + AF_INET, + route_table, + nm_vpn_connection_get_ip4_route_metric(self), + _is_device_vrf(self)); - nm_ip4_config_add_dependent_routes(config, - route_table, - nm_vpn_connection_get_ip4_route_metric(self), - _is_device_vrf(self), - &priv->ip4_dev_route_blacklist); + //XXX +#if 0 + if (priv->ip4_config) { + nm_ip4_config_replace (priv->ip4_config, config, NULL); + g_object_unref (config); + } else { + priv->ip4_config = config; + nm_dbus_object_export (NM_DBUS_OBJECT (config)); + g_object_notify ((GObject *) self, NM_ACTIVE_CONNECTION_IP4_CONFIG); + } - if (priv->ip4_config) { - nm_ip4_config_replace(priv->ip4_config, config, NULL); - g_object_unref(config); - } else { - priv->ip4_config = config; - nm_dbus_object_export(NM_DBUS_OBJECT(config)); - g_object_notify((GObject *) self, NM_ACTIVE_CONNECTION_IP4_CONFIG); - } - - nm_vpn_connection_config_maybe_complete(self, TRUE); + nm_vpn_connection_config_maybe_complete (self, TRUE); +#endif } static void nm_vpn_connection_ip6_config_get(NMVpnConnection *self, GVariant *dict) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); - NMPlatformIP6Address address; - guint32 u32, route_metric; - NMSettingIPConfig * s_ip; - guint32 route_table; - NMIP6Config * config; - GVariantIter * iter; - const char * str; - GVariant * v; - gboolean b; - int ip_ifindex; - guint32 mss = 0; - gboolean never_default = FALSE; + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE(self); + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + NMPlatformIP6Address address; + guint32 u32; + guint32 route_metric; + NMSettingIPConfig * s_ip; + guint32 route_table; + GVariantIter * iter; + const char * str; + GVariant * v; + gboolean b; + int ip_ifindex; + guint32 mss = 0; + gboolean never_default = FALSE; g_return_if_fail(dict && g_variant_is_of_type(dict, G_VARIANT_TYPE_VARDICT)); @@ -1734,16 +1704,18 @@ nm_vpn_connection_ip6_config_get(NMVpnConnection *self, GVariant *dict) if (ip_ifindex <= 0) g_return_if_reached(); - config = nm_ip6_config_new(nm_netns_get_multi_idx(priv->netns), ip_ifindex); - nm_ip6_config_set_dns_priority(config, NM_DNS_PRIORITY_DEFAULT_VPN); + l3cd = nm_l3_config_data_new(nm_netns_get_multi_idx(priv->netns), ip_ifindex); + nm_l3_config_data_set_source(l3cd, NM_IP_CONFIG_SOURCE_VPN); + nm_l3_config_data_set_dns_priority(l3cd, AF_INET6, NM_DNS_PRIORITY_DEFAULT_VPN); - memset(&address, 0, sizeof(address)); - address.plen = 128; + address = (NMPlatformIP6Address){ + .plen = 128, + }; /* Internal address of the VPN subnet's gateway */ nm_clear_g_free(&priv->ip6_internal_gw); if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP6_CONFIG_INT_GATEWAY, "@ay", &v)) { - priv->ip6_internal_gw = ip6_addr_dup_from_variant(v); + priv->ip6_internal_gw = ip6_addr_from_variant_dup(v); g_variant_unref(v); } @@ -1762,10 +1734,9 @@ nm_vpn_connection_ip6_config_get(NMVpnConnection *self, GVariant *dict) if (!IN6_IS_ADDR_UNSPECIFIED(&address.address) && address.plen && address.plen <= 128) { address.addr_source = NM_IP_CONFIG_SOURCE_VPN; - nm_ip6_config_add_address(config, &address); + nm_l3_config_data_add_address_6(l3cd, &address); } else { _LOGW("invalid IP6 config received!"); - g_object_unref(config); nm_vpn_connection_config_maybe_complete(self, FALSE); return; } @@ -1775,7 +1746,7 @@ nm_vpn_connection_ip6_config_get(NMVpnConnection *self, GVariant *dict) struct in6_addr dns; if (ip6_addr_from_variant(v, &dns)) - nm_ip6_config_add_nameserver(config, &dns); + nm_l3_config_data_add_nameserver(l3cd, AF_INET6, &dns); g_variant_unref(v); } g_variant_iter_free(iter); @@ -1785,11 +1756,11 @@ nm_vpn_connection_ip6_config_get(NMVpnConnection *self, GVariant *dict) mss = u32; if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP6_CONFIG_DOMAIN, "&s", &str)) - nm_ip6_config_add_domain(config, str); + nm_l3_config_data_add_domain(l3cd, AF_INET6, str); if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP6_CONFIG_DOMAINS, "as", &iter)) { while (g_variant_iter_next(iter, "&s", &str)) - nm_ip6_config_add_domain(config, str); + nm_l3_config_data_add_domain(l3cd, AF_INET6, str); g_variant_iter_free(iter); } @@ -1800,33 +1771,41 @@ nm_vpn_connection_ip6_config_get(NMVpnConnection *self, GVariant *dict) if (nm_setting_ip_config_get_ignore_auto_routes(s_ip)) { /* Ignore VPN routes */ } else if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP6_CONFIG_PRESERVE_ROUTES, "b", &b) && b) { - if (priv->ip6_config) { - NMDedupMultiIter ipconf_iter; - const NMPlatformIP6Route *route; - - nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, priv->ip6_config, &route) - nm_ip6_config_add_route(config, route, NULL); + if (priv->l3cd_6) { + NMDedupMultiIter ipconf_iter; + const NMPObject *route; + + nm_l3_config_data_iter_obj_for_each (&ipconf_iter, + priv->l3cd_6, + &route, + NMP_OBJECT_TYPE_IP6_ROUTE) + nm_l3_config_data_add_route(l3cd, AF_INET6, route, NULL); } } else if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP6_CONFIG_ROUTES, "a(ayuayu)", &iter)) { - GVariant *dest, *next_hop; - guint32 prefix, metric; + GVariant *next_hop; + GVariant *dest; + guint32 prefix; + guint32 metric; while (g_variant_iter_next(iter, "(@ayu@ayu)", &dest, &prefix, &next_hop, &metric)) { - NMPlatformIP6Route route; + _nm_unused gs_unref_variant GVariant *nexT_hop_keep_alive = next_hop; + _nm_unused gs_unref_variant GVariant *dest_keep_alive = dest; + NMPlatformIP6Route route; - memset(&route, 0, sizeof(route)); + if (prefix > 128) + continue; - if (!ip6_addr_from_variant(dest, &route.network)) - goto next; + route = (NMPlatformIP6Route){ + .plen = prefix, + .table_coerced = nm_platform_route_table_coerce(route_table), + .metric = route_metric, + .rt_source = NM_IP_CONFIG_SOURCE_VPN, + }; - if (prefix > 128) - goto next; + if (!ip6_addr_from_variant(dest, &route.network)) + continue; - route.plen = prefix; ip6_addr_from_variant(next_hop, &route.gateway); - route.table_coerced = nm_platform_route_table_coerce(route_table); - route.metric = route_metric; - route.rt_source = NM_IP_CONFIG_SOURCE_VPN; nm_utils_ip6_address_clear_host_address(&route.network, &route.network, route.plen); @@ -1837,14 +1816,10 @@ nm_vpn_connection_ip6_config_get(NMVpnConnection *self, GVariant *dict) * server, we want to use the NM created route instead of whatever * the server provides. */ - goto next; + continue; } - nm_ip6_config_add_route(config, &route, NULL); - -next: - g_variant_unref(dest); - g_variant_unref(next_hop); + nm_l3_config_data_add_route_6(l3cd, &route); } g_variant_iter_free(iter); } @@ -1853,7 +1828,12 @@ next: never_default = b; /* Merge in user overrides from the NMConnection's IPv6 setting */ - nm_ip6_config_merge_setting(config, s_ip, route_table, route_metric); + //XXX + (void) s_ip; + //nm_ip6_config_merge_setting (config, + // s_ip, + // route_table, + // route_metric); if (!never_default && !nm_setting_ip_config_get_never_default(s_ip)) { const NMPlatformIP6Route r = { @@ -1865,19 +1845,26 @@ next: .mss = mss, }; - nm_ip6_config_add_route(config, &r, NULL); + nm_l3_config_data_add_route_6(l3cd, &r); } - nm_ip6_config_add_dependent_routes(config, route_table, route_metric, _is_device_vrf(self)); + nm_l3_config_data_add_dependent_routes(l3cd, + AF_INET6, + route_table, + route_metric, + _is_device_vrf(self)); - if (priv->ip6_config) { - nm_ip6_config_replace(priv->ip6_config, config, NULL); - g_object_unref(config); - } else { - priv->ip6_config = config; - nm_dbus_object_export(NM_DBUS_OBJECT(config)); - g_object_notify((GObject *) self, NM_ACTIVE_CONNECTION_IP6_CONFIG); - } + //XXX +#if 0 + if (priv->ip6_config) { + nm_ip6_config_replace (priv->ip6_config, config, NULL); + g_object_unref (config); + } else { + priv->ip6_config = config; + nm_dbus_object_export (NM_DBUS_OBJECT (config)); + g_object_notify ((GObject *) self, NM_ACTIVE_CONNECTION_IP6_CONFIG); + } +#endif nm_vpn_connection_config_maybe_complete(self, TRUE); } @@ -2423,28 +2410,12 @@ nm_vpn_connection_get_banner(NMVpnConnection *self) return NM_VPN_CONNECTION_GET_PRIVATE(self)->banner; } -NMProxyConfig * -nm_vpn_connection_get_proxy_config(NMVpnConnection *self) -{ - g_return_val_if_fail(NM_IS_VPN_CONNECTION(self), NULL); - - return NM_VPN_CONNECTION_GET_PRIVATE(self)->proxy_config; -} - -NMIP4Config * -nm_vpn_connection_get_ip4_config(NMVpnConnection *self) -{ - g_return_val_if_fail(NM_IS_VPN_CONNECTION(self), NULL); - - return NM_VPN_CONNECTION_GET_PRIVATE(self)->ip4_config; -} - -NMIP6Config * -nm_vpn_connection_get_ip6_config(NMVpnConnection *self) +const NML3ConfigData * +nm_vpn_connection_get_l3cd(NMVpnConnection *self, int addr_family) { g_return_val_if_fail(NM_IS_VPN_CONNECTION(self), NULL); - return NM_VPN_CONNECTION_GET_PRIVATE(self)->ip6_config; + return NM_VPN_CONNECTION_GET_PRIVATE(self)->l3cd_x[NM_IS_IPv4(addr_family)]; } static int @@ -2820,8 +2791,6 @@ dispose(GObject *object) nm_clear_pointer(&priv->connect_hash, g_variant_unref); - nm_clear_pointer(&priv->ip4_dev_route_blacklist, g_ptr_array_unref); - nm_clear_g_source(&priv->connect_timeout); dispatcher_cleanup(self); @@ -2830,9 +2799,6 @@ dispose(GObject *object) nm_clear_g_cancellable(&priv->cancellable); - g_clear_object(&priv->proxy_config); - nm_dbus_object_clear_and_unexport(&priv->ip4_config); - nm_dbus_object_clear_and_unexport(&priv->ip6_config); g_clear_object(&priv->proxy); g_clear_object(&priv->plugin_info); @@ -2859,7 +2825,8 @@ finalize(GObject *object) g_clear_object(&priv->netns); } -static gboolean +//XXX +_nm_unused static gboolean ip_config_valid(VpnState state) { return (state == STATE_PRE_UP || state == STATE_ACTIVATED); @@ -2879,14 +2846,14 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) g_value_set_string(value, priv->banner ?: ""); break; case PROP_IP4_CONFIG: - nm_dbus_utils_g_value_set_object_path(value, - ip_config_valid(priv->vpn_state) ? priv->ip4_config - : NULL); + //XXX nm_dbus_utils_g_value_set_object_path(value, + //XXX ip_config_valid(priv->vpn_state) ? priv->ip4_config + //XXX : NULL); break; case PROP_IP6_CONFIG: - nm_dbus_utils_g_value_set_object_path(value, - ip_config_valid(priv->vpn_state) ? priv->ip6_config - : NULL); + //XXX nm_dbus_utils_g_value_set_object_path(value, + //XXX ip_config_valid(priv->vpn_state) ? priv->ip6_config + //XXX : NULL); break; case PROP_MASTER: parent_dev = nm_active_connection_get_device(NM_ACTIVE_CONNECTION(object)); diff --git a/src/core/vpn/nm-vpn-connection.h b/src/core/vpn/nm-vpn-connection.h index 0209ea3d60..940a20d7a3 100644 --- a/src/core/vpn/nm-vpn-connection.h +++ b/src/core/vpn/nm-vpn-connection.h @@ -54,10 +54,8 @@ void nm_vpn_connection_disconnect(NMVpnConnection * self, NMActiveConnectionStateReason reason, gboolean quitting); -NMProxyConfig *nm_vpn_connection_get_proxy_config(NMVpnConnection *self); +const NML3ConfigData *nm_vpn_connection_get_l3cd(NMVpnConnection *self, int addr_family); -NMIP4Config * nm_vpn_connection_get_ip4_config(NMVpnConnection *self); -NMIP6Config * nm_vpn_connection_get_ip6_config(NMVpnConnection *self); const char * nm_vpn_connection_get_ip_iface(NMVpnConnection *self, gboolean fallback_device); int nm_vpn_connection_get_ip_ifindex(NMVpnConnection *self, gboolean fallback_device); guint32 nm_vpn_connection_get_ip4_internal_gateway(NMVpnConnection *self); diff --git a/src/libnm-systemd-core/meson.build b/src/libnm-systemd-core/meson.build index 7ecf31640a..66e7cc82c4 100644 --- a/src/libnm-systemd-core/meson.build +++ b/src/libnm-systemd-core/meson.build @@ -18,8 +18,6 @@ libnm_systemd_core = static_library( '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', diff --git a/src/libnm-systemd-core/nm-sd.h b/src/libnm-systemd-core/nm-sd.h index f346197440..c52f7cfe77 100644 --- a/src/libnm-systemd-core/nm-sd.h +++ b/src/libnm-systemd-core/nm-sd.h @@ -9,7 +9,6 @@ #include "src/systemd/sd-dhcp-client.h" #include "src/systemd/sd-dhcp6-client.h" #include "src/systemd/sd-lldp.h" -#include "src/systemd/sd-ipv4ll.h" /*****************************************************************************/ diff --git a/tools/run-nm-test.sh b/tools/run-nm-test.sh index 81b94ec648..355a436600 100755 --- a/tools/run-nm-test.sh +++ b/tools/run-nm-test.sh @@ -362,7 +362,6 @@ if [ $HAS_ERRORS -eq 0 ]; then # valgrind doesn't support setns syscall and spams the logfile. # hack around it... case "$TEST_NAME" in - 'test-acd' | \ 'test-address-linux' | \ 'test-cleanup-linux' | \ 'test-config' | \ -- cgit v1.2.1