1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2013 Red Hat, Inc.
*/
#ifndef __NETWORKMANAGER_NDISC_H__
#define __NETWORKMANAGER_NDISC_H__
#include <stdlib.h>
#include <netinet/in.h>
#include "nm-compat-headers/linux/if_addr.h"
#include "nm-setting-ip6-config.h"
#include "NetworkManagerUtils.h"
#include "libnm-platform/nm-platform.h"
#include "libnm-platform/nmp-object.h"
#define NM_RA_TIMEOUT_DEFAULT ((guint32) 0)
#define NM_RA_TIMEOUT_INFINITY ((guint32) G_MAXINT32)
#define NM_TYPE_NDISC (nm_ndisc_get_type())
#define NM_NDISC(obj) (_NM_G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_NDISC, NMNDisc))
#define NM_NDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_NDISC, NMNDiscClass))
#define NM_IS_NDISC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_NDISC))
#define NM_IS_NDISC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_NDISC))
#define NM_NDISC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_NDISC, NMNDiscClass))
#define NM_NDISC_CONFIG "config"
#define NM_NDISC_CONFIG_RECEIVED "config-received"
#define NM_NDISC_RA_TIMEOUT_SIGNAL "ra-timeout-signal"
typedef enum {
NM_NDISC_DHCP_LEVEL_UNKNOWN,
NM_NDISC_DHCP_LEVEL_NONE,
NM_NDISC_DHCP_LEVEL_OTHERCONF,
NM_NDISC_DHCP_LEVEL_MANAGED
} NMNDiscDHCPLevel;
const char *nm_ndisc_dhcp_level_to_string(NMNDiscDHCPLevel level);
#define NM_NDISC_INFINITY_U32 ((uint32_t) -1)
/* It's important that this is G_MAXINT64, so that we can meaningfully do
* MIN(e1, e2) to find the minimum expiry time (and properly handle if any
* of them is infinity).
*
* While usually you assign this to "expiry_msec", you might say the
* unit of it is milliseconds. But of course, infinity has not really a unit. */
#define NM_NDISC_EXPIRY_INFINITY G_MAXINT64
static inline gint64
_nm_ndisc_lifetime_to_expiry(gint64 now_msec, guint32 lifetime)
{
if (lifetime == NM_NDISC_INFINITY_U32)
return NM_NDISC_EXPIRY_INFINITY;
return now_msec + (((gint64) lifetime) * 1000);
}
static inline gint64
_nm_ndisc_lifetime_from_expiry(gint64 now_msec, gint64 expiry_msec, gboolean ceil)
{
gint64 diff;
if (expiry_msec == NM_NDISC_EXPIRY_INFINITY)
return NM_NDISC_INFINITY_U32;
/* we don't expect nor handle integer overflow. The time stamp and expiry
* should be reasonably small so that it cannot happen. */
diff = expiry_msec - now_msec;
if (diff <= 0)
return 0;
if (ceil) {
/* we ceil() towards the next full second (instead of floor()). */
diff += 999;
}
return NM_MIN(diff / 1000, (gint64) (G_MAXUINT32 - 1));
}
/*****************************************************************************/
typedef struct _NMNDiscGateway {
struct in6_addr address;
gint64 expiry_msec;
NMIcmpv6RouterPref preference;
} NMNDiscGateway;
typedef struct _NMNDiscAddress {
struct in6_addr address;
gint64 expiry_msec;
gint64 expiry_preferred_msec;
guint8 dad_counter;
} NMNDiscAddress;
typedef struct _NMNDiscRoute {
struct in6_addr network;
struct in6_addr gateway;
gint64 expiry_msec;
NMIcmpv6RouterPref preference;
guint8 plen;
bool on_link : 1;
bool duplicate : 1;
} NMNDiscRoute;
typedef struct _NMNDiscPref64 {
struct in6_addr prefix;
struct in6_addr gateway;
gint64 expiry_msec;
gint64 gateway_expiry_msec;
NMIcmpv6RouterPref gateway_preference;
guint8 plen;
} NMNDiscPref64;
typedef struct {
struct in6_addr address;
gint64 expiry_msec;
} NMNDiscDNSServer;
typedef struct {
char *domain;
gint64 expiry_msec;
} NMNDiscDNSDomain;
typedef enum {
NM_NDISC_CONFIG_NONE = 0,
NM_NDISC_CONFIG_DHCP_LEVEL = 1 << 0,
NM_NDISC_CONFIG_GATEWAYS = 1 << 1,
NM_NDISC_CONFIG_ADDRESSES = 1 << 2,
NM_NDISC_CONFIG_ROUTES = 1 << 3,
NM_NDISC_CONFIG_DNS_SERVERS = 1 << 4,
NM_NDISC_CONFIG_DNS_DOMAINS = 1 << 5,
NM_NDISC_CONFIG_HOP_LIMIT = 1 << 6,
NM_NDISC_CONFIG_MTU = 1 << 7,
NM_NDISC_CONFIG_REACHABLE_TIME = 1 << 8,
NM_NDISC_CONFIG_RETRANS_TIMER = 1 << 9,
NM_NDISC_CONFIG_PREF64 = 1 << 10,
} NMNDiscConfigMap;
typedef enum {
NM_NDISC_NODE_TYPE_INVALID,
NM_NDISC_NODE_TYPE_HOST,
NM_NDISC_NODE_TYPE_ROUTER,
} NMNDiscNodeType;
#define NM_NDISC_RFC4861_RTR_SOLICITATION_INTERVAL 4 /* seconds */
#define NM_NDISC_RFC4861_MAX_RTR_SOLICITATION_DELAY 1 /* seconds */
#define NM_NDISC_MAX_ADDRESSES_DEFAULT 16
#define NM_NDISC_ROUTER_SOLICITATIONS_DEFAULT 3 /* RFC4861, MAX_RTR_SOLICITATIONS */
#define NM_NDISC_ROUTER_ADVERTISEMENTS_DEFAULT 3 /* RFC4861, MAX_INITIAL_RTR_ADVERTISEMENTS */
#define NM_NDISC_ROUTER_ADVERT_DELAY 3 /* RFC4861, MIN_DELAY_BETWEEN_RAS */
#define NM_NDISC_ROUTER_ADVERT_INITIAL_INTERVAL 16 /* RFC4861, MAX_INITIAL_RTR_ADVERT_INTERVAL */
#define NM_NDISC_ROUTER_ADVERT_DELAY_MS 500 /* RFC4861, MAX_RA_DELAY_TIME */
#define NM_NDISC_ROUTER_ADVERT_MAX_INTERVAL 600 /* RFC4861, MaxRtrAdvInterval default */
#define NM_NDISC_ROUTER_LIFETIME 900 /* 1.5 * NM_NDISC_ROUTER_ADVERT_MAX_INTERVAL */
typedef struct {
NML3Cfg *l3cfg;
const char *ifname;
const char *network_id;
int max_addresses;
int router_solicitations;
int router_solicitation_interval;
guint32 ra_timeout;
NMUtilsStableType stable_type;
NMSettingIP6ConfigAddrGenMode addr_gen_mode;
NMNDiscNodeType node_type;
NMSettingIP6ConfigPrivacy ip6_privacy;
} NMNDiscConfig;
struct _NMNDiscPrivate;
struct _NMNDiscDataInternal;
typedef struct {
NMNDiscDHCPLevel dhcp_level;
guint32 mtu;
int hop_limit;
guint32 reachable_time_ms;
guint32 retrans_timer_ms;
guint gateways_n;
guint addresses_n;
guint routes_n;
guint pref64_n;
guint dns_servers_n;
guint dns_domains_n;
const NMNDiscGateway *gateways;
const NMNDiscAddress *addresses;
const NMNDiscRoute *routes;
const NMNDiscPref64 *pref64;
const NMNDiscDNSServer *dns_servers;
const NMNDiscDNSDomain *dns_domains;
} NMNDiscData;
/**
* NMNDisc:
*
* Interface-specific structure that handles incoming router advertisements,
* caches advertised items and removes them when they are obsolete.
*/
typedef struct {
GObject parent;
union {
struct _NMNDiscPrivate *_priv;
struct _NMNDiscDataInternal *rdata;
};
} NMNDisc;
typedef struct {
GObjectClass parent;
void (*start)(NMNDisc *ndisc);
void (*stop)(NMNDisc *ndisc);
gboolean (*send_rs)(NMNDisc *ndisc, GError **error);
gboolean (*send_ra)(NMNDisc *ndisc, GError **error);
} NMNDiscClass;
GType nm_ndisc_get_type(void);
int nm_ndisc_get_ifindex(NMNDisc *self);
const char *nm_ndisc_get_ifname(NMNDisc *self);
NMNDiscNodeType nm_ndisc_get_node_type(NMNDisc *self);
gboolean nm_ndisc_set_iid(NMNDisc *ndisc, const NMUtilsIPv6IfaceId iid, gboolean is_token);
void nm_ndisc_start(NMNDisc *ndisc);
void nm_ndisc_stop(NMNDisc *ndisc);
void nm_ndisc_set_config(NMNDisc *ndisc, const NML3ConfigData *l3cd);
NMNDiscConfigMap
nm_ndisc_dad_failed(NMNDisc *ndisc, GArray *addresses, gboolean emit_changed_signal);
NMPlatform *nm_ndisc_get_platform(NMNDisc *self);
NMPNetns *nm_ndisc_netns_get(NMNDisc *self);
gboolean nm_ndisc_netns_push(NMNDisc *self, NMPNetns **netns);
static inline gboolean
nm_ndisc_dad_addr_is_fail_candidate_event(NMPlatformSignalChangeType change_type,
const NMPlatformIP6Address *addr)
{
return !NM_FLAGS_HAS(addr->n_ifa_flags, IFA_F_SECONDARY)
&& ((change_type == NM_PLATFORM_SIGNAL_CHANGED && addr->n_ifa_flags & IFA_F_DADFAILED)
|| (change_type == NM_PLATFORM_SIGNAL_REMOVED
&& addr->n_ifa_flags & IFA_F_TENTATIVE));
}
static inline gboolean
nm_ndisc_dad_addr_is_fail_candidate(NMPlatform *platform, const NMPObject *obj)
{
const NMPlatformIP6Address *addr;
addr = NMP_OBJECT_CAST_IP6_ADDRESS(
nm_platform_lookup_obj(platform, NMP_CACHE_ID_TYPE_OBJECT_TYPE, obj));
if (addr
&& (NM_FLAGS_HAS(addr->n_ifa_flags, IFA_F_SECONDARY)
|| !NM_FLAGS_HAS(addr->n_ifa_flags, IFA_F_DADFAILED))) {
/* the address still/again exists and is not in DADFAILED state. Skip it. */
return FALSE;
}
return TRUE;
}
/*****************************************************************************/
void nm_ndisc_get_sysctl(NMPlatform *platform,
const char *ifname,
int *out_max_addresses,
int *out_router_solicitations,
int *out_router_solicitation_interval,
guint32 *out_default_ra_timeout);
/*****************************************************************************/
struct _NML3ConfigData;
struct _NML3ConfigData *nm_ndisc_data_to_l3cd(NMDedupMultiIndex *multi_idx,
int ifindex,
const NMNDiscData *rdata,
NMSettingIP6ConfigPrivacy ip6_privacy,
NMUtilsIPv6IfaceId *token,
const char *network_id);
#endif /* __NETWORKMANAGER_NDISC_H__ */
|