2 This file is part of systemd.
4 Copyright (C) 2014 Intel Corporation. All rights reserved.
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 #include <netinet/ether.h>
23 #include "sd-dhcp6-client.h"
25 #include "network-internal.h"
26 #include "networkd-link.h"
27 #include "networkd-manager.h"
29 static int dhcp6_lease_address_acquired(sd_dhcp6_client
*client
, Link
*link
);
31 static int dhcp6_lease_information_acquired(sd_dhcp6_client
*client
,
36 static int dhcp6_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
,
38 _cleanup_link_unref_ Link
*link
= userdata
;
43 r
= sd_netlink_message_get_errno(m
);
44 if (r
< 0 && r
!= -EEXIST
) {
45 if (link
->rtnl_extended_attrs
) {
46 log_link_warning(link
, "Could not set extended netlink attributes, reverting to fallback mechanism");
48 link
->rtnl_extended_attrs
= false;
49 dhcp6_lease_address_acquired(link
->dhcp6_client
, link
);
54 log_link_error_errno(link
, r
, "Could not set DHCPv6 address: %m");
56 link_enter_failed(link
);
59 manager_rtnl_process_address(rtnl
, m
, link
->manager
);
64 static int dhcp6_address_change(
66 struct in6_addr
*ip6_addr
,
67 uint32_t lifetime_preferred
,
68 uint32_t lifetime_valid
) {
70 _cleanup_address_free_ Address
*addr
= NULL
;
71 char buffer
[INET6_ADDRSTRLEN
];
74 r
= address_new(&addr
);
78 addr
->family
= AF_INET6
;
79 memcpy(&addr
->in_addr
.in6
, ip6_addr
, sizeof(*ip6_addr
));
81 addr
->flags
= IFA_F_NOPREFIXROUTE
;
82 addr
->prefixlen
= 128;
84 addr
->cinfo
.ifa_prefered
= lifetime_preferred
;
85 addr
->cinfo
.ifa_valid
= lifetime_valid
;
88 "DHCPv6 address %s/%d timeout preferred %d valid %d",
89 inet_ntop(AF_INET6
, &addr
->in_addr
.in6
, buffer
, sizeof(buffer
)),
90 addr
->prefixlen
, lifetime_preferred
, lifetime_valid
);
92 r
= address_configure(addr
, link
, dhcp6_address_handler
, true);
94 log_link_warning_errno(link
, r
, "Could not assign DHCPv6 address: %m");
99 static int dhcp6_lease_address_acquired(sd_dhcp6_client
*client
, Link
*link
) {
101 sd_dhcp6_lease
*lease
;
102 struct in6_addr ip6_addr
;
103 uint32_t lifetime_preferred
, lifetime_valid
;
105 r
= sd_dhcp6_client_get_lease(client
, &lease
);
109 sd_dhcp6_lease_reset_address_iter(lease
);
111 while (sd_dhcp6_lease_get_address(lease
, &ip6_addr
,
113 &lifetime_valid
) >= 0) {
115 r
= dhcp6_address_change(link
, &ip6_addr
, lifetime_preferred
, lifetime_valid
);
123 static void dhcp6_handler(sd_dhcp6_client
*client
, int event
, void *userdata
) {
125 Link
*link
= userdata
;
128 assert(link
->network
);
130 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
134 case SD_DHCP6_CLIENT_EVENT_STOP
:
135 case SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE
:
136 case SD_DHCP6_CLIENT_EVENT_RETRANS_MAX
:
137 if (sd_dhcp6_client_get_lease(client
, NULL
) >= 0)
138 log_link_warning(link
, "DHCPv6 lease lost");
140 link
->dhcp6_configured
= false;
143 case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE
:
144 r
= dhcp6_lease_address_acquired(client
, link
);
146 link_enter_failed(link
);
151 case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST
:
152 r
= dhcp6_lease_information_acquired(client
, link
);
154 link_enter_failed(link
);
158 link
->dhcp6_configured
= true;
163 log_link_warning_errno(link
, event
, "DHCPv6 error: %m");
165 log_link_warning(link
, "DHCPv6 unknown event: %d", event
);
169 link_check_ready(link
);
172 int dhcp6_request_address(Link
*link
, int ir
) {
177 assert(link
->dhcp6_client
);
178 assert(in_addr_is_link_local(AF_INET6
, (const union in_addr_union
*)&link
->ipv6ll_address
) > 0);
180 r
= sd_dhcp6_client_is_running(link
->dhcp6_client
);
187 r
= sd_dhcp6_client_get_information_request(link
->dhcp6_client
, &inf_req
);
194 r
= sd_dhcp6_client_stop(link
->dhcp6_client
);
198 r
= sd_dhcp6_client_set_local_address(link
->dhcp6_client
, &link
->ipv6ll_address
);
203 r
= sd_dhcp6_client_set_information_request(link
->dhcp6_client
, ir
);
207 r
= sd_dhcp6_client_start(link
->dhcp6_client
);
214 int dhcp6_configure(Link
*link
) {
215 sd_dhcp6_client
*client
= NULL
;
221 if (link
->dhcp6_client
)
224 r
= sd_dhcp6_client_new(&client
);
228 r
= sd_dhcp6_client_attach_event(client
, NULL
, 0);
232 r
= sd_dhcp6_client_set_mac(client
,
233 (const uint8_t *) &link
->mac
,
234 sizeof (link
->mac
), ARPHRD_ETHER
);
238 r
= sd_dhcp6_client_set_iaid(client
, link
->network
->iaid
);
242 duid
= link_duid(link
);
243 r
= sd_dhcp6_client_set_duid(client
,
245 duid
->raw_data_len
> 0 ? duid
->raw_data
: NULL
,
250 r
= sd_dhcp6_client_set_ifindex(client
, link
->ifindex
);
254 r
= sd_dhcp6_client_set_callback(client
, dhcp6_handler
, link
);
258 link
->dhcp6_client
= client
;
263 sd_dhcp6_client_unref(client
);