diff options
author | Thomas Haller <thaller@redhat.com> | 2020-09-22 20:32:14 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2021-04-28 13:51:24 +0200 |
commit | ba23f8c629efefbe6a90f4e5041ee705df646214 (patch) | |
tree | a2b1a0c1d7bd1bba2d86748afd4d46d2a644381c | |
parent | 5d8cfb8f4a82cb41ce0bdafadcafca9d58c26746 (diff) | |
download | NetworkManager-th/l3cfg-18.tar.gz |
core: use NML3ConfigData (WIP)th/l3cfg-18
68 files changed, 4391 insertions, 6512 deletions
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 5b99dc98a4..02a01c19e1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2313,8 +2313,6 @@ src_core_libnm_systemd_core_la_SOURCES = \ src/core/systemd/src/libsystemd-network/sd-dhcp-lease.c \ src/core/systemd/src/libsystemd-network/sd-dhcp6-client.c \ src/core/systemd/src/libsystemd-network/sd-dhcp6-lease.c \ - src/core/systemd/src/libsystemd-network/sd-ipv4acd.c \ - src/core/systemd/src/libsystemd-network/sd-ipv4ll.c \ src/core/systemd/src/libsystemd-network/sd-lldp.c \ src/core/systemd/src/libsystemd/sd-event/event-source.h \ src/core/systemd/src/libsystemd/sd-event/event-util.c \ @@ -2332,8 +2330,6 @@ src_core_libnm_systemd_core_la_SOURCES = \ src/core/systemd/src/systemd/sd-dhcp6-option.h \ src/core/systemd/src/systemd/sd-event.h \ src/core/systemd/src/systemd/sd-id128.h \ - src/core/systemd/src/systemd/sd-ipv4acd.h \ - src/core/systemd/src/systemd/sd-ipv4ll.h \ src/core/systemd/src/systemd/sd-lldp.h \ src/core/systemd/src/systemd/sd-ndisc.h \ $(NULL) @@ -2423,8 +2419,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.c \ @@ -4253,20 +4247,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..3f3bd353f9 --- /dev/null +++ b/WIP.txt @@ -0,0 +1,15 @@ +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-act-request.c + > src/core/nm-act-request.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 dcc1e0e469..0ca959e40e 100644 --- a/src/core/devices/adsl/nm-device-adsl.c +++ b/src/core/devices/adsl/nm-device-adsl.c @@ -15,7 +15,6 @@ #include <unistd.h> #include <stdlib.h> -#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 c7f76a5ab8..6485c459c8 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 <netinet/in.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <linux/if_ether.h> - -#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 <netinet/in.h> - -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-ethernet.c b/src/core/devices/nm-device-ethernet.c index 638c9b6937..fae23a0d35 100644 --- a/src/core/devices/nm-device-ethernet.c +++ b/src/core/devices/nm-device-ethernet.c @@ -1135,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 @@ -1163,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, @@ -1196,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; } @@ -1495,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-ppp.c b/src/core/devices/nm-device-ppp.c index b642d0d7de..fd974f8c32 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 8675a699a3..ddd7b01003 100644 --- a/src/core/devices/nm-device-private.h +++ b/src/core/devices/nm-device-private.h @@ -42,8 +42,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); @@ -74,8 +72,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); @@ -119,8 +116,7 @@ nm_device_activate_ip6_state_done(NMDevice *self) void nm_device_set_dhcp_anycast_address(NMDevice *device, const char *addr); -gboolean nm_device_dhcp4_renew(NMDevice *device, gboolean release); -gboolean nm_device_dhcp6_renew(NMDevice *device, gboolean release); +gboolean nm_device_dhcp_renew(NMDevice *device, int addr_family, gboolean release); void nm_device_recheck_available_connections(NMDevice *device); @@ -136,7 +132,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); @@ -147,11 +143,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-vlan.c b/src/core/devices/nm-device-vlan.c index 3b426ef4c9..d25ab76bc0 100644 --- a/src/core/devices/nm-device-vlan.c +++ b/src/core/devices/nm-device-vlan.c @@ -112,7 +112,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-wireguard.c b/src/core/devices/nm-device-wireguard.c index ca552a2c8c..973e80101f 100644 --- a/src/core/devices/nm-device-wireguard.c +++ b/src/core/devices/nm-device-wireguard.c @@ -11,6 +11,7 @@ #include <linux/fib_rules.h> #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.c b/src/core/devices/nm-device.c index bfc3f55a1e..84bf11347d 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -33,6 +33,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" @@ -64,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 "systemd/nm-sd.h" #include "nm-lldp-listener.h" @@ -79,23 +79,14 @@ #include "nm-device-logging.h" +//XXX +NM_PRAGMA_WARNING_DISABLE("-Wunused-function") + /*****************************************************************************/ #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; -} +#define GRACE_PERIOD_MULTIPLIER 2U #define CARRIER_WAIT_TIME_MS 6000 #define CARRIER_WAIT_TIME_AFTER_MTU_MS 10000 @@ -114,6 +105,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; @@ -136,28 +134,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, @@ -174,18 +184,13 @@ typedef enum { } 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 struct { NMDhcpClient *client; NMDhcpConfig *config; + GSource * grace_source; gulong state_sigid; - guint grace_id; bool grace_pending : 1; bool was_active : 1; + bool is_bad : 1; } DhcpData; struct _NMDeviceConnectivityHandle { @@ -257,6 +262,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, @@ -290,8 +298,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; @@ -305,16 +311,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; @@ -331,15 +328,30 @@ typedef struct _NMDevicePrivate { }; 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; + + NMUtilsShareRules *shared4_rules; int parent_ifindex; @@ -362,9 +374,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; @@ -378,6 +387,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 */ @@ -443,7 +454,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; @@ -460,6 +471,14 @@ typedef struct _NMDevicePrivate { 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_; }; @@ -489,13 +508,19 @@ 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; + /* Generic DHCP stuff */ char *dhcp_anycast_address; @@ -505,65 +530,16 @@ typedef struct _NMDevicePrivate { 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 +564,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; NMFirewallManager * fw_mgr; NMFirewallManagerCallId *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 +587,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,27 +667,23 @@ 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 gboolean update_ext_ip_config(NMDevice *self, int addr_family, gboolean intersect_configs); +static void nm_device_set_proxy_config(NMDevice *self); -static gboolean nm_device_set_ip_config(NMDevice * self, - int addr_family, - NMIPConfig *config, - gboolean commit, - GPtrArray * ip4_dev_route_blacklist); +static void _dev_l3_cfg_commit(NMDevice *self); -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); @@ -734,28 +694,36 @@ 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 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 +733,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); /*****************************************************************************/ @@ -1459,8 +1427,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); @@ -2391,27 +2359,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) { @@ -2426,98 +2373,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) +static const NML3ConfigData * +_dev_create_l3_config_data_from_connection(NMDevice *self, NMConnection *connection) { - g_clear_object(&config->current); - g_clear_object(&config->orig); -} + NML3ConfigData *l3cd; + int ifindex; -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) -{ - 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); -} - -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); } /*****************************************************************************/ @@ -2572,6 +2454,7 @@ nm_device_sys_iface_state_set(NMDevice *self, NMDeviceSysIfaceState sys_iface_st _sys_iface_state_to_str(priv->sys_iface_state), _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. @@ -2684,33 +2567,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) { @@ -2887,6 +2743,427 @@ _set_ip_state(NMDevice *self, int addr_family, NMDeviceIPState new_state) } } +static void +_set_ip_state_check(NMDevice *self, int addr_family) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const gboolean IS_IPv4 = (addr_family == AF_INET); + + if (addr_family == AF_UNSPEC) { + _set_ip_state_check(self, AF_INET); + _set_ip_state_check(self, AF_INET6); + return; + } + + nm_assert_addr_family(addr_family); + + if (IS_IPv4) { + 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_pending) { + /* we are still waiting for DHCP to complete/succeed. */ + addr_method_state_dhcp_4 = ADDR_METHOD_STATE_PENDING; + } else if (priv->dhcp_data_4.is_bad || !priv->l3cds[L3_CONFIG_DATA_TYPE_DHCP_4].d) { + /* the DHCP configuration is failed. */ + addr_method_state_dhcp_4 = ADDR_METHOD_STATE_FAILED; + } else + 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(). +} + +/*****************************************************************************/ + +static L3ConfigDataType +_dev_l3_config_data_tag_to_type(NMDevice *self, gconstpointer tag) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + int d; + + /* 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 (nm_ptr_to_uintptr(tag) < nm_ptr_to_uintptr(&priv->l3cds[0].d) + || nm_ptr_to_uintptr(tag) >= nm_ptr_to_uintptr(&priv->l3cds[G_N_ELEMENTS(priv->l3cds)].d)) + return _L3_CONFIG_DATA_TYPE_NONE; + + d = ((const NML3ConfigData **) tag) - (&priv->l3cds[0].d); + + nm_assert(d >= 0); + nm_assert(d < _L3_CONFIG_DATA_TYPE_NUM); + nm_assert(tag == &priv->l3cds[d].d); + return d; +} + +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; + + nm_assert(type >= 0 && type < _L3_CONFIG_DATA_TYPE_NUM); + + 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, + &priv->l3cds[l3cd_type].d, + 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) +{ + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + nm_auto_unref_l3cd const NML3ConfigData *l3cd_old_free = NULL; + const NML3ConfigData * l3cd_old; + gboolean changed = FALSE; + + l3cd_old = priv->l3cds[l3cd_type].d; + if (l3cd != priv->l3cds[l3cd_type].d) { + l3cd_old_free = 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 (_dev_l3_register_l3cds_add_config(self, l3cd_type)) + changed = TRUE; + + if (l3cd_old && l3cd_old != l3cd) { + if (nm_l3cfg_remove_config(priv->l3cfg, &priv->l3cds[l3cd_type].d, l3cd_old)) + changed = TRUE; + } + } + + 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 < G_N_ELEMENTS(priv->l3cds); i++) { + if (!priv->l3cds[i].d) + continue; + if (!do_add) { + if (nm_l3cfg_remove_config(l3cfg, &priv->l3cds[i].d, 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); + + 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) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + + if (priv->l3cfg) + 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_ACD_EVENT: + { + const NML3AcdAddrInfo *addr_info = ¬ify_data->acd_event.info; + guint i; + + for (i = 0; i < addr_info->n_track_infos; i++) { + L3ConfigDataType l3cd_type = + _dev_l3_config_data_tag_to_type(self, addr_info->track_infos[i].tag); + + if (NM_IN_SET(l3cd_type, L3_CONFIG_DATA_TYPE_DHCP_4)) { + 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); + return; + } + } + _dev_l3_notify_change(self, AF_INET); + 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); +} + +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); +} + /*****************************************************************************/ const char * @@ -2908,8 +3185,13 @@ nm_device_get_iface(NMDevice *self) static gboolean _set_ifindex(NMDevice *self, int ifindex, gboolean is_ip_ifindex) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - int * p_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) ifindex = 0; @@ -2921,13 +3203,78 @@ _set_ifindex(NMDevice *self, int ifindex, gboolean is_ip_ifindex) *p_ifindex = ifindex; - _LOGD(LOGD_DEVICE, "ifindex: set %sifindex %d", is_ip_ifindex ? "ip-" : "", ifindex); + ip_ifindex_new = nm_device_get_ip_ifindex(self); - if (!is_ip_ifindex) - _notify(self, PROP_IFINDEX); + 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_dbus_object_unexport_on_idle(g_steal_pointer(&priv->ip_config_4)); + nm_dbus_object_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); + nm_dbus_object_export(priv->ip_config_4); + nm_dbus_object_export(priv->ip_config_6); + } + + _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); + + if (l3cfg_commit_type_old) + nm_l3cfg_commit_type_unregister(l3cfg_old, l3cfg_commit_type_old); + return TRUE; } @@ -3663,7 +4010,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); @@ -3747,28 +4095,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) @@ -3800,18 +4142,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 * @@ -4366,14 +4700,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 * @@ -4740,10 +5068,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. @@ -4759,7 +5083,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; } @@ -4877,7 +5201,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; @@ -4918,7 +5242,7 @@ 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 (!nm_device_dhcp_renew(self, AF_INET, FALSE)) { nm_device_state_changed(self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_DHCP_FAILED); @@ -4926,17 +5250,17 @@ nm_device_update_dynamic_ip_setup(NMDevice *self) } } if (priv->dhcp_data_6.client) { - if (!nm_device_dhcp6_renew(self, FALSE)) { + 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 */ } } @@ -5203,82 +5527,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 @@ -5312,8 +5574,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; @@ -5398,8 +5661,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); } @@ -5446,23 +5709,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); } if (update_unmanaged_specs) @@ -5484,8 +5739,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; @@ -5548,13 +5804,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); } } @@ -6002,8 +6257,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", @@ -6147,9 +6400,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); @@ -6245,9 +6495,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); @@ -6839,15 +7086,12 @@ 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); - } + 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 @@ -7105,22 +7349,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; - /* Check for IP configuration. */ - if (priv->ip_config_4 && nm_ip4_config_get_num_addresses(priv->ip_config_4)) + pllink = nm_l3cfg_get_pllink(priv->l3cfg, TRUE); + if (!pllink) + return FALSE; + + 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; } @@ -7174,7 +7432,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; @@ -7268,11 +7527,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()); @@ -7725,20 +7986,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, @@ -8075,6 +8322,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); @@ -8554,1126 +8802,983 @@ 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; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - for (i = 0; data->configs && data->configs[i]; i++) - g_object_unref(data->configs[i]); - g_free(data->configs); - g_slice_free(AcdData, data); -} + priv->ll4_ipv4ll_failed = FALSE; + priv->ll4_ipv4ll_ready = FALSE; -static void -ipv4_manual_method_apply(NMDevice *self, NMIP4Config **configs, gboolean success) -{ - NMConnection *connection; - const char * method; - - 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); } 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); + if (_dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_LL_4, l3cd)) + _dev_l3_cfg_commit(self); - 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); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + guint timeout_msec; - for (i = 0, addr_found = FALSE; configs[i]; i++) { - if (nm_ip4_config_get_num_addresses(configs[i]) > 0) { - addr_found = TRUE; - break; - } - } + _dev_ll4_cleanup(self); - 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); + timeout_msec = _prop_get_ipv4_dad_timeout(self); + if (timeout_msec == 0) + timeout_msec = NM_ACD_TIMEOUT_RFC5227_MSEC; - 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); + _LOGI(LOGD_DEVICE | LOGD_AUTOIP4, "ipv4ll: enabling"); - for (i = 0; configs[i]; i++) - g_object_unref(configs[i]); - g_free(configs); + 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; +} - return; - } +/*****************************************************************************/ - data = g_slice_new0(AcdData); - data->configs = configs; - data->callback = cb; - data->device = self; +static void +_dev_dhcpx_cleanup(NMDevice *self, int addr_family, gboolean reset_dhcp_config, gboolean release) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const gboolean IS_IPv4 = NM_IS_IPv4(addr_family); - 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); + priv->dhcp_data_x[IS_IPv4].was_active = FALSE; - 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); - } + _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_DHCP_X(IS_IPv4), NULL); - r = nm_acd_manager_start_probe(acd_manager, timeout); - if (r < 0) { - _LOGW(LOGD_DEVICE, "acd probe failed"); + if (!IS_IPv4) + priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_NONE; - /* DAD could not be started, signal success */ - cb(self, configs, TRUE); + nm_clear_g_source_inst(&priv->dhcp_data_x[IS_IPv4].grace_source); + priv->dhcp_data_x[IS_IPv4].grace_pending = FALSE; - priv->acd.dad_list = g_slist_remove(priv->acd.dad_list, acd_manager); - nm_acd_manager_free(acd_manager); + 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); } -} - -/*****************************************************************************/ -/* IPv4LL stuff */ - -static void -ipv4ll_cleanup(NMDevice *self) -{ - 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 (reset_dhcp_config) { + if (nm_dbus_object_clear_and_unexport(&priv->dhcp_data_x[IS_IPv4].config)) + _notify(self, PROP_DHCPX_CONFIG(IS_IPv4)); } - - nm_clear_g_source(&priv->ipv4ll_timeout); } -static NMIP4Config * -ipv4ll_get_ip4_config(NMDevice *self, guint32 lla) +static gboolean +_dev_dhcpx_grace_period_expired(NMDevice *self, int addr_family) { - NMIP4Config * config = NULL; - NMPlatformIP4Address address; - NMPlatformIP4Route route; + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const gboolean IS_IPv4 = (addr_family == AF_INET); - config = nm_device_ip4_config_new(self); - g_assert(config); + nm_clear_g_source_inst(&priv->dhcp_data_x[IS_IPv4].grace_source); + priv->dhcp_data_x[IS_IPv4].grace_pending = FALSE; - 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); + _LOGI(LOGD_DHCPX(IS_IPv4), + "DHCPv%c: grace period expired", + nm_utils_addr_family_to_char(addr_family)); - /* 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); + _set_ip_state_check(self, addr_family); + return G_SOURCE_REMOVE; +} - return config; +static gboolean +_dev_dhcpx_grace_period_expired_4(gpointer user_data) +{ + return _dev_dhcpx_grace_period_expired(user_data, AF_INET); } -static void -nm_device_handle_ipv4ll_event(sd_ipv4ll *ll, int event, void *data) +static gboolean +_dev_dhcpx_grace_period_expired_6(gpointer user_data) { - NMDevice * self = data; - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - struct in_addr address; - NMIP4Config * config; - int r; + return _dev_dhcpx_grace_period_expired(user_data, AF_INET6); +} - if (priv->act_request.obj == NULL) - return; +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); + const gboolean IS_IPv4 = (addr_family == AF_INET); - nm_assert(nm_streq(nm_device_get_effective_ip_config_method(self, AF_INET), - NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)); + /* 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_pending) { + /* already pending. */ + return FALSE; + } - 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; - } + /* Start a grace period equal to the DHCP timeout multiplied + * by a constant factor. */ - 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; - } + nm_clear_g_source_inst(&priv->dhcp_data_x[IS_IPv4].grace_source); - 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; - } + if (timeout_sec == 0) + timeout_sec = _prop_get_ipvx_dhcp_timeout(self, addr_family); - 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(); + nm_assert(timeout_sec > 0); + nm_assert(timeout_sec < G_MAXINT32); - 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 (timeout_sec == NM_DHCP_TIMEOUT_INFINITY) + _LOGD(LOGD_DHCPX(IS_IPv4), + "DHCPv%c: trying to acquire a new lease", + nm_utils_addr_family_to_char(addr_family)); + else { + guint timeout_msec; -static gboolean -ipv4ll_timeout_cb(gpointer user_data) -{ - NMDevice * self = NM_DEVICE(user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + _LOGD(LOGD_DHCPX(IS_IPv4), + "DHCPv%c: trying to acquire a new lease within %u seconds", + nm_utils_addr_family_to_char(addr_family), + timeout_sec); - if (priv->ipv4ll_timeout) { - _LOGI(LOGD_AUTOIP4, "IPv4LL configuration timed out."); - priv->ipv4ll_timeout = 0; - ipv4ll_cleanup(self); + if (timeout_sec < G_MAXUINT / (GRACE_PERIOD_MULTIPLIER * 1000u)) + timeout_msec = timeout_sec * (GRACE_PERIOD_MULTIPLIER * 1000u); + else + timeout_msec = G_MAXUINT; - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF) - nm_device_activate_schedule_ip_config_timeout(self, AF_INET); + 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 FALSE; + priv->dhcp_data_x[IS_IPv4].grace_pending = TRUE; + return TRUE; } -static NMActStageReturn -ipv4ll_start(NMDevice *self) +static void +_dev_dhcpx_state_changed(NMDevice * self, + int addr_family, + NMDhcpState state, + const NML3ConfigData *l3cd) { - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - const struct ether_addr *addr; - int ifindex, r; - size_t addr_len; - - ipv4ll_cleanup(self); + nm_auto_unref_l3cd const NML3ConfigData *l3cd_merged = NULL; + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + const gboolean IS_IPv4 = NM_IS_IPv4(addr_family); - 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; - } + _LOGD(LOGD_DHCPX(IS_IPv4), + "new DHCPv%c client state %d", + nm_utils_addr_family_to_char(addr_family), + (int) state); - 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; - } + switch (state) { + case NM_DHCP_STATE_BOUND: + case NM_DHCP_STATE_EXTENDED: - 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; - } + nm_assert(l3cd); - 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; - } + /* 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; + } + } - 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; - } + nm_clear_g_source_inst(&priv->dhcp_data_x[IS_IPv4].grace_source); + priv->dhcp_data_x[IS_IPv4].grace_pending = FALSE; - 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; - } + priv->dhcp_data_x[IS_IPv4].is_bad = FALSE; - _LOGI(LOGD_DEVICE | LOGD_AUTOIP4, "IPv4LL: started"); + _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_DHCP_X(IS_IPv4), l3cd); - /* 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; -} + if (IS_IPv4) + nm_device_set_proxy_config(self); -/*****************************************************************************/ + nm_dhcp_config_set_lease(priv->dhcp_data_x[IS_IPv4].config, l3cd); -static void -ensure_con_ip_config(NMDevice *self, int addr_family) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMConnection * connection; - const int IS_IPv4 = NM_IS_IPv4(addr_family); - NMIPConfig * con_ip_config; + _set_ip_state_check(self, addr_family); - if (priv->con_ip_config_x[IS_IPv4]) - return; + _dev_l3_cfg_commit(self); - connection = nm_device_get_applied_connection(self); - if (!connection) - return; + _dev_l3_notify_change(self, addr_family); - con_ip_config = nm_device_ip_config_new(self, addr_family); + 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); + } - 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)); + 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; } - 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); - } +out_fail: + _LOGD(LOGD_DHCPX(IS_IPv4), + "DHCPv%c failed (ip_state %s, was_active %d)", + nm_utils_addr_family_to_char(addr_family), + _ip_state_to_string(priv->ip_state_x[IS_IPv4]), + (int) priv->dhcp_data_x[IS_IPv4].was_active); - priv->con_ip_config_x[IS_IPv4] = con_ip_config; + _dev_dhcpx_grace_period_start(self, addr_family, 0, FALSE); + priv->dhcp_data_x[IS_IPv4].is_bad = TRUE; + _set_ip_state_check(self, addr_family); } -/*****************************************************************************/ - static void -dhcp4_cleanup(NMDevice *self, CleanupType cleanup_type, gboolean release) +_dev_dhcpx_state_changed_4(NMDhcpClient * client, + NMDhcpState state, + const NML3ConfigData *l3cd, + gpointer user_data) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - 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); - - 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); + _dev_dhcpx_state_changed(user_data, AF_INET, state, l3cd); +} - if (cleanup_type == CLEANUP_TYPE_DECONFIGURE || cleanup_type == CLEANUP_TYPE_REMOVED) - nm_dhcp_client_stop(priv->dhcp_data_4.client, release); +static void +_dev_dhcpx_state_changed_6(NMDhcpClient * client, + NMDhcpState state, + const NML3ConfigData *l3cd, + gpointer user_data) +{ + _dev_dhcpx_state_changed(user_data, AF_INET6, state, l3cd); +} - g_clear_object(&priv->dhcp_data_4.client); - } +static void +_dev_dhcp6_prefix_delegated(NMDhcpClient *client, NMPlatformIP6Address *prefix, gpointer user_data) +{ + NMDevice *self = NM_DEVICE(user_data); - if (priv->dhcp_data_4.config) { - nm_dbus_object_clear_and_unexport(&priv->dhcp_data_4.config); - _notify(self, PROP_DHCP4_CONFIG); - } + /* 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 -ip_config_merge_and_apply(NMDevice *self, int addr_family, gboolean commit) +_dev_dhcpx_start(NMDevice *self, int addr_family) { - 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); + const gboolean 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; + + nm_assert(priv->dhcp_data_x[IS_IPv4].client == NULL); if (nm_device_sys_iface_state_is_external(self)) - commit = FALSE; + g_return_val_if_reached(TRUE); connection = nm_device_get_applied_connection(self); + g_return_val_if_fail(connection, FALSE); - /* Apply ignore-auto-routes and ignore-auto-dns settings */ - if (connection) { - NMSettingIPConfig *s_ip; + 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); - 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); + ifindex = 0; - /* 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); + 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)); + } - if (!IS_IPv4) { - NMSettingIP6Config *s_ip6 = NM_SETTING_IP6_CONFIG(s_ip); + if (ifindex <= 0) + g_return_val_if_reached(TRUE); - 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); - } + hwaddr = nmp_link_address_get_as_bytes(&pllink->l_address); + + if (!IS_IPv4) { + if (!hwaddr) { + _LOGD(LOGD_DHCP6, "dhcp6: cannot start DHCP with no suitable interface"); + return FALSE; } } - 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); + request_broadcast = FALSE; + if (pllink) { + str = nmp_object_link_udev_device_get_property_value(NMP_OBJECT_UP_CAST(pllink), + "ID_NET_DHCP_BROADCAST"); + if (str && _nm_utils_ascii_str_to_bool(str, FALSE)) { + /* Use the device property ID_NET_DHCP_BROADCAST setting, which may be set for interfaces + * requiring that the DHCPOFFER message is being broadcast because they can't handle unicast + * messages while not fully configured. + */ + request_broadcast = TRUE; + } } - init_ip_config_dns_priority(self, composite); + timeout_sec = _prop_get_ipvx_dhcp_timeout(self, addr_family); - 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); - } + _dev_dhcpx_grace_period_start(self, addr_family, timeout_sec, TRUE); 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 (!_dev_ll6_start(self, &ll_addr)) { + /* wait for the LL address to show up */ + return TRUE; } } - if (commit) { - gboolean v; + 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; - 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; - } + 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); - /* Merge all the IP configs into the composite config */ + bcast_hwaddr = nmp_link_address_get_as_bytes(&pllink->l_broadcast); - 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)); - } + 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, + priv->dhcp_anycast_address, + 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), + priv->dhcp_anycast_address, + nm_setting_ip6_config_get_ip6_privacy(NM_SETTING_IP6_CONFIG(s_ip)), + priv->dhcp6.needed_prefixes, + &error); } - 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 (nm_device_sys_iface_state_is_external_or_assume(self)) + 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) { - 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)); - } + 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); } - 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->dhcp_data_x[IS_IPv4].config) { + priv->dhcp_data_x[IS_IPv4].config = nm_dhcp_config_new(addr_family); + nm_dbus_object_export(priv->dhcp_data_x[IS_IPv4].config); + _notify(self, PROP_DHCPX_CONFIG(IS_IPv4)); + } else + nm_dhcp_config_set_lease(priv->dhcp_data_x[IS_IPv4].config, NULL); - 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); + return 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)); - } +static void +_dev_dhcp6_set_dhcp_level(NMDevice *self, NMNDiscDHCPLevel dhcp_level) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - 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); - } - } - } + if (priv->dhcp6.mode == dhcp_level) + return; - /* 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)); - } + _LOGD(LOGD_DEVICE | LOGD_DHCP6, "reset DHCPv6 level to %d", (int) dhcp_level); - if (commit) { - gboolean is_vrf; + _dev_dhcpx_cleanup(self, AF_INET6, TRUE, TRUE); - is_vrf = priv->master && nm_device_get_device_type(priv->master) == NM_DEVICE_TYPE_VRF; + priv->dhcp6.mode = dhcp_level; + if (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_NONE) + return; - 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); - } - } + _dev_dhcpx_start(self, AF_INET6); +} - 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; +gboolean +nm_device_dhcp_renew(NMDevice *self, int addr_family, gboolean release) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + const gboolean IS_IPv4 = NM_IS_IPv4(addr_family); - 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 (!priv->dhcp_data_x[IS_IPv4].client) + g_return_val_if_reached(FALSE); - 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; - } + _LOGI(LOGD_DHCPX(IS_IPv4), + "DHCPv%c lease renewal requested", + nm_utils_addr_family_to_char(addr_family)); - return success; + _dev_dhcpx_cleanup(self, addr_family, FALSE, release); + + return _dev_dhcpx_start(self, addr_family); } +/*****************************************************************************/ + static gboolean -dhcp4_lease_change(NMDevice *self, NMIP4Config *config, gboolean bound) +connection_ip_method_requires_carrier(NMConnection *connection, + int addr_family, + gboolean * out_ip_enabled) { - 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); + const char *method; - if (!ip_config_merge_and_apply(self, AF_INET, TRUE)) { - _LOGW(LOGD_DHCP4, "failed to update IPv4 config for DHCP change."); - return FALSE; - } + method = nm_utils_get_ip_config_method(connection, addr_family); - /* 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; + if (NM_IS_IPv4(addr_family)) { + NM_SET_OUT(out_ip_enabled, !nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)); + return NM_IN_STRSET(method, + NM_SETTING_IP4_CONFIG_METHOD_AUTO, + NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL); } - nm_dispatcher_call_device(NM_DISPATCHER_ACTION_DHCP4_CHANGE, self, NULL, NULL, NULL, NULL); - - return TRUE; + NM_SET_OUT(out_ip_enabled, + !NM_IN_STRSET(method, + NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_METHOD_DISABLED)); + return NM_IN_STRSET(method, + NM_SETTING_IP6_CONFIG_METHOD_AUTO, + NM_SETTING_IP6_CONFIG_METHOD_DHCP, + NM_SETTING_IP6_CONFIG_METHOD_SHARED, + NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL); } static gboolean -dhcp_grace_period_expired(NMDevice *self, int addr_family) +connection_requires_carrier(NMConnection *connection) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - const int IS_IPv4 = NM_IS_IPv4(addr_family); + NMSettingIPConfig * s_ip4, *s_ip6; + NMSettingConnection *s_con; + gboolean ip4_carrier_wanted, ip6_carrier_wanted; + gboolean ip4_used = FALSE, ip6_used = FALSE; - priv->dhcp_data_x[IS_IPv4].grace_id = 0; - priv->dhcp_data_x[IS_IPv4].grace_pending = FALSE; + /* We can progress to IP_CONFIG now, so that we're enslaved. + * That may actually cause carrier to go up and thus continue activation. */ + s_con = nm_connection_get_setting_connection(connection); + if (nm_setting_connection_get_master(s_con)) + return FALSE; - _LOGI(LOGD_DHCPX(IS_IPv4), - "DHCPv%c: grace period expired", - nm_utils_addr_family_to_char(addr_family)); + ip4_carrier_wanted = connection_ip_method_requires_carrier(connection, AF_INET, &ip4_used); + if (ip4_carrier_wanted) { + /* If IPv4 wants a carrier and cannot fail, the whole connection + * requires a carrier regardless of the IPv6 method. + */ + s_ip4 = nm_connection_get_setting_ip4_config(connection); + if (s_ip4 && !nm_setting_ip_config_get_may_fail(s_ip4)) + return TRUE; + } - 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 */ + ip6_carrier_wanted = connection_ip_method_requires_carrier(connection, AF_INET6, &ip6_used); + 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; + } - return G_SOURCE_REMOVE; + /* 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 -dhcp_grace_period_expired_4(gpointer user_data) +have_any_ready_slaves(NMDevice *self) { - return dhcp_grace_period_expired(user_data, AF_INET); + 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; } -static gboolean -dhcp_grace_period_expired_6(gpointer user_data) +/*****************************************************************************/ +<<<<<<< HEAD +/* DHCPv6 stuff */ + +static void +dhcp6_cleanup(NMDevice *self, CleanupType cleanup_type, gboolean release) { - return dhcp_grace_period_expired(user_data, AF_INET6); + 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 -dhcp_grace_period_start(NMDevice *self, int addr_family) +dhcp6_lease_change(NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - const int IS_IPv4 = NM_IS_IPv4(addr_family); - guint32 timeout; + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + NMSettingsConnection *settings_connection; - /* 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. */ + if (!applied_config_get_current(&priv->dhcp6.ip6_config)) { + _LOGW(LOGD_DHCP6, "failed to get DHCPv6 config for rebind"); 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); + 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; } - priv->dhcp_data_x[IS_IPv4].grace_pending = TRUE; + nm_dispatcher_call_device(NM_DISPATCHER_ACTION_DHCP6_CHANGE, self, NULL, NULL, NULL, NULL); return TRUE; } + static void -dhcp4_fail(NMDevice *self, NMDhcpState dhcp_state) +dhcp6_fail(NMDevice *self, NMDhcpState dhcp_state) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + gboolean is_dhcp_managed; - _LOGD(LOGD_DHCP4, - "DHCPv4 failed (ip_state %s, was_active %d)", - _ip_state_to_string(priv->ip_state_4), - priv->dhcp_data_4.was_active); + _LOGD(LOGD_DHCP6, + "DHCPv6 failed (ip_state %s, was_active %d)", + _ip_state_to_string(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_4 == NM_DEVICE_IP_STATE_FAIL) + if (priv->ip_state_6 == 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; + is_dhcp_managed = (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_MANAGED); - /* 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 (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; - if (dhcp_grace_period_start(self, AF_INET)) - 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_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); - } -} - -static void -dhcp4_dad_cb(NMDevice *self, NMIP4Config **configs, gboolean success) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - 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); + 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 -dhcp4_state_changed(NMDhcpClient *client, +dhcp6_state_changed(NMDhcpClient *client, NMDhcpState state, - NMIP4Config * ip4_config, + NMIP6Config * ip6_config, GHashTable * options, gpointer user_data) { - NMDevice * self = NM_DEVICE(user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMIP4Config * manual, **configs; - NMConnection * connection; + 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_INET); - g_return_if_fail(!ip4_config || NM_IS_IP4_CONFIG(ip4_config)); + 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_DHCP4, "new DHCPv4 client state %d", state); + _LOGD(LOGD_DHCP6, "new DHCPv6 client state %d", state); 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_clear_g_source(&priv->dhcp_data_4.grace_id); - priv->dhcp_data_4.grace_pending = FALSE; - - /* After some failures, we have been able to renew the lease: - * update the ip state + 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. */ - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_FAIL) - _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_CONF); - - 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); - nm_dhcp_config_set_options(priv->dhcp_data_4.config, options); - _notify(self, PROP_DHCP4_CONFIG); + event_id = nm_dhcp_utils_get_dhcp6_event_id(options); - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF) { - connection = nm_device_get_applied_connection(self); - g_assert(connection); + if (ip6_config && event_id && priv->dhcp6.event_id + && nm_streq(event_id, priv->dhcp6.event_id)) { + NMDedupMultiIter ipconf_iter; + const NMPlatformIP6Address *a; - 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)); + 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); + } - configs = g_new0(NMIP4Config *, 3); - configs[0] = manual; - configs[1] = g_object_ref(ip4_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); - 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 (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: - dhcp4_fail(self, state); + 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_4 == NM_DEVICE_IP_STATE_CONF) + 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: - case NM_DHCP_STATE_TERMINATED: - dhcp4_fail(self, state); + dhcp6_fail(self, state); break; default: break; } } -static NMActStageReturn -dhcp4_start(NMDevice *self) +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_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; + 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; - connection = nm_device_get_applied_connection(self); g_return_val_if_fail(connection, FALSE); - s_ip4 = nm_connection_get_setting_ip4_config(connection); - + 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); - /* 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); + 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); + } - request_broadcast = FALSE; + 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); - bcast_hwaddr = nmp_link_address_get_as_bytes(&pllink->l_broadcast); - - str = nmp_object_link_udev_device_get_property_value(NMP_OBJECT_UP_CAST(pllink), - "ID_NET_DHCP_BROADCAST"); - if (str && _nm_utils_ascii_str_to_bool(str, FALSE)) { - /* Use the device property ID_NET_DHCP_BROADCAST setting, which may be set for interfaces - * requiring that the DHCPOFFER message is being broadcast because they can't handle unicast - * messages while not fully configured. - */ - request_broadcast = TRUE; - } - } + if (pllink) + hwaddr = nmp_link_address_get_as_bytes(&pllink->l_address); - 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); + iaid = _prop_get_ipvx_dhcp_iaid(self, AF_INET6, connection, TRUE, &iaid_explicit); + duid = _prop_get_ipv6_dhcp_duid(self, connection, hwaddr, &enforce_duid); - g_warn_if_fail(priv->dhcp_data_4.client == NULL); - priv->dhcp_data_4.client = nm_dhcp_manager_start_ip4( + priv->dhcp_data_6.client = nm_dhcp_manager_start_ip6( nm_dhcp_manager_get(), - nm_netns_get_multi_idx(nm_device_get_netns(self)), + nm_device_get_multi_index(self), nm_device_get_ip_iface(self), nm_device_get_ip_ifindex(self), - hwaddr, - bcast_hwaddr, + &ll_addr->address, 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), + 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), - client_id, - _prop_get_ipvx_dhcp_timeout(self, AF_INET), + duid, + enforce_duid, + iaid, + iaid_explicit, + _prop_get_ipvx_dhcp_timeout(self, AF_INET6), priv->dhcp_anycast_address, - NULL, - vendor_class_identifier, - reject_servers, + nm_setting_ip6_config_get_ip6_privacy(NM_SETTING_IP6_CONFIG(s_ip6)), + priv->dhcp6.needed_prefixes, &error); - if (!priv->dhcp_data_4.client) { - _LOGW(LOGD_DHCP4, "failure to start DHCP: %s", error->message); + if (!priv->dhcp_data_6.client) { + _LOGW(LOGD_DHCP6, "failure to start DHCPv6: %s", error->message); g_clear_error(&error); - return NM_ACT_STAGE_RETURN_FAILURE; + if (nm_device_sys_iface_state_is_external_or_assume(self)) + priv->dhcp_data_6.was_active = TRUE; + return FALSE; } - priv->dhcp_data_4.state_sigid = g_signal_connect(priv->dhcp_data_4.client, + priv->dhcp_data_6.state_sigid = g_signal_connect(priv->dhcp_data_6.client, NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, - G_CALLBACK(dhcp4_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_4.was_active = TRUE; + priv->dhcp_data_6.was_active = TRUE; - /* DHCP devices will be notified by the DHCP manager when stuff happens */ - return NM_ACT_STAGE_RETURN_POSTPONE; + return TRUE; } -gboolean -nm_device_dhcp4_renew(NMDevice *self, gboolean release) +static gboolean +dhcp6_start(NMDevice *self, gboolean wait_for_ll) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMConnection * connection; - g_return_val_if_fail(priv->dhcp_data_4.client != NULL, FALSE); - - _LOGI(LOGD_DHCP4, "DHCPv4 lease renewal requested"); - - /* Terminate old DHCP instance and release the old lease */ - dhcp4_cleanup(self, CLEANUP_TYPE_DECONFIGURE, release); - - /* Start DHCP again on the interface */ - return dhcp4_start(self) != NM_ACT_STAGE_RETURN_FAILURE; -} - -/*****************************************************************************/ - -static NMIP4Config * -shared4_new_config(NMDevice *self, NMConnection *connection) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMIP4Config * config; - NMSettingIPConfig * s_ip4; - NMPlatformIP4Address address = { - .addr_source = NM_IP_CONFIG_SOURCE_SHARED, - }; + nm_dbus_object_clear_and_unexport(&priv->dhcp_data_6.config); + priv->dhcp_data_6.config = nm_dhcp_config_new(AF_INET6); - g_return_val_if_fail(self, NULL); - g_return_val_if_fail(connection, NULL); + 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); - 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; + connection = nm_device_get_applied_connection(self); + g_return_val_if_fail(connection, 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); + if (wait_for_ll) { + /* ensure link local is ready... */ + if (!linklocal6_start(self)) { + /* wait for the LL address to show up */ + return TRUE; + } + /* already have the LL address; kick off DHCP */ } - config = nm_device_ip4_config_new(self); - nm_ip4_config_add_address(config, &address); - - return config; -} - -/*****************************************************************************/ - -static gboolean -connection_ip_method_requires_carrier(NMConnection *connection, - int addr_family, - gboolean * out_ip_enabled) -{ - const char *method; - - method = nm_utils_get_ip_config_method(connection, addr_family); - - if (NM_IS_IPv4(addr_family)) { - NM_SET_OUT(out_ip_enabled, !nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)); - return NM_IN_STRSET(method, - NM_SETTING_IP4_CONFIG_METHOD_AUTO, - NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL); - } + if (!dhcp6_start_with_link_ready(self, connection)) + return FALSE; - NM_SET_OUT(out_ip_enabled, - !NM_IN_STRSET(method, - NM_SETTING_IP6_CONFIG_METHOD_IGNORE, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED)); - return NM_IN_STRSET(method, - NM_SETTING_IP6_CONFIG_METHOD_AUTO, - NM_SETTING_IP6_CONFIG_METHOD_DHCP, - NM_SETTING_IP6_CONFIG_METHOD_SHARED, - NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL); + return TRUE; } -static gboolean -connection_requires_carrier(NMConnection *connection) +gboolean +nm_device_dhcp6_renew(NMDevice *self, gboolean release) { - NMSettingIPConfig * s_ip4, *s_ip6; - NMSettingConnection *s_con; - gboolean ip4_carrier_wanted, ip6_carrier_wanted; - gboolean ip4_used = FALSE, ip6_used = FALSE; - - /* We can progress to IP_CONFIG now, so that we're enslaved. - * That may actually cause carrier to go up and thus continue activation. */ - s_con = nm_connection_get_setting_connection(connection); - if (nm_setting_connection_get_master(s_con)) - return FALSE; - - ip4_carrier_wanted = connection_ip_method_requires_carrier(connection, AF_INET, &ip4_used); - if (ip4_carrier_wanted) { - /* If IPv4 wants a carrier and cannot fail, the whole connection - * requires a carrier regardless of the IPv6 method. - */ - s_ip4 = nm_connection_get_setting_ip4_config(connection); - if (s_ip4 && !nm_setting_ip_config_get_may_fail(s_ip4)) - return TRUE; - } - - ip6_carrier_wanted = connection_ip_method_requires_carrier(connection, AF_INET6, &ip6_used); - 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; - } + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + NMNDiscDHCPLevel mode; - /* 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; + g_return_val_if_fail(priv->dhcp_data_6.client != NULL, FALSE); - /* If both want a carrier, the whole connection wants a carrier */ - return ip4_carrier_wanted && ip6_carrier_wanted; -} + _LOGI(LOGD_DHCP6, "DHCPv6 lease renewal requested"); -static gboolean -have_any_ready_slaves(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - SlaveInfo * info; - CList * iter; + /* Terminate old DHCP instance and release the old lease */ + mode = priv->dhcp6.mode; + dhcp6_cleanup(self, CLEANUP_TYPE_DECONFIGURE, release); + priv->dhcp6.mode = mode; - /* 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; + /* Start DHCP again on the interface */ + return dhcp6_start(self, FALSE); } /*****************************************************************************/ +||||||| parent of a2bf185ef259 (core: use NML3ConfigData (WIP)) /* DHCPv6 stuff */ static void @@ -10035,6 +10140,8 @@ nm_device_dhcp6_renew(NMDevice *self, gboolean release) } /*****************************************************************************/ +======= +>>>>>>> a2bf185ef259 (core: use NML3ConfigData (WIP)) /* * Called on the requesting interface when a subnet can't be obtained @@ -10049,7 +10156,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"); } @@ -10068,25 +10175,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); + _dev_l3_cfg_commit(self); } /* @@ -10096,41 +10202,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; - 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); + /* FIXME(l3fcg): this entire code an approach seems flawed. It's flawed, because the + * very next RA will reset the changes. */ + + 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); + + _dev_l3_cfg_commit(self); } /*****************************************************************************/ static void -linklocal6_failed(NMDevice *self) +_dev_ll6_failed(NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); @@ -10139,17 +10251,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; @@ -10160,18 +10273,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); @@ -10182,14 +10295,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); } @@ -10208,17 +10321,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); @@ -10242,7 +10356,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"; @@ -10253,7 +10367,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; } @@ -10271,21 +10385,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); } 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 " @@ -10299,7 +10428,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; } @@ -10463,13 +10592,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; @@ -10477,7 +10609,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); @@ -10491,8 +10625,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 @@ -10519,9 +10656,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; } @@ -10704,244 +10841,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); - } - } + NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + int ifindex; - 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)); - } - } - - 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); - 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); +} - 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)) @@ -10964,28 +11005,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)) { @@ -10994,32 +11037,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); + + 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; - 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); + 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); + + _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_AC_6, NULL); + + if (priv->ac6_ndisc) { + nm_ndisc_stop(priv->ac6_ndisc); + g_clear_object(&priv->ac6_ndisc); } } @@ -11141,10 +11210,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); @@ -11193,52 +11262,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 @@ -11246,10 +11297,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"); @@ -11267,15 +11315,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; @@ -11297,7 +11342,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 @@ -11311,33 +11356,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 @@ -11347,23 +11389,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; } } @@ -11371,13 +11396,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); @@ -11389,22 +11414,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); + 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); @@ -11461,8 +11477,7 @@ 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); + nm_device_set_proxy_config(self); check_ip_state(self, TRUE, TRUE); } @@ -11654,8 +11669,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->shared4_rules) { + nm_utils_share_rules_apply(priv->shared4_rules, FALSE); + nm_clear_pointer(&priv->shared4_rules, nm_utils_share_rules_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", @@ -11710,29 +11783,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; - NMUtilsShareRules * share_rules; - - 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->shared4_rules); + 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, @@ -11740,19 +11821,23 @@ 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); - share_rules = nm_utils_share_rules_new(); + priv->shared4_rules = nm_utils_share_rules_new(); - nm_utils_share_rules_add_all_rules(share_rules, ip_iface, ip4_addr->address, ip4_addr->plen); + nm_utils_share_rules_add_all_rules(priv->shared4_rules, + ip_iface, + ip4_addr.address, + ip4_addr.plen); - nm_utils_share_rules_apply(share_rules, TRUE); - - nm_act_request_set_shared(req, share_rules); + nm_utils_share_rules_apply(priv->shared4_rules, TRUE); conn = nm_act_request_get_applied_connection(req); s_con = nm_connection_get_setting_connection(conn); @@ -11777,8 +11862,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, @@ -11786,81 +11873,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; -} + 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); -static void -arp_cleanup(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); + _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_SHARED_4, l3cd); - 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; - - 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(); - } - - 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; @@ -12021,6 +12056,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 @@ -12040,18 +12076,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. @@ -12076,73 +12112,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 @@ -12181,21 +12150,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) { @@ -12287,26 +12241,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); } } @@ -12396,37 +12338,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); @@ -12445,58 +12356,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); } static void @@ -12520,7 +12380,7 @@ reactivate_proxy_config(NMDevice *self) if (!priv->pacrunner_conf_id) return; - nm_device_set_proxy_config(self, priv->dhcp4.pac_url); + nm_device_set_proxy_config(self); _pacrunner_manager_add(self); } @@ -12741,6 +12601,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 @@ -13000,96 +12861,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, @@ -13481,11 +13252,12 @@ nm_device_get_proxy_config(NMDevice *self) } static void -nm_device_set_proxy_config(NMDevice *self, const char *pac_url) +nm_device_set_proxy_config(NMDevice *self) { NMDevicePrivate *priv; NMConnection * connection; NMSettingProxy * s_proxy = NULL; + const char * pac_url = NULL; g_return_if_fail(NM_IS_DEVICE(self)); @@ -13494,6 +13266,14 @@ nm_device_set_proxy_config(NMDevice *self, const char *pac_url) g_clear_object(&priv->proxy_config); priv->proxy_config = nm_proxy_config_new(); + if (priv->l3cds[L3_CONFIG_DATA_TYPE_DHCP_4].d) { + NMDhcpLease *lease; + + lease = + nm_l3_config_data_get_dhcp_lease(priv->l3cds[L3_CONFIG_DATA_TYPE_DHCP_4].d, AF_INET); + pac_url = nm_dhcp_lease_lookup_option(lease, "wpad"); + } + 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); @@ -13509,278 +13289,52 @@ nm_device_set_proxy_config(NMDevice *self, const char *pac_url) 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; + return NM_DEVICE_GET_PRIVATE(self)->dhcp_data_x[NM_IS_IPv4(addr_family)].config; } -NMIP4Config * -nm_device_get_ip4_config(NMDevice *self) +const NML3Cfg * +nm_device_get_l3cfg(NMDevice *self) { g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - return NM_DEVICE_GET_PRIVATE(self)->ip_config_4; + return NM_DEVICE_GET_PRIVATE(self)->l3cfg; } -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; - } - - return FALSE; -} - -void -nm_device_replace_vpn4_config(NMDevice *self, NMIP4Config *old, NMIP4Config *config) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - 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)); - - if (!_replace_vpn_config_in_list(&priv->vpn_configs_4, (GObject *) old, (GObject *) config)) - return; - - /* 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"); -} - -void -nm_device_set_dev2_ip_config(NMDevice *self, int addr_family, NMIPConfig *config) +const NML3ConfigData * +nm_device_get_l3cd(NMDevice *self, gboolean get_commited) { NMDevicePrivate *priv; - const int IS_IPv4 = NM_IS_IPv4(addr_family); - 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); + g_return_val_if_fail(NM_IS_DEVICE(self), NULL); priv = NM_DEVICE_GET_PRIVATE(self); - 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)); - } -} - -void -nm_device_replace_vpn6_config(NMDevice *self, NMIP6Config *old, NMIP6Config *config) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - 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)); - - if (!_replace_vpn_config_in_list(&priv->vpn_configs_6, (GObject *) old, (GObject *) config)) - return; + 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 gboolean 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); + _dev_l3_cfg_commit(self); } /*****************************************************************************/ static gboolean -dispatcher_cleanup(NMDevice *self) +_dispatcher_cleanup(NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); @@ -13794,7 +13348,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); @@ -13814,7 +13368,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; @@ -13822,11 +13376,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); } } @@ -14018,17 +13572,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); @@ -14167,15 +13725,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); return TRUE; } @@ -14238,43 +13788,10 @@ 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) { +#if 0 //XXX NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); int ifindex; GSList * iter; @@ -14401,6 +13918,7 @@ update_ext_ip_config(NMDevice *self, int addr_family, gboolean intersect_configs nm_ip6_config_subtract(priv->ext_ip_config_6, iter->data, 0); } } +#endif return TRUE; } @@ -14408,6 +13926,7 @@ update_ext_ip_config(NMDevice *self, int addr_family, gboolean intersect_configs static void update_ip_config(NMDevice *self, int addr_family) { +#if 0 //XXX NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); nm_assert_addr_family(addr_family); @@ -14426,22 +13945,13 @@ update_ip_config(NMDevice *self, int addr_family) 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); +#endif } static gboolean queued_ip_config_change(NMDevice *self, int addr_family) { +#if 0 //XXX NMDevicePrivate *priv; const int IS_IPv4 = NM_IS_IPv4(addr_family); @@ -14542,6 +14052,7 @@ queued_ip_config_change(NMDevice *self, int addr_family) set_unmanaged_external_down(self, TRUE); +#endif return G_SOURCE_REMOVE; } @@ -14565,6 +14076,7 @@ device_ipx_changed(NMPlatform * platform, int change_type_i, NMDevice * self) { +#if 0 //XXX const NMPObjectType obj_type = obj_type_i; const NMPlatformSignalChangeType change_type = change_type_i; NMDevicePrivate * priv; @@ -14611,6 +14123,7 @@ device_ipx_changed(NMPlatform * platform, default: g_return_if_reached(); } +#endif } /*****************************************************************************/ @@ -14865,12 +14378,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); @@ -15236,9 +14743,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 @@ -15806,7 +15317,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 */ @@ -15841,7 +15352,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); @@ -15860,6 +15371,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; @@ -15869,39 +15381,19 @@ _cleanup_generic_post(NMDevice *self, CleanupType cleanup_type) priv->linklocal6_dad_counter = 0; + priv->ipv6ll_has = FALSE; + priv->ipv6ll_addr = nm_ip_addr_zero.addr6; + 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); - 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; - - /* 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) { @@ -16068,18 +15560,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 @@ -16091,7 +15584,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; @@ -16136,10 +15628,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); @@ -16148,8 +15639,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")); @@ -16199,7 +15694,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")); @@ -16250,23 +15745,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) { @@ -16405,9 +15883,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; @@ -16417,8 +15895,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; @@ -16455,14 +15932,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); @@ -16731,11 +16208,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: @@ -16758,18 +16230,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)) @@ -17950,13 +17417,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); @@ -17991,24 +17455,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); @@ -18319,24 +17775,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); @@ -18388,15 +17827,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); @@ -18474,7 +17910,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); diff --git a/src/core/devices/nm-device.h b/src/core/devices/nm-device.h index 72777d0aaf..a2e4493465 100644 --- a/src/core/devices/nm-device.h +++ b/src/core/devices/nm-device.h @@ -390,14 +390,15 @@ 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); + //XXX: needs rework to not use NMIP4Config. void (*ip4_config_pre_commit)(NMDevice *self, NMIP4Config *config); /* Async deactivating (in the DEACTIVATING phase) */ @@ -507,13 +508,10 @@ 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 37feb2f442..9107a1047c 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 5d07c2117e..d6e33db730 100644 --- a/src/core/devices/ovs/nm-device-ovs-interface.c +++ b/src/core/devices/ovs/nm-device-ovs-interface.c @@ -180,10 +180,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); @@ -203,7 +203,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 2ecb95e881..0c089c466f 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/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 <linux/if_ether.h> - -#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 7ff0434ca9..1c7531da4d 100644 --- a/src/core/devices/wifi/nm-device-wifi-p2p.c +++ b/src/core/devices/wifi/nm-device-wifi-p2p.c @@ -555,10 +555,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 +582,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 0d210f0ab4..5a8de56669 100644 --- a/src/core/devices/wifi/nm-device-wifi.c +++ b/src/core/devices/wifi/nm-device-wifi.c @@ -3271,10 +3271,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 +3297,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 405ced64a1..0b44b752e0 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); @@ -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..a2c286c024 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 */ @@ -788,7 +808,9 @@ nm_modem_stage3_ip4_config_start(NMModem * self, void nm_modem_ip4_pre_commit(NMModem *modem, NMDevice *device, NMIP4Config *config) { - 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 @@ -1768,10 +1683,6 @@ nm_modem_init(NMModem *self) 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; } 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..a56f7b8bac 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); @@ -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 0dc21be630..2827c4e5fb 100644 --- a/src/core/dhcp/nm-dhcp-client.c +++ b/src/core/dhcp/nm-dhcp-client.c @@ -19,6 +19,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" @@ -39,8 +40,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, @@ -67,8 +66,6 @@ typedef struct _NMDhcpClientPrivate { guint watch_id; int addr_family; int ifindex; - guint32 route_table; - guint32 route_metric; guint32 timeout; guint32 iaid; NMDhcpState state; @@ -148,44 +145,6 @@ nm_dhcp_client_get_broadcast_hw_addr(NMDhcpClient *self) } 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) { g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), 0); @@ -424,20 +383,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); @@ -453,22 +414,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()) { @@ -485,7 +455,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 @@ -496,7 +466,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; } @@ -522,7 +492,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 @@ -740,7 +710,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); } /*****************************************************************************/ @@ -864,12 +834,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, }; @@ -897,9 +866,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); @@ -912,14 +882,12 @@ 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 { +<<<<<<< HEAD prefix = nm_dhcp_utils_ip6_prefix_from_options(str_options); ip_config = NM_IP_CONFIG_CAST(nm_dhcp_utils_ip6_config_from_options( nm_dhcp_client_get_multi_idx(self), @@ -927,9 +895,31 @@ nm_dhcp_client_handle_event(gpointer unused, priv->iface, str_options, NM_FLAGS_HAS(priv->client_flags, NM_DHCP_CLIENT_FLAGS_INFO_ONLY))); +||||||| parent of a2bf185ef259 (core: use NML3ConfigData (WIP)) + prefix = nm_dhcp_utils_ip6_prefix_from_options(str_options); + ip_config = NM_IP_CONFIG_CAST( + nm_dhcp_utils_ip6_config_from_options(nm_dhcp_client_get_multi_idx(self), + priv->ifindex, + priv->iface, + str_options, + priv->info_only)); +======= + 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, + priv->info_only); +>>>>>>> a2bf185ef259 (core: use NML3ConfigData (WIP)) } } 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)) { @@ -937,17 +927,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; } @@ -1018,12 +1007,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; @@ -1102,12 +1085,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); @@ -1300,24 +1277,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, @@ -1361,10 +1320,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 e61e01de3b..4d40c57054 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 */ @@ -33,8 +31,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" @@ -132,14 +128,6 @@ GBytes *nm_dhcp_client_get_hw_addr(NMDhcpClient *self); GBytes *nm_dhcp_client_get_broadcast_hw_addr(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); @@ -190,10 +178,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 83de1c156d..4681be7b61 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 2a59571cf3..31efd6d46b 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, @@ -405,9 +397,15 @@ nm_dhcp_manager_start_ip4(NMDhcpManager * self, GBytes * hwaddr, GBytes * bcast_hwaddr, const char * uuid, +<<<<<<< HEAD guint32 route_table, guint32 route_metric, NMDhcpClientFlags client_flags, +||||||| parent of a2bf185ef259 (core: use NML3ConfigData (WIP)) + guint32 route_table, + guint32 route_metric, +======= +>>>>>>> a2bf185ef259 (core: use NML3ConfigData (WIP)) gboolean send_hostname, const char * dhcp_hostname, const char * dhcp_fqdn, @@ -457,6 +455,7 @@ nm_dhcp_manager_start_ip4(NMDhcpManager * self, } } +<<<<<<< HEAD return client_start( self, AF_INET, @@ -485,6 +484,63 @@ nm_dhcp_manager_start_ip4(NMDhcpManager * self, vendor_class_identifier, reject_servers, error); +||||||| parent of a2bf185ef259 (core: use NML3ConfigData (WIP)) + return client_start(self, + AF_INET, + multi_idx, + iface, + ifindex, + hwaddr, + bcast_hwaddr, + uuid, + route_table, + route_metric, + NULL, + dhcp_client_id, + FALSE, + 0, + FALSE, + timeout, + dhcp_anycast_addr, + hostname, + use_fqdn, + hostname_flags, + mud_url, + FALSE, + 0, + last_ip_address, + 0, + vendor_class_identifier, + reject_servers, + error); +======= + return client_start(self, + AF_INET, + multi_idx, + iface, + ifindex, + hwaddr, + bcast_hwaddr, + uuid, + NULL, + dhcp_client_id, + FALSE, + 0, + FALSE, + timeout, + dhcp_anycast_addr, + hostname, + use_fqdn, + hostname_flags, + mud_url, + FALSE, + 0, + last_ip_address, + 0, + vendor_class_identifier, + reject_servers, + error); +>>>>>>> a2bf185ef259 (core: use NML3ConfigData (WIP)) } /* Caller owns a reference to the NMDhcpClient on return */ @@ -495,9 +551,15 @@ nm_dhcp_manager_start_ip6(NMDhcpManager * self, int ifindex, const struct in6_addr * ll_addr, const char * uuid, +<<<<<<< HEAD guint32 route_table, guint32 route_metric, NMDhcpClientFlags client_flags, +||||||| parent of a2bf185ef259 (core: use NML3ConfigData (WIP)) + guint32 route_table, + guint32 route_metric, +======= +>>>>>>> a2bf185ef259 (core: use NML3ConfigData (WIP)) gboolean send_hostname, const char * dhcp_hostname, NMDhcpHostnameFlags hostname_flags, @@ -533,8 +595,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 8f6c62afec..2096125172 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,9 +38,15 @@ NMDhcpClient *nm_dhcp_manager_start_ip4(NMDhcpManager * manager, GBytes * hwaddr, GBytes * bcast_hwaddr, const char * uuid, +<<<<<<< HEAD guint32 route_table, guint32 route_metric, NMDhcpClientFlags client_flags, +||||||| parent of a2bf185ef259 (core: use NML3ConfigData (WIP)) + guint32 route_table, + guint32 route_metric, +======= +>>>>>>> a2bf185ef259 (core: use NML3ConfigData (WIP)) gboolean send_hostname, const char * dhcp_hostname, const char * dhcp_fqdn, @@ -61,9 +66,15 @@ NMDhcpClient *nm_dhcp_manager_start_ip6(NMDhcpManager * manager, int ifindex, const struct in6_addr * ll_addr, const char * uuid, +<<<<<<< HEAD guint32 route_table, guint32 route_metric, NMDhcpClientFlags client_flags, +||||||| parent of a2bf185ef259 (core: use NML3ConfigData (WIP)) + guint32 route_table, + guint32 route_metric, +======= +>>>>>>> a2bf185ef259 (core: use NML3ConfigData (WIP)) gboolean send_hostname, const char * dhcp_hostname, NMDhcpHostnameFlags hostname_flags, diff --git a/src/core/dhcp/nm-dhcp-nettools.c b/src/core/dhcp/nm-dhcp-nettools.c index c1a26eca62..7841153445 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; @@ -362,26 +361,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, + })); } nm_dhcp_option_add_option(options, @@ -416,17 +411,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, @@ -460,19 +455,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, @@ -483,7 +476,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; @@ -501,7 +494,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, @@ -536,34 +529,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); + + nm_l3_config_data_set_source(l3cd, NM_IP_CONFIG_SOURCE_DHCP); + + options = nm_dhcp_option_create_options_dict(); - if (!lease_parse_address(lease, ip4_config, options, error)) + if (!lease_parse_address(lease, l3cd, options, error)) return NULL; r = n_dhcp4_client_lease_get_server_identifier(lease, &v_inaddr_s); @@ -582,13 +574,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)) { @@ -613,7 +601,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); } } @@ -625,18 +613,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) { @@ -647,7 +634,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)) { @@ -694,21 +681,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); } /*****************************************************************************/ @@ -740,36 +726,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 @@ -804,10 +784,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); @@ -859,13 +839,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; } diff --git a/src/core/dhcp/nm-dhcp-systemd.c b/src/core/dhcp/nm-dhcp-systemd.c index 5b06c65dba..a6d6dae819 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) { @@ -443,8 +438,12 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx, nm_dhcp_option_take_option(options, AF_INET, private_options[i].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); } /*****************************************************************************/ @@ -452,43 +451,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 @@ -507,10 +501,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: @@ -745,32 +739,34 @@ ip4_start(NMDhcpClient *client, 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); @@ -784,15 +780,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, @@ -806,7 +806,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); } @@ -816,7 +816,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); } @@ -825,30 +825,31 @@ 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"); +<<<<<<< HEAD ip6_config = lease_to_ip6_config(nm_dhcp_client_get_multi_idx(NM_DHCP_CLIENT(self)), iface, @@ -859,17 +860,32 @@ bound6_handle(NMDhcpSystemd *self) &options, ts, &error); - - if (!ip6_config) { +||||||| parent of a2bf185ef259 (core: use NML3ConfigData (WIP)) + ip6_config = lease_to_ip6_config(nm_dhcp_client_get_multi_idx(NM_DHCP_CLIENT(self)), + iface, + nm_dhcp_client_get_ifindex(NM_DHCP_CLIENT(self)), + lease, + nm_dhcp_client_get_info_only(NM_DHCP_CLIENT(self)), + &options, + ts, + &error); +======= + 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_dhcp_client_get_info_only(NM_DHCP_CLIENT(self)), + ts, + &error); +>>>>>>> a2bf185ef259 (core: use NML3ConfigData (WIP)) + + 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, @@ -894,11 +910,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 c3cbe610b1..56328100d3 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,14 @@ 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); + 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 +619,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(); + + address = (NMPlatformIP6Address){ + .plen = 128, + .timestamp = now, + }; - ip6_config = nm_ip6_config_new(multi_idx, ifindex); + 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 +665,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 +684,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 +694,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 +827,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 <stdlib.h> -#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/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 9552f7de81..37e0e4849e 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -94,7 +94,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', diff --git a/src/core/ndisc/nm-ndisc.c b/src/core/ndisc/nm-ndisc.c index 736fc937d7..7009daf636 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 31f736a8f0..a01ff12010 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 cb4b0260a5..b34ddefccf 100644 --- a/src/core/nm-act-request.c +++ b/src/core/nm-act-request.c @@ -22,8 +22,7 @@ #include "libnm-core-aux-intern/nm-auth-subject.h" typedef struct { - CList call_ids_lst_head; - NMUtilsShareRules *share_rules; + CList call_ids_lst_head; } NMActRequestPrivate; struct _NMActRequest { @@ -248,36 +247,6 @@ nm_act_request_clear_secrets(NMActRequest *self) /*****************************************************************************/ -NMUtilsShareRules * -nm_act_request_get_shared(NMActRequest *req) -{ - g_return_val_if_fail(NM_IS_ACT_REQUEST(req), FALSE); - - return NM_ACT_REQUEST_GET_PRIVATE(req)->share_rules; -} - -void -nm_act_request_set_shared(NMActRequest *req, NMUtilsShareRules *rules) -{ - NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE(req); - - g_return_if_fail(NM_IS_ACT_REQUEST(req)); - - if (priv->share_rules == rules) - return; - - if (priv->share_rules) { - nm_utils_share_rules_apply(priv->share_rules, FALSE); - priv->share_rules = NULL; - } - if (rules) { - priv->share_rules = rules; - nm_utils_share_rules_apply(priv->share_rules, TRUE); - } -} - -/*****************************************************************************/ - static void device_notify(GObject *object, GParamSpec *pspec, gpointer self) { @@ -506,11 +475,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->share_rules) { - nm_utils_share_rules_apply(priv->share_rules, FALSE); - nm_clear_pointer(&priv->share_rules, nm_utils_share_rules_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 2a568430ac..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 _NMUtilsShareRules; - -struct _NMUtilsShareRules *nm_act_request_get_shared(NMActRequest *req); - -void nm_act_request_set_shared(NMActRequest *req, struct _NMUtilsShareRules *rules); - -/*****************************************************************************/ - /* Secrets handling */ typedef void (*NMActRequestSecretsFunc)(NMActRequest * req, diff --git a/src/core/nm-dhcp-config.c b/src/core/nm-dhcp-config.c index c77e0adbaf..96b5312b4a 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..efbe50a339 100644 --- a/src/core/nm-dispatcher.c +++ b/src/core/nm-dispatcher.c @@ -16,8 +16,7 @@ #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" @@ -167,31 +166,30 @@ dump_proxy_to_props(NMProxyConfig *proxy, GVariantBuilder *builder) } 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 +223,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 +252,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 +292,9 @@ 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; + NMProxyConfig * proxy_config; + 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, @@ -333,13 +325,11 @@ fill_device_props(NMDevice * 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); + } dhcp_config = nm_device_get_dhcp_config(device, AF_INET); if (dhcp_config) @@ -351,19 +341,18 @@ 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(NMProxyConfig * proxy_config, + 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); + } } static const char * @@ -480,8 +469,7 @@ _dispatcher_call(NMDispatcherAction action, 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 +581,9 @@ _dispatcher_call(NMDispatcherAction action, &device_ip6_props, &device_dhcp4_props, &device_dhcp6_props); - if (vpn_ip4_config || vpn_ip6_config) { + if (l3cd) { fill_vpn_props(vpn_proxy_config, - vpn_ip4_config, - vpn_ip6_config, + l3cd, &vpn_proxy_props, &vpn_ip4_props, &vpn_ip6_props); @@ -694,7 +681,6 @@ nm_dispatcher_call_hostname(NMDispatcherFunc callback, NULL, NULL, NULL, - NULL, callback, user_data, out_call_id); @@ -745,7 +731,6 @@ nm_dispatcher_call_device(NMDispatcherAction action, NULL, NULL, NULL, - NULL, callback, user_data, out_call_id); @@ -791,7 +776,6 @@ nm_dispatcher_call_device_sync(NMDispatcherAction action, NULL, NULL, NULL, - NULL, NULL); } @@ -803,8 +787,7 @@ nm_dispatcher_call_device_sync(NMDispatcherAction action, * @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 @@ -822,8 +805,7 @@ nm_dispatcher_call_vpn(NMDispatcherAction action, 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) @@ -837,8 +819,7 @@ nm_dispatcher_call_vpn(NMDispatcherAction action, NM_CONNECTIVITY_UNKNOWN, vpn_iface, vpn_proxy_config, - vpn_ip4_config, - vpn_ip6_config, + l3cd, callback, user_data, out_call_id); @@ -852,8 +833,7 @@ nm_dispatcher_call_vpn(NMDispatcherAction action, * @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. @@ -867,8 +847,7 @@ nm_dispatcher_call_vpn_sync(NMDispatcherAction action, 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, @@ -879,8 +858,7 @@ nm_dispatcher_call_vpn_sync(NMDispatcherAction action, NM_CONNECTIVITY_UNKNOWN, vpn_iface, vpn_proxy_config, - vpn_ip4_config, - vpn_ip6_config, + l3cd, NULL, NULL, NULL); @@ -914,7 +892,6 @@ nm_dispatcher_call_connectivity(NMConnectivityState 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..783b3ebe66 100644 --- a/src/core/nm-dispatcher.h +++ b/src/core/nm-dispatcher.h @@ -49,8 +49,7 @@ gboolean nm_dispatcher_call_vpn(NMDispatcherAction action, 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); @@ -61,8 +60,7 @@ gboolean nm_dispatcher_call_vpn_sync(NMDispatcherAction action, 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 227363deac..9440752828 100644 --- a/src/core/nm-iface-helper.c +++ b/src/core/nm-iface-helper.c @@ -19,6 +19,8 @@ #include "libnm-glib-aux/nm-c-list.h" #include "main-utils.h" +#include "nm-ip4-config.h" +#include "nm-ip6-config.h" #include "NetworkManagerUtils.h" #include "libnm-platform/nm-linux-platform.h" #include "libnm-platform/nm-platform-utils.h" @@ -93,16 +95,18 @@ static struct { /*****************************************************************************/ 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)); @@ -666,9 +670,15 @@ main(int argc, char *argv[]) hwaddr, bcast_hwaddr, global_opt.uuid, +<<<<<<< HEAD RT_TABLE_MAIN, global_opt.priority_v4, NM_DHCP_CLIENT_FLAGS_NONE, +||||||| parent of a2bf185ef259 (core: use NML3ConfigData (WIP)) + RT_TABLE_MAIN, + global_opt.priority_v4, +======= +>>>>>>> a2bf185ef259 (core: use NML3ConfigData (WIP)) !!global_opt.dhcp4_hostname, global_opt.dhcp4_hostname, global_opt.dhcp4_fqdn, diff --git a/src/core/nm-ip-config.c b/src/core/nm-ip-config.c index 2426eb4941..20584d10d8 100644 --- a/src/core/nm-ip-config.c +++ b/src/core/nm-ip-config.c @@ -48,8 +48,8 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps switch (prop_id) { case PROP_L3CFG: /* construct-only */ - priv->l3cfg = nm_g_object_ref(g_value_get_pointer(value)); - nm_assert(!priv->l3cfg || NM_IS_L3CFG(priv->l3cfg)); + priv->l3cfg = g_object_ref(g_value_get_pointer(value)); + nm_assert(NM_IS_L3CFG(priv->l3cfg)); break; case PROP_IS_VPN: /* construct-only */ @@ -94,7 +94,7 @@ 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); } diff --git a/src/core/nm-ip4-config.h b/src/core/nm-ip4-config.h index 7032a2385e..11e3617ce9 100644 --- a/src/core/nm-ip4-config.h +++ b/src/core/nm-ip4-config.h @@ -105,6 +105,8 @@ typedef struct _NMIP4ConfigClass NMIP4ConfigClass; GType nm_ip4_config_get_type(void); +NMIP4Config *nm_ip4_config_new_l3cfg(NML3Cfg *l3cfg); + NMIP4Config *nm_ip4_config_new(NMDedupMultiIndex *multi_idx, int ifindex); NMIP4Config *nm_ip4_config_clone(const NMIP4Config *self); diff --git a/src/core/nm-ip6-config.h b/src/core/nm-ip6-config.h index 4aa0ee4e58..61d217d2f8 100644 --- a/src/core/nm-ip6-config.h +++ b/src/core/nm-ip6-config.h @@ -60,6 +60,8 @@ typedef struct _NMIP6ConfigClass NMIP6ConfigClass; GType nm_ip6_config_get_type(void); +NMIP6Config *nm_ip6_config_new_l3cfg(NML3Cfg *l3cfg); + NMIP6Config *nm_ip6_config_new(struct _NMDedupMultiIndex *multi_idx, int ifindex); NMIP6Config *nm_ip6_config_new_cloned(const NMIP6Config *src); diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c index 216dc8d2dd..33366d5dfd 100644 --- a/src/core/nm-manager.c +++ b/src/core/nm-manager.c @@ -2595,8 +2595,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-policy.c b/src/core/nm-policy.c index 52d9b34e0c..d16082cb85 100644 --- a/src/core/nm-policy.c +++ b/src/core/nm-policy.c @@ -1039,10 +1039,14 @@ get_best_ip_config(NMPolicy * self, nm_assert(device); + /* FIXME(l3cfg) */ + conf = NULL; +#if 0 if (addr_family == AF_INET) conf = nm_device_get_ip4_config(device); else conf = nm_device_get_ip6_config(device); +#endif NM_SET_OUT(out_device, device); NM_SET_OUT(out_vpn, NULL); @@ -1906,9 +1910,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: @@ -2015,6 +2017,8 @@ device_state_changed(NMDevice * device, nm_dns_manager_begin_updates(priv->dns_manager, __func__); + /* FIXME(l3cfg) */ +#if 0 ip4_config = nm_device_get_ip4_config(device); if (ip4_config) _dns_manager_set_ip_config(priv->dns_manager, @@ -2027,6 +2031,7 @@ device_state_changed(NMDevice * device, NM_IP_CONFIG_CAST(ip6_config), NM_DNS_IP_CONFIG_TYPE_DEFAULT, device); +#endif update_routing_and_dns(self, FALSE, device); 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/systemd/meson.build b/src/core/systemd/meson.build index c0d8a27c07..fb1e812fa4 100644 --- a/src/core/systemd/meson.build +++ b/src/core/systemd/meson.build @@ -25,8 +25,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/core/systemd/nm-sd.h b/src/core/systemd/nm-sd.h index 0ea4be2229..ad183c67f3 100644 --- a/src/core/systemd/nm-sd.h +++ b/src/core/systemd/nm-sd.h @@ -9,7 +9,6 @@ #include "systemd/src/systemd/sd-dhcp-client.h" #include "systemd/src/systemd/sd-dhcp6-client.h" #include "systemd/src/systemd/sd-lldp.h" -#include "systemd/src/systemd/sd-ipv4ll.h" /*****************************************************************************/ diff --git a/src/core/systemd/src/libsystemd-network/sd-ipv4acd.c b/src/core/systemd/src/libsystemd-network/sd-ipv4acd.c deleted file mode 100644 index af83f51954..0000000000 --- a/src/core/systemd/src/libsystemd-network/sd-ipv4acd.c +++ /dev/null @@ -1,555 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/*** - Copyright © 2014 Axis Communications AB. All rights reserved. -***/ - -#include "nm-sd-adapt-core.h" - -#include <arpa/inet.h> -#include <errno.h> -#include <netinet/if_ether.h> -#include <stdio.h> -#include <stdlib.h> - -#include "sd-ipv4acd.h" - -#include "alloc-util.h" -#include "arp-util.h" -#include "ether-addr-util.h" -#include "event-util.h" -#include "fd-util.h" -#include "in-addr-util.h" -#include "log-link.h" -#include "network-common.h" -#include "random-util.h" -#include "siphash24.h" -#include "string-table.h" -#include "string-util.h" -#include "time-util.h" - -/* Constants from the RFC */ -#define PROBE_WAIT_USEC (1U * USEC_PER_SEC) -#define PROBE_NUM 3U -#define PROBE_MIN_USEC (1U * USEC_PER_SEC) -#define PROBE_MAX_USEC (2U * USEC_PER_SEC) -#define ANNOUNCE_WAIT_USEC (2U * USEC_PER_SEC) -#define ANNOUNCE_NUM 2U -#define ANNOUNCE_INTERVAL_USEC (2U * USEC_PER_SEC) -#define MAX_CONFLICTS 10U -#define RATE_LIMIT_INTERVAL_USEC (60U * USEC_PER_SEC) -#define DEFEND_INTERVAL_USEC (10U * USEC_PER_SEC) - -typedef enum IPv4ACDState { - IPV4ACD_STATE_INIT, - IPV4ACD_STATE_STARTED, - IPV4ACD_STATE_WAITING_PROBE, - IPV4ACD_STATE_PROBING, - IPV4ACD_STATE_WAITING_ANNOUNCE, - IPV4ACD_STATE_ANNOUNCING, - IPV4ACD_STATE_RUNNING, - _IPV4ACD_STATE_MAX, - _IPV4ACD_STATE_INVALID = -EINVAL, -} IPv4ACDState; - -struct sd_ipv4acd { - unsigned n_ref; - - IPv4ACDState state; - int ifindex; - int fd; - - char *ifname; - unsigned n_iteration; - unsigned n_conflict; - - sd_event_source *receive_message_event_source; - sd_event_source *timer_event_source; - - usec_t defend_window; - be32_t address; - - /* External */ - struct ether_addr mac_addr; - - sd_event *event; - int event_priority; - sd_ipv4acd_callback_t callback; - void* userdata; -}; - -#define log_ipv4acd_errno(acd, error, fmt, ...) \ - ({ \ - int _e = (error); \ - if (DEBUG_LOGGING) \ - log_interface_full_errno( \ - sd_ipv4acd_get_ifname(acd), \ - LOG_DEBUG, _e, "IPv4ACD: " fmt, \ - ##__VA_ARGS__); \ - -ERRNO_VALUE(_e); \ - }) -#define log_ipv4acd(acd, fmt, ...) \ - log_ipv4acd_errno(acd, 0, fmt, ##__VA_ARGS__) - -static const char * const ipv4acd_state_table[_IPV4ACD_STATE_MAX] = { - [IPV4ACD_STATE_INIT] = "init", - [IPV4ACD_STATE_STARTED] = "started", - [IPV4ACD_STATE_WAITING_PROBE] = "waiting-probe", - [IPV4ACD_STATE_PROBING] = "probing", - [IPV4ACD_STATE_WAITING_ANNOUNCE] = "waiting-announce", - [IPV4ACD_STATE_ANNOUNCING] = "announcing", - [IPV4ACD_STATE_RUNNING] = "running", -}; - -DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(ipv4acd_state, IPv4ACDState); - -static void ipv4acd_set_state(sd_ipv4acd *acd, IPv4ACDState st, bool reset_counter) { - assert(acd); - assert(st < _IPV4ACD_STATE_MAX); - - if (st != acd->state) - log_ipv4acd(acd, "%s -> %s", ipv4acd_state_to_string(acd->state), ipv4acd_state_to_string(st)); - - if (st == acd->state && !reset_counter) - acd->n_iteration++; - else { - acd->state = st; - acd->n_iteration = 0; - } -} - -static void ipv4acd_reset(sd_ipv4acd *acd) { - assert(acd); - - (void) event_source_disable(acd->timer_event_source); - acd->receive_message_event_source = sd_event_source_unref(acd->receive_message_event_source); - - acd->fd = safe_close(acd->fd); - - ipv4acd_set_state(acd, IPV4ACD_STATE_INIT, true); -} - -static sd_ipv4acd *ipv4acd_free(sd_ipv4acd *acd) { - assert(acd); - - acd->timer_event_source = sd_event_source_unref(acd->timer_event_source); - - ipv4acd_reset(acd); - sd_ipv4acd_detach_event(acd); - free(acd->ifname); - return mfree(acd); -} - -DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_ipv4acd, sd_ipv4acd, ipv4acd_free); - -int sd_ipv4acd_new(sd_ipv4acd **ret) { - _cleanup_(sd_ipv4acd_unrefp) sd_ipv4acd *acd = NULL; - - assert_return(ret, -EINVAL); - - acd = new(sd_ipv4acd, 1); - if (!acd) - return -ENOMEM; - - *acd = (sd_ipv4acd) { - .n_ref = 1, - .state = IPV4ACD_STATE_INIT, - .ifindex = -1, - .fd = -1, - }; - - *ret = TAKE_PTR(acd); - - return 0; -} - -static void ipv4acd_client_notify(sd_ipv4acd *acd, int event) { - assert(acd); - - if (!acd->callback) - return; - - acd->callback(acd, event, acd->userdata); -} - -int sd_ipv4acd_stop(sd_ipv4acd *acd) { - IPv4ACDState old_state; - - if (!acd) - return 0; - - old_state = acd->state; - - ipv4acd_reset(acd); - - if (old_state == IPV4ACD_STATE_INIT) - return 0; - - log_ipv4acd(acd, "STOPPED"); - - ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_STOP); - - return 0; -} - -static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata); - -static int ipv4acd_set_next_wakeup(sd_ipv4acd *acd, usec_t usec, usec_t random_usec) { - usec_t next_timeout, time_now; - - assert(acd); - - next_timeout = usec; - - if (random_usec > 0) - next_timeout += (usec_t) random_u64() % random_usec; - - assert_se(sd_event_now(acd->event, clock_boottime_or_monotonic(), &time_now) >= 0); - - return event_reset_time(acd->event, &acd->timer_event_source, - clock_boottime_or_monotonic(), - time_now + next_timeout, 0, - ipv4acd_on_timeout, acd, - acd->event_priority, "ipv4acd-timer", true); -} - -static bool ipv4acd_arp_conflict(sd_ipv4acd *acd, struct ether_arp *arp) { - assert(acd); - assert(arp); - - /* see the BPF */ - if (memcmp(arp->arp_spa, &acd->address, sizeof(acd->address)) == 0) - return true; - - /* the TPA matched instead of the SPA, this is not a conflict */ - return false; -} - -static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) { - sd_ipv4acd *acd = userdata; - int r = 0; - - assert(acd); - - switch (acd->state) { - - case IPV4ACD_STATE_STARTED: - ipv4acd_set_state(acd, IPV4ACD_STATE_WAITING_PROBE, true); - - if (acd->n_conflict >= MAX_CONFLICTS) { - char ts[FORMAT_TIMESPAN_MAX]; - log_ipv4acd(acd, "Max conflicts reached, delaying by %s", format_timespan(ts, sizeof(ts), RATE_LIMIT_INTERVAL_USEC, 0)); - - r = ipv4acd_set_next_wakeup(acd, RATE_LIMIT_INTERVAL_USEC, PROBE_WAIT_USEC); - if (r < 0) - goto fail; - } else { - r = ipv4acd_set_next_wakeup(acd, 0, PROBE_WAIT_USEC); - if (r < 0) - goto fail; - } - - break; - - case IPV4ACD_STATE_WAITING_PROBE: - case IPV4ACD_STATE_PROBING: - /* Send a probe */ - r = arp_send_probe(acd->fd, acd->ifindex, acd->address, &acd->mac_addr); - if (r < 0) { - log_ipv4acd_errno(acd, r, "Failed to send ARP probe: %m"); - goto fail; - } else { - _cleanup_free_ char *address = NULL; - union in_addr_union addr = { .in.s_addr = acd->address }; - - (void) in_addr_to_string(AF_INET, &addr, &address); - log_ipv4acd(acd, "Probing %s", strna(address)); - } - - if (acd->n_iteration < PROBE_NUM - 2) { - ipv4acd_set_state(acd, IPV4ACD_STATE_PROBING, false); - - r = ipv4acd_set_next_wakeup(acd, PROBE_MIN_USEC, (PROBE_MAX_USEC-PROBE_MIN_USEC)); - if (r < 0) - goto fail; - } else { - ipv4acd_set_state(acd, IPV4ACD_STATE_WAITING_ANNOUNCE, true); - - r = ipv4acd_set_next_wakeup(acd, ANNOUNCE_WAIT_USEC, 0); - if (r < 0) - goto fail; - } - - break; - - case IPV4ACD_STATE_ANNOUNCING: - if (acd->n_iteration >= ANNOUNCE_NUM - 1) { - ipv4acd_set_state(acd, IPV4ACD_STATE_RUNNING, false); - break; - } - - _fallthrough_; - case IPV4ACD_STATE_WAITING_ANNOUNCE: - /* Send announcement packet */ - r = arp_send_announcement(acd->fd, acd->ifindex, acd->address, &acd->mac_addr); - if (r < 0) { - log_ipv4acd_errno(acd, r, "Failed to send ARP announcement: %m"); - goto fail; - } else - log_ipv4acd(acd, "ANNOUNCE"); - - ipv4acd_set_state(acd, IPV4ACD_STATE_ANNOUNCING, false); - - r = ipv4acd_set_next_wakeup(acd, ANNOUNCE_INTERVAL_USEC, 0); - if (r < 0) - goto fail; - - if (acd->n_iteration == 0) { - acd->n_conflict = 0; - ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_BIND); - } - - break; - - default: - assert_not_reached("Invalid state."); - } - - return 0; - -fail: - sd_ipv4acd_stop(acd); - return 0; -} - -static void ipv4acd_on_conflict(sd_ipv4acd *acd) { - _cleanup_free_ char *address = NULL; - union in_addr_union addr = { .in.s_addr = acd->address }; - - assert(acd); - - acd->n_conflict++; - - (void) in_addr_to_string(AF_INET, &addr, &address); - log_ipv4acd(acd, "Conflict on %s (%u)", strna(address), acd->n_conflict); - - ipv4acd_reset(acd); - ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_CONFLICT); -} - -static int ipv4acd_on_packet( - sd_event_source *s, - int fd, - uint32_t revents, - void *userdata) { - - sd_ipv4acd *acd = userdata; - struct ether_arp packet; - ssize_t n; - int r; - - assert(s); - assert(acd); - assert(fd >= 0); - - n = recv(fd, &packet, sizeof(struct ether_arp), 0); - if (n < 0) { - if (IN_SET(errno, EAGAIN, EINTR)) - return 0; - - log_ipv4acd_errno(acd, errno, "Failed to read ARP packet: %m"); - goto fail; - } - if ((size_t) n != sizeof(struct ether_arp)) { - log_ipv4acd(acd, "Ignoring too short ARP packet."); - return 0; - } - - switch (acd->state) { - - case IPV4ACD_STATE_ANNOUNCING: - case IPV4ACD_STATE_RUNNING: - - if (ipv4acd_arp_conflict(acd, &packet)) { - usec_t ts; - - assert_se(sd_event_now(acd->event, clock_boottime_or_monotonic(), &ts) >= 0); - - /* Defend address */ - if (ts > acd->defend_window) { - acd->defend_window = ts + DEFEND_INTERVAL_USEC; - r = arp_send_announcement(acd->fd, acd->ifindex, acd->address, &acd->mac_addr); - if (r < 0) { - log_ipv4acd_errno(acd, r, "Failed to send ARP announcement: %m"); - goto fail; - } else - log_ipv4acd(acd, "DEFEND"); - - } else - ipv4acd_on_conflict(acd); - } - break; - - case IPV4ACD_STATE_WAITING_PROBE: - case IPV4ACD_STATE_PROBING: - case IPV4ACD_STATE_WAITING_ANNOUNCE: - /* BPF ensures this packet indicates a conflict */ - ipv4acd_on_conflict(acd); - break; - - default: - assert_not_reached("Invalid state."); - } - - return 0; - -fail: - sd_ipv4acd_stop(acd); - return 0; -} - -int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int ifindex) { - assert_return(acd, -EINVAL); - assert_return(ifindex > 0, -EINVAL); - assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY); - - acd->ifindex = ifindex; - - return 0; -} - -int sd_ipv4acd_get_ifindex(sd_ipv4acd *acd) { - if (!acd) - return -EINVAL; - - return acd->ifindex; -} - -int sd_ipv4acd_set_ifname(sd_ipv4acd *acd, const char *ifname) { - assert_return(acd, -EINVAL); - assert_return(ifname, -EINVAL); - - if (!ifname_valid_full(ifname, IFNAME_VALID_ALTERNATIVE)) - return -EINVAL; - - return free_and_strdup(&acd->ifname, ifname); -} - -const char *sd_ipv4acd_get_ifname(sd_ipv4acd *acd) { - if (!acd) - return NULL; - - return get_ifname(acd->ifindex, &acd->ifname); -} - -int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr) { - assert_return(acd, -EINVAL); - assert_return(addr, -EINVAL); - assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY); - - acd->mac_addr = *addr; - - return 0; -} - -int sd_ipv4acd_detach_event(sd_ipv4acd *acd) { - assert_return(acd, -EINVAL); - - acd->event = sd_event_unref(acd->event); - - return 0; -} - -int sd_ipv4acd_attach_event(sd_ipv4acd *acd, sd_event *event, int64_t priority) { - int r; - - assert_return(acd, -EINVAL); - assert_return(!acd->event, -EBUSY); - - if (event) - acd->event = sd_event_ref(event); - else { - r = sd_event_default(&acd->event); - if (r < 0) - return r; - } - - acd->event_priority = priority; - - return 0; -} - -int sd_ipv4acd_set_callback(sd_ipv4acd *acd, sd_ipv4acd_callback_t cb, void *userdata) { - assert_return(acd, -EINVAL); - - acd->callback = cb; - acd->userdata = userdata; - - return 0; -} - -int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address) { - assert_return(acd, -EINVAL); - assert_return(address, -EINVAL); - assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY); - - acd->address = address->s_addr; - - return 0; -} - -int sd_ipv4acd_get_address(sd_ipv4acd *acd, struct in_addr *address) { - assert_return(acd, -EINVAL); - assert_return(address, -EINVAL); - - address->s_addr = acd->address; - - return 0; -} - -int sd_ipv4acd_is_running(sd_ipv4acd *acd) { - assert_return(acd, false); - - return acd->state != IPV4ACD_STATE_INIT; -} - -int sd_ipv4acd_start(sd_ipv4acd *acd, bool reset_conflicts) { - int r; - - assert_return(acd, -EINVAL); - assert_return(acd->event, -EINVAL); - assert_return(acd->ifindex > 0, -EINVAL); - assert_return(acd->address != 0, -EINVAL); - assert_return(!ether_addr_is_null(&acd->mac_addr), -EINVAL); - assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY); - - r = arp_network_bind_raw_socket(acd->ifindex, acd->address, &acd->mac_addr); - if (r < 0) - return r; - - CLOSE_AND_REPLACE(acd->fd, r); - acd->defend_window = 0; - - if (reset_conflicts) - acd->n_conflict = 0; - - r = sd_event_add_io(acd->event, &acd->receive_message_event_source, acd->fd, EPOLLIN, ipv4acd_on_packet, acd); - if (r < 0) - goto fail; - - r = sd_event_source_set_priority(acd->receive_message_event_source, acd->event_priority); - if (r < 0) - goto fail; - - (void) sd_event_source_set_description(acd->receive_message_event_source, "ipv4acd-receive-message"); - - r = ipv4acd_set_next_wakeup(acd, 0, 0); - if (r < 0) - goto fail; - - ipv4acd_set_state(acd, IPV4ACD_STATE_STARTED, true); - return 0; - -fail: - ipv4acd_reset(acd); - return r; -} diff --git a/src/core/systemd/src/libsystemd-network/sd-ipv4ll.c b/src/core/systemd/src/libsystemd-network/sd-ipv4ll.c deleted file mode 100644 index 202700d2cb..0000000000 --- a/src/core/systemd/src/libsystemd-network/sd-ipv4ll.c +++ /dev/null @@ -1,357 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/*** - Copyright © 2014 Axis Communications AB. All rights reserved. -***/ - -#include "nm-sd-adapt-core.h" - -#include <arpa/inet.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> - -#include "sd-id128.h" -#include "sd-ipv4acd.h" -#include "sd-ipv4ll.h" - -#include "alloc-util.h" -#include "ether-addr-util.h" -#include "in-addr-util.h" -#include "log-link.h" -#include "random-util.h" -#include "siphash24.h" -#include "sparse-endian.h" -#include "string-util.h" -#include "util.h" - -#define IPV4LL_NETWORK UINT32_C(0xA9FE0000) -#define IPV4LL_NETMASK UINT32_C(0xFFFF0000) - -#define IPV4LL_DONT_DESTROY(ll) \ - _cleanup_(sd_ipv4ll_unrefp) _unused_ sd_ipv4ll *_dont_destroy_##ll = sd_ipv4ll_ref(ll) - -struct sd_ipv4ll { - unsigned n_ref; - - sd_ipv4acd *acd; - - be32_t address; /* the address pushed to ACD */ - struct ether_addr mac; - - struct { - le64_t value; - le64_t generation; - } seed; - bool seed_set; - - /* External */ - be32_t claimed_address; - - sd_ipv4ll_callback_t callback; - void* userdata; -}; - -#define log_ipv4ll_errno(ll, error, fmt, ...) \ - ({ \ - int _e = (error); \ - if (DEBUG_LOGGING) \ - log_interface_full_errno( \ - sd_ipv4ll_get_ifname(ll), \ - LOG_DEBUG, _e, "IPv4LL: " fmt, \ - ##__VA_ARGS__); \ - -ERRNO_VALUE(_e); \ - }) -#define log_ipv4ll(ll, fmt, ...) \ - log_ipv4ll_errno(ll, 0, fmt, ##__VA_ARGS__) - -static void ipv4ll_on_acd(sd_ipv4acd *ll, int event, void *userdata); - -static sd_ipv4ll *ipv4ll_free(sd_ipv4ll *ll) { - assert(ll); - - sd_ipv4acd_unref(ll->acd); - return mfree(ll); -} - -DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_ipv4ll, sd_ipv4ll, ipv4ll_free); - -int sd_ipv4ll_new(sd_ipv4ll **ret) { - _cleanup_(sd_ipv4ll_unrefp) sd_ipv4ll *ll = NULL; - int r; - - assert_return(ret, -EINVAL); - - ll = new0(sd_ipv4ll, 1); - if (!ll) - return -ENOMEM; - - ll->n_ref = 1; - - r = sd_ipv4acd_new(&ll->acd); - if (r < 0) - return r; - - r = sd_ipv4acd_set_callback(ll->acd, ipv4ll_on_acd, ll); - if (r < 0) - return r; - - *ret = TAKE_PTR(ll); - - return 0; -} - -int sd_ipv4ll_stop(sd_ipv4ll *ll) { - if (!ll) - return 0; - - return sd_ipv4acd_stop(ll->acd); -} - -int sd_ipv4ll_set_ifindex(sd_ipv4ll *ll, int ifindex) { - assert_return(ll, -EINVAL); - assert_return(ifindex > 0, -EINVAL); - assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY); - - return sd_ipv4acd_set_ifindex(ll->acd, ifindex); -} - -int sd_ipv4ll_get_ifindex(sd_ipv4ll *ll) { - if (!ll) - return -EINVAL; - - return sd_ipv4acd_get_ifindex(ll->acd); -} - -int sd_ipv4ll_set_ifname(sd_ipv4ll *ll, const char *ifname) { - assert_return(ll, -EINVAL); - assert_return(ifname, -EINVAL); - - return sd_ipv4acd_set_ifname(ll->acd, ifname); -} - -const char *sd_ipv4ll_get_ifname(sd_ipv4ll *ll) { - if (!ll) - return NULL; - - return sd_ipv4acd_get_ifname(ll->acd); -} - -int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr) { - int r; - - assert_return(ll, -EINVAL); - assert_return(addr, -EINVAL); - assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY); - - r = sd_ipv4acd_set_mac(ll->acd, addr); - if (r < 0) - return r; - - ll->mac = *addr; - return 0; -} - -int sd_ipv4ll_detach_event(sd_ipv4ll *ll) { - assert_return(ll, -EINVAL); - - return sd_ipv4acd_detach_event(ll->acd); -} - -int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int64_t priority) { - assert_return(ll, -EINVAL); - - return sd_ipv4acd_attach_event(ll->acd, event, priority); -} - -int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata) { - assert_return(ll, -EINVAL); - - ll->callback = cb; - ll->userdata = userdata; - - return 0; -} - -int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address) { - assert_return(ll, -EINVAL); - assert_return(address, -EINVAL); - - if (ll->claimed_address == 0) - return -ENOENT; - - address->s_addr = ll->claimed_address; - - return 0; -} - -int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, uint64_t seed) { - assert_return(ll, -EINVAL); - assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY); - - ll->seed.value = htole64(seed); - ll->seed_set = true; - - return 0; -} - -int sd_ipv4ll_is_running(sd_ipv4ll *ll) { - assert_return(ll, false); - - return sd_ipv4acd_is_running(ll->acd); -} - -static bool ipv4ll_address_is_valid(const struct in_addr *address) { - assert(address); - - if (!in4_addr_is_link_local(address)) - return false; - - return !IN_SET(be32toh(address->s_addr) & 0x0000FF00U, 0x0000U, 0xFF00U); -} - -int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address) { - int r; - - assert_return(ll, -EINVAL); - assert_return(address, -EINVAL); - assert_return(ipv4ll_address_is_valid(address), -EINVAL); - - r = sd_ipv4acd_set_address(ll->acd, address); - if (r < 0) - return r; - - ll->address = address->s_addr; - - return 0; -} - -#define PICK_HASH_KEY SD_ID128_MAKE(15,ac,82,a6,d6,3f,49,78,98,77,5d,0c,69,02,94,0b) - -static int ipv4ll_pick_address(sd_ipv4ll *ll) { - _cleanup_free_ char *address = NULL; - be32_t addr; - - assert(ll); - - do { - uint64_t h; - - h = siphash24(&ll->seed, sizeof(ll->seed), PICK_HASH_KEY.bytes); - - /* Increase the generation counter by one */ - ll->seed.generation = htole64(le64toh(ll->seed.generation) + 1); - - addr = htobe32((h & UINT32_C(0x0000FFFF)) | IPV4LL_NETWORK); - } while (addr == ll->address || - IN_SET(be32toh(addr) & 0x0000FF00U, 0x0000U, 0xFF00U)); - - (void) in_addr_to_string(AF_INET, &(union in_addr_union) { .in.s_addr = addr }, &address); - log_ipv4ll(ll, "Picked new IP address %s.", strna(address)); - - return sd_ipv4ll_set_address(ll, &(struct in_addr) { addr }); -} - -#define MAC_HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2) - -static int ipv4ll_start_internal(sd_ipv4ll *ll, bool reset_generation) { - int r; - bool picked_address = false; - - assert_return(ll, -EINVAL); - assert_return(!ether_addr_is_null(&ll->mac), -EINVAL); - - /* If no random seed is set, generate some from the MAC address */ - if (!ll->seed_set) - ll->seed.value = htole64(siphash24(ll->mac.ether_addr_octet, ETH_ALEN, MAC_HASH_KEY.bytes)); - - if (reset_generation) - ll->seed.generation = 0; - - if (ll->address == 0) { - r = ipv4ll_pick_address(ll); - if (r < 0) - return r; - - picked_address = true; - } - - r = sd_ipv4acd_start(ll->acd, reset_generation); - if (r < 0) { - - /* We couldn't start? If so, let's forget the picked address again, the user might make a change and - * retry, and we want the new data to take effect when picking an address. */ - if (picked_address) - ll->address = 0; - - return r; - } - - return 1; -} - -int sd_ipv4ll_start(sd_ipv4ll *ll) { - assert_return(ll, -EINVAL); - - if (sd_ipv4ll_is_running(ll)) - return 0; - - return ipv4ll_start_internal(ll, true); -} - -int sd_ipv4ll_restart(sd_ipv4ll *ll) { - ll->address = 0; - - return ipv4ll_start_internal(ll, false); -} - -static void ipv4ll_client_notify(sd_ipv4ll *ll, int event) { - assert(ll); - - if (ll->callback) - ll->callback(ll, event, ll->userdata); -} - -void ipv4ll_on_acd(sd_ipv4acd *acd, int event, void *userdata) { - sd_ipv4ll *ll = userdata; - IPV4LL_DONT_DESTROY(ll); - int r; - - assert(acd); - assert(ll); - - switch (event) { - - case SD_IPV4ACD_EVENT_STOP: - ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_STOP); - ll->claimed_address = 0; - break; - - case SD_IPV4ACD_EVENT_BIND: - ll->claimed_address = ll->address; - ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_BIND); - break; - - case SD_IPV4ACD_EVENT_CONFLICT: - /* if an address was already bound we must call up to the - user to handle this, otherwise we just try again */ - if (ll->claimed_address != 0) { - ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_CONFLICT); - - ll->claimed_address = 0; - } else { - r = sd_ipv4ll_restart(ll); - if (r < 0) - goto error; - } - - break; - - default: - assert_not_reached("Invalid IPv4ACD event."); - } - - return; - -error: - ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_STOP); -} diff --git a/src/core/systemd/src/systemd/sd-ipv4acd.h b/src/core/systemd/src/systemd/sd-ipv4acd.h deleted file mode 100644 index 1e89a81b31..0000000000 --- a/src/core/systemd/src/systemd/sd-ipv4acd.h +++ /dev/null @@ -1,61 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef foosdipv4acdfoo -#define foosdipv4acdfoo - -/*** - Copyright © 2014 Axis Communications AB. All rights reserved. - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <net/ethernet.h> -#include <netinet/in.h> -#include <stdbool.h> - -#include "sd-event.h" - -#include "_sd-common.h" - -_SD_BEGIN_DECLARATIONS; - -enum { - SD_IPV4ACD_EVENT_STOP = 0, - SD_IPV4ACD_EVENT_BIND = 1, - SD_IPV4ACD_EVENT_CONFLICT = 2, -}; - -typedef struct sd_ipv4acd sd_ipv4acd; -typedef void (*sd_ipv4acd_callback_t)(sd_ipv4acd *acd, int event, void *userdata); - -int sd_ipv4acd_detach_event(sd_ipv4acd *acd); -int sd_ipv4acd_attach_event(sd_ipv4acd *acd, sd_event *event, int64_t priority); -int sd_ipv4acd_get_address(sd_ipv4acd *acd, struct in_addr *address); -int sd_ipv4acd_set_callback(sd_ipv4acd *acd, sd_ipv4acd_callback_t cb, void *userdata); -int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr); -int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int interface_index); -int sd_ipv4acd_get_ifindex(sd_ipv4acd *acd); -int sd_ipv4acd_set_ifname(sd_ipv4acd *acd, const char *interface_name); -const char *sd_ipv4acd_get_ifname(sd_ipv4acd *acd); -int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address); -int sd_ipv4acd_is_running(sd_ipv4acd *acd); -int sd_ipv4acd_start(sd_ipv4acd *acd, bool reset_conflicts); -int sd_ipv4acd_stop(sd_ipv4acd *acd); -sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *acd); -sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *acd); -int sd_ipv4acd_new(sd_ipv4acd **ret); - -_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ipv4acd, sd_ipv4acd_unref); - -_SD_END_DECLARATIONS; - -#endif diff --git a/src/core/systemd/src/systemd/sd-ipv4ll.h b/src/core/systemd/src/systemd/sd-ipv4ll.h deleted file mode 100644 index bf5596ab61..0000000000 --- a/src/core/systemd/src/systemd/sd-ipv4ll.h +++ /dev/null @@ -1,63 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef foosdipv4llfoo -#define foosdipv4llfoo - -/*** - Copyright © 2014 Axis Communications AB. All rights reserved. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <net/ethernet.h> -#include <netinet/in.h> - -#include "sd-event.h" - -#include "_sd-common.h" - -_SD_BEGIN_DECLARATIONS; - -enum { - SD_IPV4LL_EVENT_STOP = 0, - SD_IPV4LL_EVENT_BIND = 1, - SD_IPV4LL_EVENT_CONFLICT = 2, -}; - -typedef struct sd_ipv4ll sd_ipv4ll; -typedef void (*sd_ipv4ll_callback_t)(sd_ipv4ll *ll, int event, void *userdata); - -int sd_ipv4ll_detach_event(sd_ipv4ll *ll); -int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int64_t priority); -int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address); -int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata); -int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr); -int sd_ipv4ll_set_ifindex(sd_ipv4ll *ll, int interface_index); -int sd_ipv4ll_get_ifindex(sd_ipv4ll *ll); -int sd_ipv4ll_set_ifname(sd_ipv4ll *ll, const char *interface_name); -const char *sd_ipv4ll_get_ifname(sd_ipv4ll *ll); -int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address); -int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, uint64_t seed); -int sd_ipv4ll_is_running(sd_ipv4ll *ll); -int sd_ipv4ll_restart(sd_ipv4ll *ll); -int sd_ipv4ll_start(sd_ipv4ll *ll); -int sd_ipv4ll_stop(sd_ipv4ll *ll); -sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll); -sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll); -int sd_ipv4ll_new(sd_ipv4ll **ret); - -_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ipv4ll, sd_ipv4ll_unref); - -_SD_END_DECLARATIONS; - -#endif diff --git a/src/core/vpn/nm-vpn-connection.c b/src/core/vpn/nm-vpn-connection.c index 2dbbae9105..5b8bec69f6 100644 --- a/src/core/vpn/nm-vpn-connection.c +++ b/src/core/vpn/nm-vpn-connection.c @@ -18,8 +18,6 @@ #include <linux/rtnetlink.h> #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 +32,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,7 +99,7 @@ typedef struct { NMNetns *netns; - GPtrArray *ip4_dev_route_blacklist; + NML3Cfg *l3cfg; GDBusProxy * proxy; GCancellable * cancellable; @@ -110,10 +109,18 @@ typedef struct { NMPacrunnerConfId *pacrunner_conf_id; gboolean has_ip4; NMIP4Config * ip4_config; - guint32 ip4_internal_gw; - guint32 ip4_external_gw; - gboolean has_ip6; - NMIP6Config * 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; + 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 @@ -351,6 +358,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 +371,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 @@ -515,8 +525,7 @@ _set_vpn_state(NMVpnConnection * 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)) { @@ -537,8 +546,7 @@ _set_vpn_state(NMVpnConnection * self, parent_dev, priv->ip_iface, priv->proxy_config, - priv->ip4_config, - priv->ip6_config, + NULL, //XXX NULL, NULL, NULL); @@ -561,8 +569,8 @@ _set_vpn_state(NMVpnConnection * self, 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), @@ -570,8 +578,7 @@ _set_vpn_state(NMVpnConnection * self, parent_dev, priv->ip_iface, priv->proxy_config, - priv->ip4_config, - priv->ip6_config, + NULL, //XXX dispatcher_pre_down_done, self, &priv->dispatcher_id)) { @@ -593,7 +600,6 @@ _set_vpn_state(NMVpnConnection * self, parent_dev, priv->ip_iface, NULL, - NULL, NULL); } else { nm_dispatcher_call_vpn(NM_DISPATCHER_ACTION_VPN_DOWN, @@ -605,7 +611,6 @@ _set_vpn_state(NMVpnConnection * self, NULL, NULL, NULL, - NULL, NULL); } } @@ -678,11 +683,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 +697,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 +743,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 +759,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 +783,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 +829,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 +845,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 +998,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 +1014,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 +1075,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,6 +1178,7 @@ 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; } @@ -1286,26 +1276,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; } @@ -1377,7 +1364,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) { @@ -1486,20 +1473,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 +1523,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 +1548,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 +1571,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 +1587,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 +1629,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 +1643,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 +1662,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 +1726,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 +1756,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 +1768,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 +1778,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 +1793,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; + + if (prefix > 128) + continue; - memset(&route, 0, sizeof(route)); + route = (NMPlatformIP6Route){ + .plen = prefix, + .table_coerced = nm_platform_route_table_coerce(route_table), + .metric = route_metric, + .rt_source = NM_IP_CONFIG_SOURCE_VPN, + }; if (!ip6_addr_from_variant(dest, &route.network)) - goto next; - - if (prefix > 128) - goto next; + 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 +1838,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 +1850,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 +1867,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); } @@ -2820,8 +2829,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); 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' | \ |