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"
28 static int dhcp6_lease_address_acquired(sd_dhcp6_client
*client
, Link
*link
);
30 static int dhcp6_lease_information_acquired(sd_dhcp6_client
*client
,
35 static int dhcp6_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
,
37 _cleanup_link_unref_ Link
*link
= userdata
;
42 r
= sd_netlink_message_get_errno(m
);
43 if (r
< 0 && r
!= -EEXIST
) {
44 if (link
->rtnl_extended_attrs
) {
45 log_link_warning(link
, "Could not set extended netlink attributes, reverting to fallback mechanism");
47 link
->rtnl_extended_attrs
= false;
48 dhcp6_lease_address_acquired(link
->dhcp6_client
, link
);
53 log_link_error_errno(link
, r
, "Could not set DHCPv6 address: %m");
55 link_enter_failed(link
);
58 manager_rtnl_process_address(rtnl
, m
, link
->manager
);
63 static int dhcp6_address_change(Link
*link
, struct in6_addr
*ip6_addr
,
64 uint32_t lifetime_preferred
, uint32_t lifetime_valid
) {
66 _cleanup_address_free_ Address
*addr
= NULL
;
68 r
= address_new(&addr
);
72 addr
->family
= AF_INET6
;
73 memcpy(&addr
->in_addr
.in6
, ip6_addr
, sizeof(*ip6_addr
));
75 addr
->flags
= IFA_F_NOPREFIXROUTE
;
76 addr
->prefixlen
= 128;
78 addr
->cinfo
.ifa_prefered
= lifetime_preferred
;
79 addr
->cinfo
.ifa_valid
= lifetime_valid
;
82 "DHCPv6 address "SD_NDISC_ADDRESS_FORMAT_STR
"/%d timeout preferred %d valid %d",
83 SD_NDISC_ADDRESS_FORMAT_VAL(addr
->in_addr
.in6
),
84 addr
->prefixlen
, lifetime_preferred
, lifetime_valid
);
86 r
= address_configure(addr
, link
, dhcp6_address_handler
, true);
88 log_link_warning_errno(link
, r
, "Could not assign DHCPv6 address: %m");
93 static int dhcp6_lease_address_acquired(sd_dhcp6_client
*client
, Link
*link
) {
95 sd_dhcp6_lease
*lease
;
96 struct in6_addr ip6_addr
;
97 uint32_t lifetime_preferred
, lifetime_valid
;
99 r
= sd_dhcp6_client_get_lease(client
, &lease
);
103 sd_dhcp6_lease_reset_address_iter(lease
);
105 while (sd_dhcp6_lease_get_address(lease
, &ip6_addr
,
107 &lifetime_valid
) >= 0) {
109 r
= dhcp6_address_change(link
, &ip6_addr
, lifetime_preferred
, lifetime_valid
);
117 static void dhcp6_handler(sd_dhcp6_client
*client
, int event
, void *userdata
) {
119 Link
*link
= userdata
;
122 assert(link
->network
);
123 assert(link
->manager
);
125 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
129 case SD_DHCP6_CLIENT_EVENT_STOP
:
130 case SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE
:
131 case SD_DHCP6_CLIENT_EVENT_RETRANS_MAX
:
132 if (sd_dhcp6_client_get_lease(client
, NULL
) >= 0)
133 log_link_warning(link
, "DHCPv6 lease lost");
135 link
->dhcp6_configured
= false;
138 case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE
:
139 r
= dhcp6_lease_address_acquired(client
, link
);
141 link_enter_failed(link
);
146 case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST
:
147 r
= dhcp6_lease_information_acquired(client
, link
);
149 link_enter_failed(link
);
153 link
->dhcp6_configured
= true;
158 log_link_warning_errno(link
, event
, "DHCPv6 error: %m");
160 log_link_warning(link
, "DHCPv6 unknown event: %d", event
);
164 link_check_ready(link
);
167 int dhcp6_request_address(Link
*link
) {
172 assert(link
->dhcp6_client
);
174 r
= sd_dhcp6_client_get_information_request(link
->dhcp6_client
, &inf_req
);
181 r
= sd_dhcp6_client_is_running(link
->dhcp6_client
);
188 r
= sd_dhcp6_client_stop(link
->dhcp6_client
);
193 r
= sd_dhcp6_client_set_information_request(link
->dhcp6_client
, false);
198 r
= sd_dhcp6_client_start(link
->dhcp6_client
);
206 int dhcp6_configure(Link
*link
) {
207 sd_dhcp6_client
*client
= NULL
;
212 if (link
->dhcp6_client
)
215 r
= sd_dhcp6_client_new(&client
);
219 r
= sd_dhcp6_client_attach_event(client
, NULL
, 0);
223 r
= sd_dhcp6_client_set_information_request(client
, true);
227 r
= sd_dhcp6_client_set_mac(client
,
228 (const uint8_t *) &link
->mac
,
229 sizeof (link
->mac
), ARPHRD_ETHER
);
233 r
= sd_dhcp6_client_set_index(client
, link
->ifindex
);
237 r
= sd_dhcp6_client_set_callback(client
, dhcp6_handler
, link
);
241 link
->dhcp6_client
= client
;
246 sd_dhcp6_client_unref(client
);