nat64.c revision 1.1 1 1.1 christos /* nat64.c
2 1.1 christos *
3 1.1 christos * Copyright (c) 2022-2023 Apple Inc. All rights reserved.
4 1.1 christos *
5 1.1 christos * Licensed under the Apache License, Version 2.0 (the "License");
6 1.1 christos * you may not use this file except in compliance with the License.
7 1.1 christos * You may obtain a copy of the License at
8 1.1 christos *
9 1.1 christos * https://www.apache.org/licenses/LICENSE-2.0
10 1.1 christos *
11 1.1 christos * Unless required by applicable law or agreed to in writing, software
12 1.1 christos * distributed under the License is distributed on an "AS IS" BASIS,
13 1.1 christos * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 1.1 christos * See the License for the specific language governing permissions and
15 1.1 christos * limitations under the License.
16 1.1 christos */
17 1.1 christos
18 1.1 christos #include <netinet/in.h>
19 1.1 christos #include "srp-log.h"
20 1.1 christos #include "dns-msg.h"
21 1.1 christos #include "ioloop.h"
22 1.1 christos #include "srp-mdns-proxy.h"
23 1.1 christos #include "nat64.h"
24 1.1 christos #include "nat64-macos.h"
25 1.1 christos #include "state-machine.h"
26 1.1 christos #include "thread-service.h"
27 1.1 christos #include "omr-watcher.h"
28 1.1 christos #include "omr-publisher.h"
29 1.1 christos
30 1.1 christos #if SRP_FEATURE_NAT64
31 1.1 christos static void nat64_infra_prefix_publisher_event_init(nat64_infra_prefix_publisher_event_t *event, nat64_infra_prefix_publisher_event_type_t event_type);
32 1.1 christos static void nat64_infra_prefix_publisher_event_deliver(nat64_infra_prefix_publisher_t *state_machine, nat64_infra_prefix_publisher_event_t *event);
33 1.1 christos static void nat64_br_prefix_publisher_event_init(nat64_br_prefix_publisher_event_t *event, nat64_br_prefix_publisher_event_type_t event_type);
34 1.1 christos static void nat64_br_prefix_publisher_event_deliver(nat64_br_prefix_publisher_t *state_machine, nat64_br_prefix_publisher_event_t *event);
35 1.1 christos static void nat64_add_prefix_to_update_queue(nat64_t *nat64, nat64_prefix_t *prefix, nat64_prefix_action action);
36 1.1 christos static void nat64_prefix_start_next_update(nat64_t *nat64);
37 1.1 christos static bool nat64_query_prefix_on_infra(nat64_infra_prefix_monitor_t *state_machine);
38 1.1 christos
39 1.1 christos static void
40 1.1 christos nat64_prefix_finalize(nat64_prefix_t *prefix)
41 1.1 christos {
42 1.1 christos free(prefix);
43 1.1 christos }
44 1.1 christos
45 1.1 christos static void
46 1.1 christos nat64_finalize(nat64_t *nat64)
47 1.1 christos {
48 1.1 christos free(nat64);
49 1.1 christos }
50 1.1 christos
51 1.1 christos static nat64_ipv4_default_route_monitor_t *
52 1.1 christos nat64_ipv4_default_route_monitor_create(nat64_t *nat64)
53 1.1 christos {
54 1.1 christos nat64_ipv4_default_route_monitor_t *monitor = calloc(1, sizeof(*monitor));
55 1.1 christos if (monitor == NULL) {
56 1.1 christos return monitor;
57 1.1 christos }
58 1.1 christos RETAIN_HERE(monitor, nat64_ipv4_default_route_monitor);
59 1.1 christos monitor->nat64 = nat64;
60 1.1 christos RETAIN_HERE(monitor->nat64, nat64);
61 1.1 christos return monitor;
62 1.1 christos }
63 1.1 christos
64 1.1 christos static void
65 1.1 christos nat64_ipv4_default_route_monitor_cancel(nat64_ipv4_default_route_monitor_t *monitor)
66 1.1 christos {
67 1.1 christos if (monitor != NULL) {
68 1.1 christos monitor->has_ipv4_default_route = false;
69 1.1 christos if (monitor->nat64 != NULL) {
70 1.1 christos RELEASE_HERE(monitor->nat64, nat64);
71 1.1 christos monitor->nat64 = NULL;
72 1.1 christos }
73 1.1 christos }
74 1.1 christos }
75 1.1 christos
76 1.1 christos static void
77 1.1 christos nat64_ipv4_default_route_monitor_finalize(nat64_ipv4_default_route_monitor_t *monitor)
78 1.1 christos {
79 1.1 christos free(monitor);
80 1.1 christos }
81 1.1 christos
82 1.1 christos static void
83 1.1 christos nat64_infra_prefix_monitor_finalize(nat64_infra_prefix_monitor_t *monitor)
84 1.1 christos {
85 1.1 christos free(monitor);
86 1.1 christos }
87 1.1 christos
88 1.1 christos static nat64_infra_prefix_monitor_t *
89 1.1 christos nat64_infra_prefix_monitor_create(nat64_t *nat64)
90 1.1 christos {
91 1.1 christos nat64_infra_prefix_monitor_t *monitor = calloc(1, sizeof(*monitor));
92 1.1 christos if (monitor == NULL) {
93 1.1 christos return monitor;
94 1.1 christos }
95 1.1 christos RETAIN_HERE(monitor, nat64_infra_prefix_monitor);
96 1.1 christos monitor->nat64 = nat64;
97 1.1 christos RETAIN_HERE(monitor->nat64, nat64);
98 1.1 christos return monitor;
99 1.1 christos }
100 1.1 christos
101 1.1 christos static void
102 1.1 christos nat64_infra_prefix_monitor_cancel(nat64_infra_prefix_monitor_t *monitor)
103 1.1 christos {
104 1.1 christos if (monitor != NULL) {
105 1.1 christos nat64_prefix_t *next;
106 1.1 christos for (nat64_prefix_t *prefix = monitor->infra_nat64_prefixes; prefix != NULL; prefix = next) {
107 1.1 christos next = prefix->next;
108 1.1 christos prefix->next = NULL;
109 1.1 christos RELEASE_HERE(prefix, nat64_prefix);
110 1.1 christos }
111 1.1 christos monitor->infra_nat64_prefixes = NULL;
112 1.1 christos if (monitor->sdRef != NULL) {
113 1.1 christos DNSServiceRefDeallocate(monitor->sdRef);
114 1.1 christos monitor->sdRef = NULL;
115 1.1 christos RELEASE_HERE(monitor, nat64_infra_prefix_monitor);
116 1.1 christos }
117 1.1 christos if (monitor->nat64 != NULL) {
118 1.1 christos RELEASE_HERE(monitor->nat64, nat64);
119 1.1 christos monitor->nat64 = NULL;
120 1.1 christos }
121 1.1 christos monitor->canceled = true;
122 1.1 christos }
123 1.1 christos }
124 1.1 christos
125 1.1 christos static nat64_thread_prefix_monitor_t *
126 1.1 christos nat64_thread_prefix_monitor_create(nat64_t *nat64)
127 1.1 christos {
128 1.1 christos nat64_thread_prefix_monitor_t *monitor = calloc(1, sizeof(*monitor));
129 1.1 christos if (monitor == NULL) {
130 1.1 christos return monitor;
131 1.1 christos }
132 1.1 christos RETAIN_HERE(monitor, nat64_thread_prefix_monitor);
133 1.1 christos monitor->nat64 = nat64;
134 1.1 christos RETAIN_HERE(monitor->nat64, nat64);
135 1.1 christos return monitor;
136 1.1 christos }
137 1.1 christos
138 1.1 christos static void
139 1.1 christos nat64_thread_prefix_monitor_cancel(nat64_thread_prefix_monitor_t *monitor)
140 1.1 christos {
141 1.1 christos if (monitor != NULL) {
142 1.1 christos nat64_prefix_t *next;
143 1.1 christos for (nat64_prefix_t *prefix = monitor->thread_nat64_prefixes; prefix != NULL; prefix = next) {
144 1.1 christos next = prefix->next;
145 1.1 christos prefix->next = NULL;
146 1.1 christos RELEASE_HERE(prefix, nat64_prefix);
147 1.1 christos }
148 1.1 christos monitor->thread_nat64_prefixes = NULL;
149 1.1 christos if (monitor->timer != NULL) {
150 1.1 christos ioloop_cancel_wake_event(monitor->timer);
151 1.1 christos ioloop_wakeup_release(monitor->timer);
152 1.1 christos monitor->timer = NULL;
153 1.1 christos }
154 1.1 christos if (monitor->nat64 != NULL) {
155 1.1 christos RELEASE_HERE(monitor->nat64, nat64);
156 1.1 christos monitor->nat64 = NULL;
157 1.1 christos }
158 1.1 christos }
159 1.1 christos }
160 1.1 christos
161 1.1 christos static void
162 1.1 christos nat64_thread_prefix_monitor_finalize(nat64_thread_prefix_monitor_t *monitor)
163 1.1 christos {
164 1.1 christos free(monitor);
165 1.1 christos }
166 1.1 christos
167 1.1 christos static nat64_infra_prefix_publisher_t *
168 1.1 christos nat64_infra_prefix_publisher_create(nat64_t *nat64)
169 1.1 christos {
170 1.1 christos nat64_infra_prefix_publisher_t *publisher = calloc(1, sizeof(*publisher));
171 1.1 christos if (publisher == NULL) {
172 1.1 christos return publisher;
173 1.1 christos }
174 1.1 christos RETAIN_HERE(publisher, nat64_infra_prefix_publisher);
175 1.1 christos publisher->nat64 = nat64;
176 1.1 christos RETAIN_HERE(publisher->nat64, nat64);
177 1.1 christos return publisher;
178 1.1 christos }
179 1.1 christos
180 1.1 christos static void
181 1.1 christos nat64_infra_prefix_publisher_finalize(nat64_infra_prefix_publisher_t *publisher)
182 1.1 christos {
183 1.1 christos free(publisher);
184 1.1 christos }
185 1.1 christos
186 1.1 christos static void
187 1.1 christos nat64_infra_prefix_publisher_cancel(nat64_infra_prefix_publisher_t *publisher)
188 1.1 christos {
189 1.1 christos if (publisher != NULL) {
190 1.1 christos if (publisher->state == nat64_infra_prefix_publisher_state_publishing) {
191 1.1 christos SEGMENTED_IPv6_ADDR_GEN_SRP(publisher->proposed_prefix->prefix.s6_addr, nat64_prefix_buf);
192 1.1 christos INFO("thread network shutdown, unpublishing infra prefix " PRI_SEGMENTED_IPv6_ADDR_SRP,
193 1.1 christos SEGMENTED_IPv6_ADDR_PARAM_SRP(publisher->proposed_prefix->prefix.s6_addr, nat64_prefix_buf));
194 1.1 christos nat64_add_prefix_to_update_queue(publisher->nat64, publisher->proposed_prefix, nat64_prefix_action_remove);
195 1.1 christos }
196 1.1 christos if (publisher->proposed_prefix != NULL) {
197 1.1 christos RELEASE_HERE(publisher->proposed_prefix, nat64_prefix);
198 1.1 christos publisher->proposed_prefix = NULL;
199 1.1 christos }
200 1.1 christos if (publisher->nat64 != NULL) {
201 1.1 christos RELEASE_HERE(publisher->nat64, nat64);
202 1.1 christos publisher->nat64 = NULL;
203 1.1 christos }
204 1.1 christos }
205 1.1 christos }
206 1.1 christos
207 1.1 christos static nat64_br_prefix_publisher_t *
208 1.1 christos nat64_br_prefix_publisher_create(nat64_t *nat64)
209 1.1 christos {
210 1.1 christos nat64_br_prefix_publisher_t *publisher = calloc(1, sizeof(*publisher));
211 1.1 christos if (publisher == NULL) {
212 1.1 christos return publisher;
213 1.1 christos }
214 1.1 christos RETAIN_HERE(publisher, nat64_br_prefix_publisher);
215 1.1 christos publisher->nat64 = nat64;
216 1.1 christos RETAIN_HERE(publisher->nat64, nat64);
217 1.1 christos return publisher;
218 1.1 christos }
219 1.1 christos
220 1.1 christos static void
221 1.1 christos nat64_br_prefix_publisher_finalize(nat64_br_prefix_publisher_t *publisher)
222 1.1 christos {
223 1.1 christos free(publisher);
224 1.1 christos }
225 1.1 christos
226 1.1 christos static void
227 1.1 christos nat64_br_prefix_publisher_cancel(nat64_br_prefix_publisher_t *publisher)
228 1.1 christos {
229 1.1 christos if (publisher != NULL) {
230 1.1 christos if (publisher->state == nat64_br_prefix_publisher_state_publishing) {
231 1.1 christos SEGMENTED_IPv6_ADDR_GEN_SRP(publisher->br_prefix->prefix.s6_addr, nat64_prefix_buf);
232 1.1 christos INFO("thread network shutdown, unpublishing br prefix " PRI_SEGMENTED_IPv6_ADDR_SRP,
233 1.1 christos SEGMENTED_IPv6_ADDR_PARAM_SRP(publisher->br_prefix->prefix.s6_addr, nat64_prefix_buf));
234 1.1 christos nat64_add_prefix_to_update_queue(publisher->nat64, publisher->br_prefix, nat64_prefix_action_remove);
235 1.1 christos }
236 1.1 christos if (publisher->br_prefix != NULL) {
237 1.1 christos RELEASE_HERE(publisher->br_prefix, nat64_prefix);
238 1.1 christos publisher->br_prefix = NULL;
239 1.1 christos }
240 1.1 christos if (publisher->timer != NULL) {
241 1.1 christos ioloop_cancel_wake_event(publisher->timer);
242 1.1 christos ioloop_wakeup_release(publisher->timer);
243 1.1 christos publisher->timer = NULL;
244 1.1 christos }
245 1.1 christos if (publisher->nat64 != NULL) {
246 1.1 christos RELEASE_HERE(publisher->nat64, nat64);
247 1.1 christos publisher->nat64 = NULL;
248 1.1 christos }
249 1.1 christos }
250 1.1 christos }
251 1.1 christos
252 1.1 christos static void
253 1.1 christos nat64_cancel(nat64_t *nat64)
254 1.1 christos {
255 1.1 christos if (nat64->ipv4_monitor) {
256 1.1 christos INFO("discontinuing nat64 ipv4 default route monitor");
257 1.1 christos nat64_ipv4_default_route_monitor_cancel(nat64->ipv4_monitor);
258 1.1 christos RELEASE_HERE(nat64->ipv4_monitor, nat64_ipv4_default_route_monitor);
259 1.1 christos nat64->ipv4_monitor = NULL;
260 1.1 christos }
261 1.1 christos if (nat64->thread_monitor) {
262 1.1 christos INFO("discontinuing nat64 thread monitor");
263 1.1 christos nat64_thread_prefix_monitor_cancel(nat64->thread_monitor);
264 1.1 christos RELEASE_HERE(nat64->thread_monitor, nat64_thread_prefix_monitor);
265 1.1 christos nat64->thread_monitor = NULL;
266 1.1 christos }
267 1.1 christos if (nat64->infra_monitor) {
268 1.1 christos INFO("discontinuing nat64 infra monitor");
269 1.1 christos nat64_infra_prefix_monitor_cancel(nat64->infra_monitor);
270 1.1 christos RELEASE_HERE(nat64->infra_monitor, nat64_infra_prefix_monitor);
271 1.1 christos nat64->infra_monitor = NULL;
272 1.1 christos }
273 1.1 christos if (nat64->nat64_infra_prefix_publisher) {
274 1.1 christos INFO("discontinuing nat64 infra prefix publisher");
275 1.1 christos nat64_infra_prefix_publisher_cancel(nat64->nat64_infra_prefix_publisher);
276 1.1 christos RELEASE_HERE(nat64->nat64_infra_prefix_publisher, nat64_infra_prefix_publisher);
277 1.1 christos nat64->nat64_infra_prefix_publisher = NULL;
278 1.1 christos }
279 1.1 christos if (nat64->nat64_br_prefix_publisher) {
280 1.1 christos INFO("discontinuing nat64 br prefix publisher");
281 1.1 christos nat64_br_prefix_publisher_cancel(nat64->nat64_br_prefix_publisher);
282 1.1 christos RELEASE_HERE(nat64->nat64_br_prefix_publisher, nat64_br_prefix_publisher);
283 1.1 christos nat64->nat64_br_prefix_publisher = NULL;
284 1.1 christos }
285 1.1 christos }
286 1.1 christos
287 1.1 christos nat64_t *
288 1.1 christos nat64_create(route_state_t *route_state)
289 1.1 christos {
290 1.1 christos nat64_t *new_nat64 = calloc(1, sizeof(*new_nat64));
291 1.1 christos if (new_nat64 == NULL) {
292 1.1 christos ERROR("no memory for nat64_t.");
293 1.1 christos return NULL;
294 1.1 christos }
295 1.1 christos RETAIN_HERE(new_nat64, nat64);
296 1.1 christos new_nat64->ipv4_monitor = nat64_ipv4_default_route_monitor_create(new_nat64);
297 1.1 christos new_nat64->infra_monitor = nat64_infra_prefix_monitor_create(new_nat64);
298 1.1 christos new_nat64->thread_monitor = nat64_thread_prefix_monitor_create(new_nat64);
299 1.1 christos new_nat64->nat64_infra_prefix_publisher = nat64_infra_prefix_publisher_create(new_nat64);
300 1.1 christos new_nat64->nat64_br_prefix_publisher = nat64_br_prefix_publisher_create(new_nat64);
301 1.1 christos
302 1.1 christos if (new_nat64->ipv4_monitor == NULL || new_nat64->infra_monitor == NULL ||
303 1.1 christos new_nat64->thread_monitor == NULL || new_nat64->nat64_infra_prefix_publisher == NULL ||
304 1.1 christos new_nat64->nat64_br_prefix_publisher == NULL) {
305 1.1 christos ERROR("no memory for nat64 state machines.");
306 1.1 christos nat64_cancel(new_nat64);
307 1.1 christos return NULL;
308 1.1 christos }
309 1.1 christos new_nat64->route_state = route_state;
310 1.1 christos
311 1.1 christos return new_nat64;
312 1.1 christos }
313 1.1 christos
314 1.1 christos nat64_prefix_t *
315 1.1 christos nat64_prefix_create(struct in6_addr *address, int prefix_length, nat64_preference pref, int rloc)
316 1.1 christos {
317 1.1 christos nat64_prefix_t *prefix;
318 1.1 christos
319 1.1 christos prefix = calloc(1, (sizeof *prefix));
320 1.1 christos if (prefix == NULL) {
321 1.1 christos ERROR("no memory when create nat64 prefix");
322 1.1 christos return NULL;
323 1.1 christos }
324 1.1 christos in6prefix_copy(&prefix->prefix, address, NAT64_PREFIX_SLASH_96_BYTES);
325 1.1 christos prefix->prefix_len = prefix_length;
326 1.1 christos prefix->priority = pref;
327 1.1 christos prefix->rloc = rloc;
328 1.1 christos RETAIN_HERE(prefix, nat64_prefix);
329 1.1 christos return prefix;
330 1.1 christos }
331 1.1 christos
332 1.1 christos static nat64_prefix_t *
333 1.1 christos nat64_prefix_dup(nat64_prefix_t *src)
334 1.1 christos {
335 1.1 christos return nat64_prefix_create(&src->prefix, src->prefix_len, src->priority, src->rloc);
336 1.1 christos }
337 1.1 christos
338 1.1 christos static bool
339 1.1 christos nat64_preference_has_higher_priority(const nat64_preference higher, const nat64_preference lower)
340 1.1 christos {
341 1.1 christos // smaller value means higher priority
342 1.1 christos if (higher < lower) {
343 1.1 christos return true;
344 1.1 christos } else {
345 1.1 christos return false;
346 1.1 christos }
347 1.1 christos }
348 1.1 christos
349 1.1 christos static bool
350 1.1 christos nat64_thread_has_routable_prefix(const route_state_t * const route_state)
351 1.1 christos {
352 1.1 christos bool have_routable_omr_prefix;
353 1.1 christos if (route_state->omr_publisher != NULL && omr_publisher_have_routable_prefix(route_state->omr_publisher)) {
354 1.1 christos have_routable_omr_prefix = true;
355 1.1 christos } else {
356 1.1 christos have_routable_omr_prefix = false;
357 1.1 christos }
358 1.1 christos return have_routable_omr_prefix;
359 1.1 christos }
360 1.1 christos
361 1.1 christos #define NAT64_EVENT_ANNOUNCE(state_machine, event) \
362 1.1 christos do { \
363 1.1 christos INFO("event " PUB_S_SRP " generated in state " PUB_S_SRP, \
364 1.1 christos event.name, state_machine->state_name); \
365 1.1 christos } while (false)
366 1.1 christos
367 1.1 christos #define NAT64_STATE_ANNOUNCE(state_machine, event) \
368 1.1 christos do { \
369 1.1 christos if (event != NULL) { \
370 1.1 christos INFO("event " PUB_S_SRP " received in state " PUB_S_SRP, \
371 1.1 christos event->name, state_machine->state_name); \
372 1.1 christos } else { \
373 1.1 christos INFO("entering state " PUB_S_SRP, \
374 1.1 christos state_machine->state_name); \
375 1.1 christos } \
376 1.1 christos } while (false)
377 1.1 christos
378 1.1 christos #define NAT64_UNEXPECTED_EVENT(state_machine, event) \
379 1.1 christos do { \
380 1.1 christos if (event != NULL) { \
381 1.1 christos INFO("unexpected event " PUB_S_SRP " received in state " PUB_S_SRP, \
382 1.1 christos event->name, state_machine->state_name); \
383 1.1 christos } else { \
384 1.1 christos INFO("unexpected NULL event received in state " PUB_S_SRP, \
385 1.1 christos state_machine->state_name); \
386 1.1 christos } \
387 1.1 christos } while (false)
388 1.1 christos
389 1.1 christos #define DECLARE_NAT64_STATE_GET(type, total) \
390 1.1 christos static type ## _state_t * \
391 1.1 christos type ## _state_get(type ## _state_type_t state) \
392 1.1 christos { \
393 1.1 christos static bool once = false; \
394 1.1 christos if (!once) { \
395 1.1 christos for (unsigned i = 0; i < total ## _NUM_STATES; i++) { \
396 1.1 christos if (type ## _states[i].state != (type ## _state_type_t)i) { \
397 1.1 christos ERROR("type ## states %d doesn't match " PUB_S_SRP, i, type ## _states[i].name); \
398 1.1 christos return NULL; \
399 1.1 christos } \
400 1.1 christos } \
401 1.1 christos once = true; \
402 1.1 christos } \
403 1.1 christos if (state < 0 || state > total ## _NUM_STATES) { \
404 1.1 christos return NULL; \
405 1.1 christos } \
406 1.1 christos return & type ## _states[state]; \
407 1.1 christos }
408 1.1 christos
409 1.1 christos #define DECLARE_NAT64_NEXT_STATE(type) \
410 1.1 christos static void \
411 1.1 christos type ## _next_state(type ## _t *state_machine, type ## _state_type_t state) \
412 1.1 christos { \
413 1.1 christos type ## _state_type_t next_state = state; \
414 1.1 christos do { \
415 1.1 christos type ## _state_t *new_state = type ## _state_get(next_state); \
416 1.1 christos if (new_state == NULL) { \
417 1.1 christos ERROR("next state is invalid: %d", next_state); \
418 1.1 christos return; \
419 1.1 christos } \
420 1.1 christos state_machine->state = next_state; \
421 1.1 christos state_machine->state_name = new_state->name; \
422 1.1 christos type ## _action_t action = new_state->action; \
423 1.1 christos if (action != NULL) { \
424 1.1 christos next_state = action(state_machine, NULL); \
425 1.1 christos } \
426 1.1 christos } while (next_state != type ## _state_invalid); \
427 1.1 christos }
428 1.1 christos
429 1.1 christos #define DECLARE_NAT64_EVENT_CONFIGURATION_GET(type, total) \
430 1.1 christos static type ## _configuration_t * \
431 1.1 christos type ## _configuration_get(type ## _type_t event) \
432 1.1 christos { \
433 1.1 christos static bool once = false; \
434 1.1 christos if (!once) { \
435 1.1 christos for (unsigned i = 0; i < total ## _NUM_EVENT_TYPES; i++) { \
436 1.1 christos if (type ## _configurations[i].event_type != (type ## _type_t)i) { \
437 1.1 christos ERROR("type ## event %d doesn't match " PUB_S_SRP, i, type ## _configurations[i].name); \
438 1.1 christos return NULL; \
439 1.1 christos } \
440 1.1 christos } \
441 1.1 christos once = true; \
442 1.1 christos } \
443 1.1 christos if (event < 0 || event > total ## _NUM_EVENT_TYPES) { \
444 1.1 christos return NULL; \
445 1.1 christos } \
446 1.1 christos return & type ## _configurations[event]; \
447 1.1 christos }
448 1.1 christos
449 1.1 christos #define NAT64_EVENT_NAME_DECL(name) { nat64_event_##name, #name }
450 1.1 christos
451 1.1 christos #define DECLARE_NAT64_EVENT_INIT(type) \
452 1.1 christos static void \
453 1.1 christos type ## _init(type ## _t *event, type ## _type_t event_type) \
454 1.1 christos { \
455 1.1 christos memset(event, 0, sizeof(*event)); \
456 1.1 christos type ## _configuration_t *event_config = type ## _configuration_get(event_type); \
457 1.1 christos if (event_config == NULL) { \
458 1.1 christos ERROR("invalid event type %d", event_type); \
459 1.1 christos return; \
460 1.1 christos } \
461 1.1 christos event->event_type = event_type; \
462 1.1 christos event->name = event_config->name; \
463 1.1 christos }
464 1.1 christos
465 1.1 christos #define DECLARE_NAT64_EVENT_DELIVER(type) \
466 1.1 christos static void \
467 1.1 christos type ## _event_deliver(type ## _t *state_machine, type ## _event_t *event) \
468 1.1 christos { \
469 1.1 christos type ## _state_t *state = type ## _state_get(state_machine->state); \
470 1.1 christos if (state == NULL) { \
471 1.1 christos ERROR("event " PUB_S_SRP " received in invalid state %d", event->name, state_machine->state); \
472 1.1 christos return; \
473 1.1 christos } \
474 1.1 christos if (state->action == NULL) { \
475 1.1 christos FAULT("event " PUB_S_SRP " received in state " PUB_S_SRP " with NULL action", event->name, state->name); \
476 1.1 christos return; \
477 1.1 christos } \
478 1.1 christos type ## _state_type_t next_state = state->action(state_machine, event); \
479 1.1 christos if (next_state != type ## _state_invalid) { \
480 1.1 christos type ## _next_state(state_machine, next_state); \
481 1.1 christos } \
482 1.1 christos }
483 1.1 christos
484 1.1 christos // ipv4 default route state machine start
485 1.1 christos static void nat64_ipv4_default_route_monitor_event_init(nat64_ipv4_default_route_monitor_event_t *event, nat64_ipv4_default_route_monitor_event_type_t event_type);
486 1.1 christos
487 1.1 christos typedef nat64_ipv4_default_route_monitor_state_type_t (*nat64_ipv4_default_route_monitor_action_t)(nat64_ipv4_default_route_monitor_t *NONNULL state_machine, nat64_ipv4_default_route_monitor_event_t *NULLABLE event);
488 1.1 christos
489 1.1 christos typedef struct {
490 1.1 christos nat64_ipv4_default_route_monitor_state_type_t state;
491 1.1 christos char *name;
492 1.1 christos nat64_ipv4_default_route_monitor_action_t action;
493 1.1 christos } nat64_ipv4_default_route_monitor_state_t;
494 1.1 christos
495 1.1 christos static nat64_ipv4_default_route_monitor_state_type_t
496 1.1 christos nat64_ipv4_default_route_monitor_init_action(nat64_ipv4_default_route_monitor_t *state_machine, nat64_ipv4_default_route_monitor_event_t *UNUSED event)
497 1.1 christos {
498 1.1 christos NAT64_STATE_ANNOUNCE(state_machine, event);
499 1.1 christos state_machine->has_ipv4_default_route = false;
500 1.1 christos return nat64_ipv4_default_route_monitor_state_wait_for_event;
501 1.1 christos }
502 1.1 christos
503 1.1 christos static nat64_ipv4_default_route_monitor_state_type_t
504 1.1 christos nat64_ipv4_default_route_monitor_wait_action(nat64_ipv4_default_route_monitor_t *state_machine, nat64_ipv4_default_route_monitor_event_t *event)
505 1.1 christos {
506 1.1 christos NAT64_STATE_ANNOUNCE(state_machine, event);
507 1.1 christos if (event == NULL) {
508 1.1 christos return nat64_ipv4_default_route_monitor_state_invalid;
509 1.1 christos } else if (event->event_type == nat64_event_ipv4_default_route_update) {
510 1.1 christos nat64_br_prefix_publisher_event_t out_event;
511 1.1 christos if (event->has_ipv4_connectivity == false) {
512 1.1 christos state_machine->has_ipv4_default_route = false;
513 1.1 christos nat64_br_prefix_publisher_event_init(&out_event, nat64_event_nat64_br_prefix_publisher_ipv4_default_route_went_away);
514 1.1 christos } else {
515 1.1 christos state_machine->has_ipv4_default_route = true;
516 1.1 christos nat64_br_prefix_publisher_event_init(&out_event, nat64_event_nat64_br_prefix_publisher_ipv4_default_route_showed_up);
517 1.1 christos }
518 1.1 christos NAT64_EVENT_ANNOUNCE(state_machine, out_event);
519 1.1 christos // Deliver out_event to BR prefix publisher
520 1.1 christos nat64_br_prefix_publisher_event_deliver(state_machine->nat64->nat64_br_prefix_publisher, &out_event);
521 1.1 christos } else {
522 1.1 christos NAT64_UNEXPECTED_EVENT(state_machine, event);
523 1.1 christos }
524 1.1 christos return nat64_ipv4_default_route_monitor_state_invalid;
525 1.1 christos }
526 1.1 christos
527 1.1 christos #define IPV4_STATE_NAME_DECL(name) nat64_ipv4_default_route_monitor_state_##name, #name
528 1.1 christos static nat64_ipv4_default_route_monitor_state_t
529 1.1 christos nat64_ipv4_default_route_monitor_states[] = {
530 1.1 christos { IPV4_STATE_NAME_DECL(invalid), NULL },
531 1.1 christos { IPV4_STATE_NAME_DECL(init), nat64_ipv4_default_route_monitor_init_action },
532 1.1 christos { IPV4_STATE_NAME_DECL(wait_for_event), nat64_ipv4_default_route_monitor_wait_action },
533 1.1 christos };
534 1.1 christos #define IPV4_DEFAULT_ROUTE_MONITOR_NUM_STATES (sizeof(nat64_ipv4_default_route_monitor_states) / sizeof(nat64_ipv4_default_route_monitor_state_t))
535 1.1 christos
536 1.1 christos DECLARE_NAT64_STATE_GET(nat64_ipv4_default_route_monitor, IPV4_DEFAULT_ROUTE_MONITOR);
537 1.1 christos DECLARE_NAT64_NEXT_STATE(nat64_ipv4_default_route_monitor);
538 1.1 christos
539 1.1 christos // ipv4 default route monitor event functions
540 1.1 christos typedef struct {
541 1.1 christos nat64_ipv4_default_route_monitor_event_type_t event_type;
542 1.1 christos char *name;
543 1.1 christos } nat64_ipv4_default_route_monitor_event_configuration_t;
544 1.1 christos
545 1.1 christos nat64_ipv4_default_route_monitor_event_configuration_t nat64_ipv4_default_route_monitor_event_configurations[] = {
546 1.1 christos NAT64_EVENT_NAME_DECL(ipv4_default_route_invalid),
547 1.1 christos NAT64_EVENT_NAME_DECL(ipv4_default_route_update),
548 1.1 christos NAT64_EVENT_NAME_DECL(ipv4_default_route_showed_up),
549 1.1 christos NAT64_EVENT_NAME_DECL(ipv4_default_route_went_away),
550 1.1 christos };
551 1.1 christos #define IPV4_DEFAULT_ROUTE_MONITOR_NUM_EVENT_TYPES (sizeof(nat64_ipv4_default_route_monitor_event_configurations) / sizeof(nat64_ipv4_default_route_monitor_event_configuration_t))
552 1.1 christos
553 1.1 christos DECLARE_NAT64_EVENT_CONFIGURATION_GET(nat64_ipv4_default_route_monitor_event, IPV4_DEFAULT_ROUTE_MONITOR);
554 1.1 christos DECLARE_NAT64_EVENT_INIT(nat64_ipv4_default_route_monitor_event);
555 1.1 christos DECLARE_NAT64_EVENT_DELIVER(nat64_ipv4_default_route_monitor);
556 1.1 christos
557 1.1 christos void
558 1.1 christos nat64_default_route_update(nat64_t *NONNULL nat64, bool has_ipv4_connectivity)
559 1.1 christos {
560 1.1 christos if (has_ipv4_connectivity != nat64->ipv4_monitor->has_ipv4_default_route){
561 1.1 christos nat64_ipv4_default_route_monitor_event_t event;
562 1.1 christos nat64_ipv4_default_route_monitor_event_init(&event, nat64_event_ipv4_default_route_update);
563 1.1 christos event.has_ipv4_connectivity = has_ipv4_connectivity;
564 1.1 christos nat64_ipv4_default_route_monitor_event_deliver(nat64->ipv4_monitor, &event);
565 1.1 christos }
566 1.1 christos }
567 1.1 christos // ipv4 default route state machine end
568 1.1 christos
569 1.1 christos // Infrastructure nat64 prefix monitor state machine start
570 1.1 christos static void nat64_infra_prefix_monitor_event_init(nat64_infra_prefix_monitor_event_t *event, nat64_infra_prefix_monitor_event_type_t event_type);
571 1.1 christos static void nat64_infra_prefix_monitor_event_deliver(nat64_infra_prefix_monitor_t *state_machine, nat64_infra_prefix_monitor_event_t *event);
572 1.1 christos typedef nat64_infra_prefix_monitor_state_type_t (*nat64_infra_prefix_monitor_action_t)(nat64_infra_prefix_monitor_t *NONNULL sm, nat64_infra_prefix_monitor_event_t *NULLABLE event);
573 1.1 christos
574 1.1 christos typedef struct {
575 1.1 christos nat64_infra_prefix_monitor_state_type_t state;
576 1.1 christos char *name;
577 1.1 christos nat64_infra_prefix_monitor_action_t action;
578 1.1 christos } nat64_infra_prefix_monitor_state_t;
579 1.1 christos
580 1.1 christos static void
581 1.1 christos nat64_query_infra_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
582 1.1 christos DNSServiceErrorType errorCode, const char *fullname, uint16_t rrtype, uint16_t rrclass,
583 1.1 christos uint16_t rdlen, const void *rdata, uint32_t ttl, void *context)
584 1.1 christos {
585 1.1 christos (void)(sdRef);
586 1.1 christos (void)(interfaceIndex);
587 1.1 christos
588 1.1 christos nat64_infra_prefix_monitor_t *state_machine = context;
589 1.1 christos
590 1.1 christos if (errorCode == kDNSServiceErr_NoError) {
591 1.1 christos SEGMENTED_IPv6_ADDR_GEN_SRP(rdata, ipv6_rdata_buf);
592 1.1 christos INFO("LLQ " PRI_S_SRP PRI_SEGMENTED_IPv6_ADDR_SRP
593 1.1 christos "name: " PRI_S_SRP ", rrtype: %u, rrclass: %u, rdlen: %u, ttl: %u.",
594 1.1 christos (flags & kDNSServiceFlagsAdd) ? "adding " : "removing ",
595 1.1 christos SEGMENTED_IPv6_ADDR_PARAM_SRP(rdata, ipv6_rdata_buf), fullname, rrtype, rrclass, rdlen, ttl);
596 1.1 christos nat64_infra_prefix_monitor_event_t event;
597 1.1 christos nat64_infra_prefix_monitor_event_init(&event, nat64_event_infra_prefix_update);
598 1.1 christos event.flags = flags;
599 1.1 christos event.rdata = rdata;
600 1.1 christos NAT64_EVENT_ANNOUNCE(state_machine, event);
601 1.1 christos nat64_infra_prefix_monitor_event_deliver(state_machine, &event);
602 1.1 christos } else {
603 1.1 christos if (errorCode == kDNSServiceErr_NoSuchRecord) {
604 1.1 christos // This should never happen.
605 1.1 christos INFO("No such record for " PRI_S_SRP , NAT64_PREFIX_LLQ_QUERY_DOMAIN);
606 1.1 christos } else if (errorCode == kDNSServiceErr_ServiceNotRunning) {
607 1.1 christos INFO("daemon disconnected (probably daemon crash).");
608 1.1 christos } else {
609 1.1 christos INFO("Got error code %d when query " PRI_S_SRP , errorCode, NAT64_PREFIX_LLQ_QUERY_DOMAIN);
610 1.1 christos }
611 1.1 christos DNSServiceRefDeallocate(state_machine->sdRef);
612 1.1 christos state_machine->sdRef = NULL;
613 1.1 christos
614 1.1 christos // We enter with a reference held on the state machine object. If there is no error, that means we got some kind
615 1.1 christos // of result, and so we don't release the reference because we can still get more results. If, on the other hand,
616 1.1 christos // we get an error, we will restart the query after a delay. This means that the reference we were passed is
617 1.1 christos // still needed for the duration of the dispatch_after call. When that timer expires, if the state machine hasn't
618 1.1 christos // been canceled in the meantime, we restart the query.
619 1.1 christos dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC),
620 1.1 christos dispatch_get_main_queue(), ^(void) {
621 1.1 christos if (!state_machine->canceled) {
622 1.1 christos nat64_query_prefix_on_infra(state_machine);
623 1.1 christos }
624 1.1 christos RELEASE_HERE(state_machine, nat64_infra_prefix_monitor);
625 1.1 christos });
626 1.1 christos }
627 1.1 christos }
628 1.1 christos
629 1.1 christos static bool
630 1.1 christos nat64_query_prefix_on_infra(nat64_infra_prefix_monitor_t *state_machine)
631 1.1 christos {
632 1.1 christos OSStatus err;
633 1.1 christos
634 1.1 christos err = DNSServiceQueryRecord(&state_machine->sdRef, kDNSServiceFlagsLongLivedQuery, kDNSServiceInterfaceIndexAny, NAT64_PREFIX_LLQ_QUERY_DOMAIN, kDNSServiceType_AAAA, kDNSServiceClass_IN, nat64_query_infra_callback, state_machine);
635 1.1 christos if (err != kDNSServiceErr_NoError) {
636 1.1 christos ERROR("DNSServiceQueryRecord failed for " PRI_S_SRP ": %d", NAT64_PREFIX_LLQ_QUERY_DOMAIN, (int)err);
637 1.1 christos return false;
638 1.1 christos }
639 1.1 christos RETAIN_HERE(state_machine, nat64_infra_prefix_monitor); // For the callback.
640 1.1 christos err = DNSServiceSetDispatchQueue(state_machine->sdRef, dispatch_get_main_queue());
641 1.1 christos if (err != kDNSServiceErr_NoError) {
642 1.1 christos ERROR("DNSServiceSetDispatchQueue failed for " PRI_S_SRP ": %d", NAT64_PREFIX_LLQ_QUERY_DOMAIN, (int)err);
643 1.1 christos return false;
644 1.1 christos }
645 1.1 christos return true;
646 1.1 christos }
647 1.1 christos
648 1.1 christos static nat64_infra_prefix_monitor_state_type_t
649 1.1 christos nat64_infra_prefix_monitor_init_action(nat64_infra_prefix_monitor_t *state_machine, nat64_infra_prefix_monitor_event_t * event)
650 1.1 christos {
651 1.1 christos NAT64_STATE_ANNOUNCE(state_machine, event);
652 1.1 christos // Init action: start LLQ.
653 1.1 christos if (!nat64_query_prefix_on_infra(state_machine)) {
654 1.1 christos return nat64_infra_prefix_monitor_state_invalid;
655 1.1 christos }
656 1.1 christos // Switch to next state.
657 1.1 christos return nat64_infra_prefix_monitor_state_wait_for_change;
658 1.1 christos }
659 1.1 christos
660 1.1 christos static nat64_infra_prefix_monitor_state_type_t
661 1.1 christos nat64_infra_prefix_monitor_wait_action(nat64_infra_prefix_monitor_t *state_machine, nat64_infra_prefix_monitor_event_t *event)
662 1.1 christos {
663 1.1 christos NAT64_STATE_ANNOUNCE(state_machine, event);
664 1.1 christos if (event == NULL) {
665 1.1 christos return nat64_infra_prefix_monitor_state_invalid;
666 1.1 christos } else if (event->event_type == nat64_event_infra_prefix_update){
667 1.1 christos bool changed = false;
668 1.1 christos if (event->flags & kDNSServiceFlagsAdd) {
669 1.1 christos nat64_prefix_t **ppref = &state_machine->infra_nat64_prefixes, *prefix = NULL;
670 1.1 christos while (*ppref != NULL) {
671 1.1 christos prefix = *ppref;
672 1.1 christos if (!memcmp(&prefix->prefix, event->rdata, NAT64_PREFIX_SLASH_96_BYTES)) {
673 1.1 christos SEGMENTED_IPv6_ADDR_GEN_SRP(prefix->prefix.s6_addr, nat64_prefix_buf);
674 1.1 christos INFO("ignore dup infra prefix " PRI_SEGMENTED_IPv6_ADDR_SRP,
675 1.1 christos SEGMENTED_IPv6_ADDR_PARAM_SRP(prefix->prefix.s6_addr, nat64_prefix_buf));
676 1.1 christos break;
677 1.1 christos } else {
678 1.1 christos ppref = &prefix->next;
679 1.1 christos }
680 1.1 christos }
681 1.1 christos if (*ppref == NULL) {
682 1.1 christos nat64_prefix_t * new_prefix = nat64_prefix_create((struct in6_addr *)event->rdata, NAT64_PREFIX_SLASH_96_BYTES, nat64_preference_medium, state_machine->nat64->route_state->srp_server->rloc16);
683 1.1 christos if (new_prefix == NULL) {
684 1.1 christos ERROR("no memory for nat64 prefix.");
685 1.1 christos return nat64_infra_prefix_monitor_state_invalid;
686 1.1 christos }
687 1.1 christos SEGMENTED_IPv6_ADDR_GEN_SRP(new_prefix->prefix.s6_addr, nat64_prefix_buf);
688 1.1 christos INFO("adding infra prefix " PRI_SEGMENTED_IPv6_ADDR_SRP " to list",
689 1.1 christos SEGMENTED_IPv6_ADDR_PARAM_SRP(new_prefix->prefix.s6_addr, nat64_prefix_buf));
690 1.1 christos new_prefix->next = state_machine->infra_nat64_prefixes;
691 1.1 christos state_machine->infra_nat64_prefixes = new_prefix;
692 1.1 christos changed = true;
693 1.1 christos }
694 1.1 christos } else {
695 1.1 christos nat64_prefix_t **ppref = &state_machine->infra_nat64_prefixes, *prefix = NULL;
696 1.1 christos while (*ppref != NULL) {
697 1.1 christos prefix = *ppref;
698 1.1 christos if (!memcmp(&prefix->prefix, event->rdata, NAT64_PREFIX_SLASH_96_BYTES)) {
699 1.1 christos *ppref = prefix->next;
700 1.1 christos SEGMENTED_IPv6_ADDR_GEN_SRP(prefix->prefix.s6_addr, nat64_prefix_buf);
701 1.1 christos INFO("removing infra prefix " PRI_SEGMENTED_IPv6_ADDR_SRP " from list",
702 1.1 christos SEGMENTED_IPv6_ADDR_PARAM_SRP(prefix->prefix.s6_addr, nat64_prefix_buf));
703 1.1 christos RELEASE_HERE(prefix, nat64_prefix);
704 1.1 christos changed = true;
705 1.1 christos } else {
706 1.1 christos ppref = &prefix->next;
707 1.1 christos }
708 1.1 christos }
709 1.1 christos }
710 1.1 christos if (changed){
711 1.1 christos return nat64_infra_prefix_monitor_state_change_occurred;
712 1.1 christos }
713 1.1 christos } else {
714 1.1 christos NAT64_UNEXPECTED_EVENT(state_machine, event);
715 1.1 christos }
716 1.1 christos return nat64_infra_prefix_monitor_state_invalid;
717 1.1 christos }
718 1.1 christos
719 1.1 christos static nat64_infra_prefix_monitor_state_type_t
720 1.1 christos nat64_infra_prefix_monitor_change_occurred_action(nat64_infra_prefix_monitor_t *state_machine, nat64_infra_prefix_monitor_event_t * event)
721 1.1 christos {
722 1.1 christos nat64_infra_prefix_publisher_event_t out_event_to_nat64_infra_prefix_publisher;
723 1.1 christos nat64_br_prefix_publisher_event_t out_event_to_nat64_br_prefix_publisher;
724 1.1 christos
725 1.1 christos NAT64_STATE_ANNOUNCE(state_machine, event);
726 1.1 christos nat64_infra_prefix_publisher_event_init(&out_event_to_nat64_infra_prefix_publisher, nat64_event_nat64_infra_prefix_publisher_infra_prefix_changed);
727 1.1 christos out_event_to_nat64_infra_prefix_publisher.prefix = state_machine->infra_nat64_prefixes;
728 1.1 christos NAT64_EVENT_ANNOUNCE(state_machine, out_event_to_nat64_infra_prefix_publisher);
729 1.1 christos // Deliver this event to infra prefix publisher.
730 1.1 christos nat64_infra_prefix_publisher_event_deliver(state_machine->nat64->nat64_infra_prefix_publisher, &out_event_to_nat64_infra_prefix_publisher);
731 1.1 christos
732 1.1 christos nat64_br_prefix_publisher_event_init(&out_event_to_nat64_br_prefix_publisher, nat64_event_nat64_br_prefix_publisher_infra_prefix_changed);
733 1.1 christos out_event_to_nat64_br_prefix_publisher.prefix = state_machine->infra_nat64_prefixes;
734 1.1 christos NAT64_EVENT_ANNOUNCE(state_machine, out_event_to_nat64_br_prefix_publisher);
735 1.1 christos // Deliver this event to BR prefix publisher.
736 1.1 christos nat64_br_prefix_publisher_event_deliver(state_machine->nat64->nat64_br_prefix_publisher, &out_event_to_nat64_br_prefix_publisher);
737 1.1 christos
738 1.1 christos return nat64_infra_prefix_monitor_state_wait_for_change;
739 1.1 christos }
740 1.1 christos
741 1.1 christos #define INFRA_STATE_NAME_DECL(name) nat64_infra_prefix_monitor_state_##name, #name
742 1.1 christos static nat64_infra_prefix_monitor_state_t
743 1.1 christos nat64_infra_prefix_monitor_states[] = {
744 1.1 christos { INFRA_STATE_NAME_DECL(invalid), NULL },
745 1.1 christos { INFRA_STATE_NAME_DECL(init), nat64_infra_prefix_monitor_init_action },
746 1.1 christos { INFRA_STATE_NAME_DECL(wait_for_change), nat64_infra_prefix_monitor_wait_action },
747 1.1 christos { INFRA_STATE_NAME_DECL(change_occurred), nat64_infra_prefix_monitor_change_occurred_action },
748 1.1 christos };
749 1.1 christos #define INFRA_PREFIX_MONITOR_NUM_STATES (sizeof(nat64_infra_prefix_monitor_states) / sizeof(nat64_infra_prefix_monitor_state_t))
750 1.1 christos
751 1.1 christos DECLARE_NAT64_STATE_GET(nat64_infra_prefix_monitor, INFRA_PREFIX_MONITOR);
752 1.1 christos DECLARE_NAT64_NEXT_STATE(nat64_infra_prefix_monitor);
753 1.1 christos
754 1.1 christos // Infra prefix monitor event functions
755 1.1 christos typedef struct {
756 1.1 christos nat64_infra_prefix_monitor_event_type_t event_type;
757 1.1 christos char *name;
758 1.1 christos } nat64_infra_prefix_monitor_event_configuration_t;
759 1.1 christos
760 1.1 christos nat64_infra_prefix_monitor_event_configuration_t nat64_infra_prefix_monitor_event_configurations[] = {
761 1.1 christos NAT64_EVENT_NAME_DECL(infra_prefix_invalid),
762 1.1 christos NAT64_EVENT_NAME_DECL(infra_prefix_update),
763 1.1 christos };
764 1.1 christos #define INFRA_PREFIX_MONITOR_NUM_EVENT_TYPES (sizeof(nat64_infra_prefix_monitor_event_configurations) / sizeof(nat64_infra_prefix_monitor_event_configuration_t))
765 1.1 christos
766 1.1 christos DECLARE_NAT64_EVENT_CONFIGURATION_GET(nat64_infra_prefix_monitor_event, INFRA_PREFIX_MONITOR);
767 1.1 christos DECLARE_NAT64_EVENT_INIT(nat64_infra_prefix_monitor_event);
768 1.1 christos DECLARE_NAT64_EVENT_DELIVER(nat64_infra_prefix_monitor);
769 1.1 christos
770 1.1 christos // Infrastructure nat64 prefix monitor state machine end
771 1.1 christos
772 1.1 christos
773 1.1 christos
774 1.1 christos // Thread nat64 prefix monitor state machine start
775 1.1 christos static void nat64_thread_prefix_monitor_event_init(nat64_thread_prefix_monitor_event_t *event, nat64_thread_prefix_monitor_event_type_t event_type);
776 1.1 christos static void nat64_thread_prefix_monitor_event_deliver(nat64_thread_prefix_monitor_t *state_machine, nat64_thread_prefix_monitor_event_t *event);
777 1.1 christos typedef nat64_thread_prefix_monitor_state_type_t (*nat64_thread_prefix_monitor_action_t)(nat64_thread_prefix_monitor_t *NONNULL sm, nat64_thread_prefix_monitor_event_t *NULLABLE event);
778 1.1 christos
779 1.1 christos typedef struct {
780 1.1 christos nat64_thread_prefix_monitor_state_type_t state;
781 1.1 christos char *name;
782 1.1 christos nat64_thread_prefix_monitor_action_t action;
783 1.1 christos } nat64_thread_prefix_monitor_state_t;
784 1.1 christos
785 1.1 christos static void
786 1.1 christos nat64_thread_prefix_monitor_context_release(void *context)
787 1.1 christos {
788 1.1 christos nat64_thread_prefix_monitor_t *state_machine = context;
789 1.1 christos RELEASE_HERE(state_machine, nat64_thread_prefix_monitor);
790 1.1 christos }
791 1.1 christos
792 1.1 christos static void
793 1.1 christos nat64_thread_prefix_monitor_wakeup(void *context)
794 1.1 christos {
795 1.1 christos nat64_thread_prefix_monitor_t *state_machine = context;
796 1.1 christos nat64_thread_prefix_monitor_event_t out_event;
797 1.1 christos nat64_thread_prefix_monitor_event_init(&out_event, nat64_event_thread_prefix_init_wait_ended);
798 1.1 christos NAT64_EVENT_ANNOUNCE(state_machine, out_event);
799 1.1 christos nat64_thread_prefix_monitor_event_deliver(state_machine, &out_event);
800 1.1 christos }
801 1.1 christos
802 1.1 christos static nat64_thread_prefix_monitor_state_type_t
803 1.1 christos nat64_thread_prefix_monitor_init_action(nat64_thread_prefix_monitor_t *state_machine, nat64_thread_prefix_monitor_event_t * event)
804 1.1 christos {
805 1.1 christos NAT64_STATE_ANNOUNCE(state_machine, event);
806 1.1 christos // Init action: start timer.
807 1.1 christos if (state_machine->timer == NULL) {
808 1.1 christos state_machine->timer = ioloop_wakeup_create();
809 1.1 christos if (state_machine->timer == NULL) {
810 1.1 christos ERROR("no memory when create timer");
811 1.1 christos return nat64_thread_prefix_monitor_state_invalid;
812 1.1 christos }
813 1.1 christos RETAIN_HERE(state_machine, nat64_thread_prefix_monitor);
814 1.1 christos // wait rand(0,10) seconds
815 1.1 christos ioloop_add_wake_event(state_machine->timer, state_machine, nat64_thread_prefix_monitor_wakeup, nat64_thread_prefix_monitor_context_release, srp_random16() % (NAT64_THREAD_PREFIX_SETTLING_TIME * IOLOOP_SECOND));
816 1.1 christos } else {
817 1.1 christos INFO("thread prefix monitor timer already started");
818 1.1 christos }
819 1.1 christos // Switch to next state.
820 1.1 christos return nat64_thread_prefix_monitor_state_wait_for_settling;
821 1.1 christos }
822 1.1 christos
823 1.1 christos static nat64_thread_prefix_monitor_state_type_t
824 1.1 christos nat64_thread_prefix_monitor_wait_for_settling_action(nat64_thread_prefix_monitor_t *state_machine, nat64_thread_prefix_monitor_event_t * event)
825 1.1 christos {
826 1.1 christos NAT64_STATE_ANNOUNCE(state_machine, event);
827 1.1 christos if (event == NULL) {
828 1.1 christos return nat64_thread_prefix_monitor_state_invalid;
829 1.1 christos } else if (event->event_type == nat64_event_thread_prefix_init_wait_ended){
830 1.1 christos // Switch to next state.
831 1.1 christos return nat64_thread_prefix_monitor_state_wait_for_change;
832 1.1 christos } else {
833 1.1 christos NAT64_UNEXPECTED_EVENT(state_machine, event);
834 1.1 christos return nat64_thread_prefix_monitor_state_invalid;
835 1.1 christos }
836 1.1 christos }
837 1.1 christos
838 1.1 christos static nat64_preference
839 1.1 christos route_pref_to_nat64_pref(offmesh_route_preference_t route_pref)
840 1.1 christos {
841 1.1 christos if (route_pref == offmesh_route_preference_low) {
842 1.1 christos return nat64_preference_low;
843 1.1 christos } else if (route_pref == offmesh_route_preference_high) {
844 1.1 christos return nat64_preference_high;
845 1.1 christos } else if (route_pref == offmesh_route_preference_medium) {
846 1.1 christos return nat64_preference_medium;
847 1.1 christos } else {
848 1.1 christos ERROR("Unknown route prefix preference %d", route_pref);
849 1.1 christos return nat64_preference_reserved;
850 1.1 christos }
851 1.1 christos }
852 1.1 christos
853 1.1 christos static char *
854 1.1 christos get_nat64_prefix_pref_name(nat64_preference pref)
855 1.1 christos {
856 1.1 christos if (pref == nat64_preference_low) {
857 1.1 christos return "low";
858 1.1 christos } else if (pref == nat64_preference_high) {
859 1.1 christos return "high";
860 1.1 christos } else if (pref == nat64_preference_medium) {
861 1.1 christos return "medium";
862 1.1 christos } else {
863 1.1 christos ERROR("Unknown nat64 prefix preference %d", pref);
864 1.1 christos return "unknown";
865 1.1 christos }
866 1.1 christos }
867 1.1 christos
868 1.1 christos static nat64_thread_prefix_monitor_state_type_t
869 1.1 christos nat64_thread_prefix_monitor_wait_for_change_action(nat64_thread_prefix_monitor_t *state_machine, nat64_thread_prefix_monitor_event_t * event)
870 1.1 christos {
871 1.1 christos NAT64_STATE_ANNOUNCE(state_machine, event);
872 1.1 christos if (event == NULL) {
873 1.1 christos return nat64_thread_prefix_monitor_state_invalid;
874 1.1 christos } else if (event->event_type == nat64_event_thread_prefix_update){
875 1.1 christos size_t i;
876 1.1 christos nat64_prefix_t **ppref = &state_machine->thread_nat64_prefixes, *prefix = NULL;
877 1.1 christos bool changed = false;
878 1.1 christos // Delete any NAT64 prefixes that are not in the list provided by Thread.
879 1.1 christos while (*ppref != NULL) {
880 1.1 christos prefix = *ppref;
881 1.1 christos for (i = 0; i < event->routes->num; i++) {
882 1.1 christos cti_route_t *route = event->routes->routes[i];
883 1.1 christos if (route->nat64 && route->origin == offmesh_route_origin_ncp){
884 1.1 christos if (!in6prefix_compare(&prefix->prefix, &route->prefix, NAT64_PREFIX_SLASH_96_BYTES)) {
885 1.1 christos break;
886 1.1 christos }
887 1.1 christos }
888 1.1 christos }
889 1.1 christos if (i == event->routes->num) {
890 1.1 christos *ppref = prefix->next;
891 1.1 christos SEGMENTED_IPv6_ADDR_GEN_SRP(prefix->prefix.s6_addr, nat64_prefix_buf);
892 1.1 christos INFO("prefix " PRI_SEGMENTED_IPv6_ADDR_SRP " with pref " PRI_S_SRP " went away",
893 1.1 christos SEGMENTED_IPv6_ADDR_PARAM_SRP(prefix->prefix.s6_addr, nat64_prefix_buf),
894 1.1 christos get_nat64_prefix_pref_name(prefix->priority));
895 1.1 christos RELEASE_HERE(prefix, nat64_prefix);
896 1.1 christos changed = true;
897 1.1 christos } else {
898 1.1 christos ppref = &prefix->next;
899 1.1 christos }
900 1.1 christos }
901 1.1 christos // Add any NAT64 prefixes that are not present.
902 1.1 christos for (i = 0; i < event->routes->num; i++) {
903 1.1 christos cti_route_t *route = event->routes->routes[i];
904 1.1 christos if (route->nat64 && route->origin == offmesh_route_origin_ncp) {
905 1.1 christos for(prefix = state_machine->thread_nat64_prefixes; prefix != NULL; prefix = prefix->next){
906 1.1 christos if (!in6prefix_compare(&prefix->prefix, &route->prefix, NAT64_PREFIX_SLASH_96_BYTES)) {
907 1.1 christos break;
908 1.1 christos }
909 1.1 christos }
910 1.1 christos if (prefix == NULL) {
911 1.1 christos prefix = nat64_prefix_create(&route->prefix, NAT64_PREFIX_SLASH_96_BYTES, route_pref_to_nat64_pref(route->preference), route->rloc);
912 1.1 christos if (prefix == NULL) {
913 1.1 christos ERROR("no memory for nat64 prefix.");
914 1.1 christos return nat64_thread_prefix_monitor_state_invalid;
915 1.1 christos } else {
916 1.1 christos SEGMENTED_IPv6_ADDR_GEN_SRP(prefix->prefix.s6_addr, nat64_prefix_buf);
917 1.1 christos INFO("prefix " PRI_SEGMENTED_IPv6_ADDR_SRP " with pref " PRI_S_SRP " showed up",
918 1.1 christos SEGMENTED_IPv6_ADDR_PARAM_SRP(prefix->prefix.s6_addr, nat64_prefix_buf),
919 1.1 christos get_nat64_prefix_pref_name(prefix->priority));
920 1.1 christos *ppref = prefix;
921 1.1 christos ppref = &prefix->next;
922 1.1 christos changed = true;
923 1.1 christos }
924 1.1 christos }
925 1.1 christos }
926 1.1 christos }
927 1.1 christos if (changed) {
928 1.1 christos // Switch to next state.
929 1.1 christos return nat64_thread_prefix_monitor_state_change_occurred;
930 1.1 christos }
931 1.1 christos } else {
932 1.1 christos NAT64_UNEXPECTED_EVENT(state_machine, event);
933 1.1 christos }
934 1.1 christos return nat64_thread_prefix_monitor_state_invalid;
935 1.1 christos }
936 1.1 christos
937 1.1 christos static nat64_thread_prefix_monitor_state_type_t
938 1.1 christos nat64_thread_prefix_monitor_change_occurred_action(nat64_thread_prefix_monitor_t *state_machine, nat64_thread_prefix_monitor_event_t * event)
939 1.1 christos {
940 1.1 christos nat64_infra_prefix_publisher_event_t out_event_to_nat64_infra_prefix_publisher;
941 1.1 christos nat64_br_prefix_publisher_event_t out_event_to_nat64_br_prefix_publisher;
942 1.1 christos
943 1.1 christos NAT64_STATE_ANNOUNCE(state_machine, event);
944 1.1 christos nat64_infra_prefix_publisher_event_init(&out_event_to_nat64_infra_prefix_publisher, nat64_event_nat64_infra_prefix_publisher_thread_prefix_changed);
945 1.1 christos out_event_to_nat64_infra_prefix_publisher.prefix = state_machine->thread_nat64_prefixes;
946 1.1 christos NAT64_EVENT_ANNOUNCE(state_machine, out_event_to_nat64_infra_prefix_publisher);
947 1.1 christos // Deliver this event to infra prefix publisher.
948 1.1 christos nat64_infra_prefix_publisher_event_deliver(state_machine->nat64->nat64_infra_prefix_publisher, &out_event_to_nat64_infra_prefix_publisher);
949 1.1 christos
950 1.1 christos nat64_br_prefix_publisher_event_init(&out_event_to_nat64_br_prefix_publisher, nat64_event_nat64_br_prefix_publisher_thread_prefix_changed);
951 1.1 christos out_event_to_nat64_br_prefix_publisher.prefix = state_machine->thread_nat64_prefixes;
952 1.1 christos NAT64_EVENT_ANNOUNCE(state_machine, out_event_to_nat64_br_prefix_publisher);
953 1.1 christos // Deliver this event to BR prefix publisher.
954 1.1 christos nat64_br_prefix_publisher_event_deliver(state_machine->nat64->nat64_br_prefix_publisher, &out_event_to_nat64_br_prefix_publisher);
955 1.1 christos
956 1.1 christos return nat64_thread_prefix_monitor_state_wait_for_change;
957 1.1 christos }
958 1.1 christos
959 1.1 christos #define THREAD_STATE_NAME_DECL(name) nat64_thread_prefix_monitor_state_##name, #name
960 1.1 christos static nat64_thread_prefix_monitor_state_t
961 1.1 christos nat64_thread_prefix_monitor_states[] = {
962 1.1 christos { THREAD_STATE_NAME_DECL(invalid), NULL },
963 1.1 christos { THREAD_STATE_NAME_DECL(init), nat64_thread_prefix_monitor_init_action },
964 1.1 christos { THREAD_STATE_NAME_DECL(wait_for_settling), nat64_thread_prefix_monitor_wait_for_settling_action },
965 1.1 christos { THREAD_STATE_NAME_DECL(wait_for_change), nat64_thread_prefix_monitor_wait_for_change_action },
966 1.1 christos { THREAD_STATE_NAME_DECL(change_occurred), nat64_thread_prefix_monitor_change_occurred_action },
967 1.1 christos };
968 1.1 christos #define THREAD_PREFIX_MONITOR_NUM_STATES (sizeof(nat64_thread_prefix_monitor_states) / sizeof(nat64_thread_prefix_monitor_state_t))
969 1.1 christos
970 1.1 christos DECLARE_NAT64_STATE_GET(nat64_thread_prefix_monitor, THREAD_PREFIX_MONITOR);
971 1.1 christos DECLARE_NAT64_NEXT_STATE(nat64_thread_prefix_monitor);
972 1.1 christos
973 1.1 christos // Thread prefix monitor event functions
974 1.1 christos typedef struct {
975 1.1 christos nat64_thread_prefix_monitor_event_type_t event_type;
976 1.1 christos char *name;
977 1.1 christos } nat64_thread_prefix_monitor_event_configuration_t;
978 1.1 christos
979 1.1 christos nat64_thread_prefix_monitor_event_configuration_t nat64_thread_prefix_monitor_event_configurations[] = {
980 1.1 christos NAT64_EVENT_NAME_DECL(thread_prefix_invalid),
981 1.1 christos NAT64_EVENT_NAME_DECL(thread_prefix_init_wait_ended),
982 1.1 christos NAT64_EVENT_NAME_DECL(thread_prefix_update),
983 1.1 christos };
984 1.1 christos #define THREAD_PREFIX_MONITOR_NUM_EVENT_TYPES (sizeof(nat64_thread_prefix_monitor_event_configurations) / sizeof(nat64_thread_prefix_monitor_event_configuration_t))
985 1.1 christos
986 1.1 christos DECLARE_NAT64_EVENT_CONFIGURATION_GET(nat64_thread_prefix_monitor_event, THREAD_PREFIX_MONITOR);
987 1.1 christos DECLARE_NAT64_EVENT_INIT(nat64_thread_prefix_monitor_event);
988 1.1 christos DECLARE_NAT64_EVENT_DELIVER(nat64_thread_prefix_monitor);
989 1.1 christos
990 1.1 christos // Thread nat64 prefix monitor state machine end
991 1.1 christos
992 1.1 christos
993 1.1 christos // Infrastructure nat64 prefix publisher state machine start
994 1.1 christos typedef nat64_infra_prefix_publisher_state_type_t (*nat64_infra_prefix_publisher_action_t)(nat64_infra_prefix_publisher_t *NONNULL sm, nat64_infra_prefix_publisher_event_t *NULLABLE event);
995 1.1 christos
996 1.1 christos typedef struct {
997 1.1 christos nat64_infra_prefix_publisher_state_type_t state;
998 1.1 christos char *name;
999 1.1 christos nat64_infra_prefix_publisher_action_t action;
1000 1.1 christos } nat64_infra_prefix_publisher_state_t;
1001 1.1 christos
1002 1.1 christos static nat64_infra_prefix_publisher_state_type_t
1003 1.1 christos nat64_infra_prefix_publisher_init_action(nat64_infra_prefix_publisher_t *state_machine, nat64_infra_prefix_publisher_event_t * event)
1004 1.1 christos {
1005 1.1 christos NAT64_STATE_ANNOUNCE(state_machine, event);
1006 1.1 christos // Init action
1007 1.1 christos
1008 1.1 christos // Switch to next state.
1009 1.1 christos return nat64_infra_prefix_publisher_state_wait;
1010 1.1 christos }
1011 1.1 christos
1012 1.1 christos static int
1013 1.1 christos nat64_num_infra_prefix(const nat64_prefix_t *prefix)
1014 1.1 christos {
1015 1.1 christos int num_infra_prefix = 0;
1016 1.1 christos
1017 1.1 christos for (; prefix != NULL; prefix = prefix->next) {
1018 1.1 christos if (nat64_preference_has_higher_priority(prefix->priority, nat64_preference_low)) {
1019 1.1 christos num_infra_prefix++;
1020 1.1 christos }
1021 1.1 christos }
1022 1.1 christos INFO("%d infra nat64 prefixes", num_infra_prefix);
1023 1.1 christos return num_infra_prefix;
1024 1.1 christos }
1025 1.1 christos
1026 1.1 christos static nat64_infra_prefix_publisher_state_type_t
1027 1.1 christos nat64_infra_prefix_publisher_wait_action(nat64_infra_prefix_publisher_t *state_machine, nat64_infra_prefix_publisher_event_t *event)
1028 1.1 christos {
1029 1.1 christos NAT64_STATE_ANNOUNCE(state_machine, event);
1030 1.1 christos if (event == NULL) {
1031 1.1 christos return nat64_infra_prefix_publisher_state_invalid;
1032 1.1 christos } else if (event->event_type == nat64_event_nat64_infra_prefix_publisher_thread_prefix_changed) {
1033 1.1 christos if (nat64_num_infra_prefix(event->prefix) >= NAT64_INFRA_PREFIX_LIMIT) {
1034 1.1 christos INFO("more than %d infra nat64 prefix present on thread network, ignore", NAT64_INFRA_PREFIX_LIMIT);
1035 1.1 christos return nat64_infra_prefix_publisher_state_ignore;
1036 1.1 christos } else {
1037 1.1 christos return nat64_infra_prefix_publisher_state_check;
1038 1.1 christos }
1039 1.1 christos } else if (event->event_type == nat64_event_nat64_infra_prefix_publisher_infra_prefix_changed) {
1040 1.1 christos // Check to see if it's appropriate to publish infra nat64 prefix
1041 1.1 christos if (event->prefix) {
1042 1.1 christos return nat64_infra_prefix_publisher_state_check;
1043 1.1 christos }
1044 1.1 christos } else if (event->event_type == nat64_event_nat64_infra_prefix_publisher_routable_omr_prefix_showed_up) {
1045 1.1 christos // Routable OMR prefix showed up, check to see if we should publish infra nat64 prefix
1046 1.1 christos return nat64_infra_prefix_publisher_state_check;
1047 1.1 christos } else {
1048 1.1 christos NAT64_UNEXPECTED_EVENT(state_machine, event);
1049 1.1 christos }
1050 1.1 christos return nat64_infra_prefix_publisher_state_invalid;
1051 1.1 christos }
1052 1.1 christos
1053 1.1 christos static nat64_infra_prefix_publisher_state_type_t
1054 1.1 christos nat64_infra_prefix_publisher_ignore_action(nat64_infra_prefix_publisher_t *state_machine, nat64_infra_prefix_publisher_event_t *event)
1055 1.1 christos {
1056 1.1 christos NAT64_STATE_ANNOUNCE(state_machine, event);
1057 1.1 christos if (event == NULL) {
1058 1.1 christos return nat64_infra_prefix_publisher_state_invalid;
1059 1.1 christos } else if (event->event_type == nat64_event_nat64_infra_prefix_publisher_thread_prefix_changed) {
1060 1.1 christos if (nat64_num_infra_prefix(event->prefix) >= NAT64_INFRA_PREFIX_LIMIT) {
1061 1.1 christos INFO("more than %d infra nat64 prefixes present, ignore", NAT64_INFRA_PREFIX_LIMIT);
1062 1.1 christos return nat64_infra_prefix_publisher_state_invalid;
1063 1.1 christos } else {
1064 1.1 christos return nat64_infra_prefix_publisher_state_check;
1065 1.1 christos }
1066 1.1 christos } else {
1067 1.1 christos NAT64_UNEXPECTED_EVENT(state_machine, event);
1068 1.1 christos }
1069 1.1 christos return nat64_infra_prefix_publisher_state_invalid;
1070 1.1 christos }
1071 1.1 christos
1072 1.1 christos static nat64_infra_prefix_publisher_state_type_t
1073 1.1 christos nat64_infra_prefix_publisher_check_action(nat64_infra_prefix_publisher_t *state_machine, nat64_infra_prefix_publisher_event_t *event)
1074 1.1 christos {
1075 1.1 christos NAT64_STATE_ANNOUNCE(state_machine, event);
1076 1.1 christos // Go to publish state when all of the following conditions are met:
1077 1.1 christos // 1. We have infra prefix
1078 1.1 christos // 2. We have routable OMR prefix
1079 1.1 christos // 3. The number of infra prefixes on thread network is less than NAT64_INFRA_PREFIX_LIMIT
1080 1.1 christos nat64_prefix_t *infra_prefix = state_machine->nat64->infra_monitor->infra_nat64_prefixes;
1081 1.1 christos if (infra_prefix && nat64_thread_has_routable_prefix(state_machine->nat64->route_state)
1082 1.1 christos && nat64_num_infra_prefix(state_machine->nat64->thread_monitor->thread_nat64_prefixes) < NAT64_INFRA_PREFIX_LIMIT) {
1083 1.1 christos state_machine->proposed_prefix = nat64_prefix_dup(infra_prefix);
1084 1.1 christos if (state_machine->proposed_prefix == NULL) {
1085 1.1 christos return nat64_infra_prefix_publisher_state_wait;
1086 1.1 christos }
1087 1.1 christos return nat64_infra_prefix_publisher_state_publish;
1088 1.1 christos } else {
1089 1.1 christos return nat64_infra_prefix_publisher_state_wait;
1090 1.1 christos }
1091 1.1 christos }
1092 1.1 christos
1093 1.1 christos static nat64_infra_prefix_publisher_state_type_t
1094 1.1 christos nat64_infra_prefix_publisher_publish_action(nat64_infra_prefix_publisher_t *state_machine, nat64_infra_prefix_publisher_event_t *event)
1095 1.1 christos {
1096 1.1 christos NAT64_STATE_ANNOUNCE(state_machine, event);
1097 1.1 christos SEGMENTED_IPv6_ADDR_GEN_SRP(state_machine->proposed_prefix->prefix.s6_addr, nat64_prefix_buf);
1098 1.1 christos INFO("publishing infra prefix " PRI_SEGMENTED_IPv6_ADDR_SRP,
1099 1.1 christos SEGMENTED_IPv6_ADDR_PARAM_SRP(state_machine->proposed_prefix->prefix.s6_addr, nat64_prefix_buf));
1100 1.1 christos nat64_add_prefix_to_update_queue(state_machine->nat64, state_machine->proposed_prefix,
1101 1.1 christos nat64_prefix_action_add);
1102 1.1 christos return nat64_infra_prefix_publisher_state_publishing;
1103 1.1 christos }
1104 1.1 christos
1105 1.1 christos static void
1106 1.1 christos nat64_remove_prefix_from_thread_monitor(nat64_t *nat64, nat64_prefix_t *deprecated_prefix)
1107 1.1 christos {
1108 1.1 christos nat64_prefix_t **ppref = &nat64->thread_monitor->thread_nat64_prefixes, *prefix = NULL;
1109 1.1 christos while (*ppref != NULL) {
1110 1.1 christos prefix = *ppref;
1111 1.1 christos if (!in6prefix_compare(&prefix->prefix, &deprecated_prefix->prefix, NAT64_PREFIX_SLASH_96_BYTES)
1112 1.1 christos && prefix->rloc == deprecated_prefix->rloc)
1113 1.1 christos {
1114 1.1 christos *ppref = prefix->next;
1115 1.1 christos SEGMENTED_IPv6_ADDR_GEN_SRP(prefix->prefix.s6_addr, nat64_prefix_buf);
1116 1.1 christos INFO("prefix " PRI_SEGMENTED_IPv6_ADDR_SRP " with pref " PRI_S_SRP " went away",
1117 1.1 christos SEGMENTED_IPv6_ADDR_PARAM_SRP(prefix->prefix.s6_addr, nat64_prefix_buf),
1118 1.1 christos get_nat64_prefix_pref_name(prefix->priority));
1119 1.1 christos RELEASE_HERE(prefix, nat64_prefix);
1120 1.1 christos } else {
1121 1.1 christos ppref = &prefix->next;
1122 1.1 christos }
1123 1.1 christos }
1124 1.1 christos }
1125 1.1 christos
1126 1.1 christos static nat64_infra_prefix_publisher_state_type_t
1127 1.1 christos nat64_infra_prefix_publisher_publishing_action(nat64_infra_prefix_publisher_t *state_machine, nat64_infra_prefix_publisher_event_t *event)
1128 1.1 christos {
1129 1.1 christos NAT64_STATE_ANNOUNCE(state_machine, event);
1130 1.1 christos if (event == NULL) {
1131 1.1 christos return nat64_infra_prefix_publisher_state_invalid;
1132 1.1 christos } else if (event->event_type == nat64_event_nat64_infra_prefix_publisher_infra_prefix_changed ||
1133 1.1 christos event->event_type == nat64_event_nat64_infra_prefix_publisher_shutdown)
1134 1.1 christos {
1135 1.1 christos nat64_prefix_t *infra_prefix;
1136 1.1 christos for (infra_prefix = event->prefix; infra_prefix; infra_prefix = infra_prefix->next) {
1137 1.1 christos if (!in6prefix_compare(&infra_prefix->prefix, &state_machine->proposed_prefix->prefix, NAT64_PREFIX_SLASH_96_BYTES)) {
1138 1.1 christos // The proposed prefix is still there, do nothing
1139 1.1 christos return nat64_infra_prefix_publisher_state_invalid;
1140 1.1 christos }
1141 1.1 christos }
1142 1.1 christos // The proposed infra prefix is gone
1143 1.1 christos SEGMENTED_IPv6_ADDR_GEN_SRP(state_machine->proposed_prefix->prefix.s6_addr, nat64_prefix_buf);
1144 1.1 christos INFO("The proposed infra prefix is gone, unpublishing infra prefix " PRI_SEGMENTED_IPv6_ADDR_SRP,
1145 1.1 christos SEGMENTED_IPv6_ADDR_PARAM_SRP(state_machine->proposed_prefix->prefix.s6_addr, nat64_prefix_buf));
1146 1.1 christos nat64_add_prefix_to_update_queue(state_machine->nat64, state_machine->proposed_prefix, nat64_prefix_action_remove);
1147 1.1 christos // Remove it from thread_monitor prefix database
1148 1.1 christos nat64_remove_prefix_from_thread_monitor(state_machine->nat64, state_machine->proposed_prefix);
1149 1.1 christos RELEASE_HERE(state_machine->proposed_prefix, nat64_prefix);
1150 1.1 christos state_machine->proposed_prefix = NULL;
1151 1.1 christos // Is there a different infra NAT64 prefix?
1152 1.1 christos if (event->prefix) {
1153 1.1 christos state_machine->proposed_prefix = nat64_prefix_dup(event->prefix);
1154 1.1 christos if (state_machine->proposed_prefix == NULL) {
1155 1.1 christos return nat64_infra_prefix_publisher_state_check;
1156 1.1 christos }
1157 1.1 christos return nat64_infra_prefix_publisher_state_publish;
1158 1.1 christos } else {
1159 1.1 christos INFO("no longer publishing infra prefix.");
1160 1.1 christos return nat64_infra_prefix_publisher_state_wait;
1161 1.1 christos }
1162 1.1 christos } else if (event->event_type == nat64_event_nat64_infra_prefix_publisher_routable_omr_prefix_went_away ||
1163 1.1 christos event->event_type == nat64_event_nat64_infra_prefix_publisher_shutdown)
1164 1.1 christos {
1165 1.1 christos // Routable OMR prefix is gone
1166 1.1 christos SEGMENTED_IPv6_ADDR_GEN_SRP(state_machine->proposed_prefix->prefix.s6_addr, nat64_prefix_buf);
1167 1.1 christos INFO("Routable OMR prefix is gone, unpublishing infra prefix " PRI_SEGMENTED_IPv6_ADDR_SRP,
1168 1.1 christos SEGMENTED_IPv6_ADDR_PARAM_SRP(state_machine->proposed_prefix->prefix.s6_addr, nat64_prefix_buf));
1169 1.1 christos nat64_add_prefix_to_update_queue(state_machine->nat64, state_machine->proposed_prefix, nat64_prefix_action_remove);
1170 1.1 christos // Remove it from thread_monitor prefix database
1171 1.1 christos nat64_remove_prefix_from_thread_monitor(state_machine->nat64, state_machine->proposed_prefix);
1172 1.1 christos RELEASE_HERE(state_machine->proposed_prefix, nat64_prefix);
1173 1.1 christos state_machine->proposed_prefix = NULL;
1174 1.1 christos INFO("no longer publishing infra prefix.");
1175 1.1 christos return nat64_infra_prefix_publisher_state_wait;
1176 1.1 christos } else if (event->event_type == nat64_event_nat64_infra_prefix_publisher_thread_prefix_changed) {
1177 1.1 christos nat64_prefix_t *thread_prefix;
1178 1.1 christos int num_infra_prefix = 0;
1179 1.1 christos for (thread_prefix = event->prefix; thread_prefix; thread_prefix = thread_prefix->next) {
1180 1.1 christos if (nat64_preference_has_higher_priority(thread_prefix->priority, nat64_preference_low)) {
1181 1.1 christos num_infra_prefix++;
1182 1.1 christos }
1183 1.1 christos }
1184 1.1 christos INFO("%d infra nat64 prefixes present on thread network", num_infra_prefix);
1185 1.1 christos // If more than 3 infra prefixes show on thread network, BR with highest rloc should withdraw
1186 1.1 christos if (num_infra_prefix > NAT64_INFRA_PREFIX_LIMIT) {
1187 1.1 christos int max_rloc = event->prefix->rloc;
1188 1.1 christos for (thread_prefix = event->prefix; thread_prefix; thread_prefix = thread_prefix->next) {
1189 1.1 christos if (thread_prefix->rloc > max_rloc) {
1190 1.1 christos max_rloc = thread_prefix->rloc;
1191 1.1 christos }
1192 1.1 christos }
1193 1.1 christos INFO("%d infra nat64 prefixes present on thread network with max_rloc[%d]", num_infra_prefix, max_rloc);
1194 1.1 christos if (max_rloc == state_machine->nat64->route_state->srp_server->rloc16) {
1195 1.1 christos SEGMENTED_IPv6_ADDR_GEN_SRP(state_machine->proposed_prefix->prefix.s6_addr, nat64_prefix_buf);
1196 1.1 christos INFO("BR has highest rloc, unpublishing infra prefix " PRI_SEGMENTED_IPv6_ADDR_SRP,
1197 1.1 christos SEGMENTED_IPv6_ADDR_PARAM_SRP(state_machine->proposed_prefix->prefix.s6_addr, nat64_prefix_buf));
1198 1.1 christos nat64_add_prefix_to_update_queue(state_machine->nat64, state_machine->proposed_prefix, nat64_prefix_action_remove);
1199 1.1 christos // Remove it from thread_monitor prefix database
1200 1.1 christos nat64_remove_prefix_from_thread_monitor(state_machine->nat64, state_machine->proposed_prefix);
1201 1.1 christos RELEASE_HERE(state_machine->proposed_prefix, nat64_prefix);
1202 1.1 christos state_machine->proposed_prefix = NULL;
1203 1.1 christos INFO("no longer publishing infra prefix.");
1204 1.1 christos return nat64_infra_prefix_publisher_state_wait;
1205 1.1 christos }
1206 1.1 christos }
1207 1.1 christos } else {
1208 1.1 christos NAT64_UNEXPECTED_EVENT(state_machine, event);
1209 1.1 christos }
1210 1.1 christos return nat64_infra_prefix_publisher_state_invalid;
1211 1.1 christos }
1212 1.1 christos
1213 1.1 christos #define INFRA_PUBLISHER_STATE_NAME_DECL(name) nat64_infra_prefix_publisher_state_##name, #name
1214 1.1 christos static nat64_infra_prefix_publisher_state_t
1215 1.1 christos nat64_infra_prefix_publisher_states[] = {
1216 1.1 christos { INFRA_PUBLISHER_STATE_NAME_DECL(invalid), NULL },
1217 1.1 christos { INFRA_PUBLISHER_STATE_NAME_DECL(init), nat64_infra_prefix_publisher_init_action },
1218 1.1 christos { INFRA_PUBLISHER_STATE_NAME_DECL(wait), nat64_infra_prefix_publisher_wait_action },
1219 1.1 christos { INFRA_PUBLISHER_STATE_NAME_DECL(ignore), nat64_infra_prefix_publisher_ignore_action },
1220 1.1 christos { INFRA_PUBLISHER_STATE_NAME_DECL(check), nat64_infra_prefix_publisher_check_action },
1221 1.1 christos { INFRA_PUBLISHER_STATE_NAME_DECL(publish), nat64_infra_prefix_publisher_publish_action },
1222 1.1 christos { INFRA_PUBLISHER_STATE_NAME_DECL(publishing), nat64_infra_prefix_publisher_publishing_action },
1223 1.1 christos };
1224 1.1 christos #define INFRA_PREFIX_PUBLISHER_NUM_STATES (sizeof(nat64_infra_prefix_publisher_states) / sizeof(nat64_infra_prefix_publisher_state_t))
1225 1.1 christos
1226 1.1 christos DECLARE_NAT64_STATE_GET(nat64_infra_prefix_publisher, INFRA_PREFIX_PUBLISHER);
1227 1.1 christos DECLARE_NAT64_NEXT_STATE(nat64_infra_prefix_publisher);
1228 1.1 christos
1229 1.1 christos // Infra prefix publisher event functions
1230 1.1 christos typedef struct {
1231 1.1 christos nat64_infra_prefix_publisher_event_type_t event_type;
1232 1.1 christos char *name;
1233 1.1 christos } nat64_infra_prefix_publisher_event_configuration_t;
1234 1.1 christos
1235 1.1 christos nat64_infra_prefix_publisher_event_configuration_t nat64_infra_prefix_publisher_event_configurations[] = {
1236 1.1 christos NAT64_EVENT_NAME_DECL(nat64_infra_prefix_publisher_invalid),
1237 1.1 christos NAT64_EVENT_NAME_DECL(nat64_infra_prefix_publisher_thread_prefix_changed),
1238 1.1 christos NAT64_EVENT_NAME_DECL(nat64_infra_prefix_publisher_infra_prefix_changed),
1239 1.1 christos NAT64_EVENT_NAME_DECL(nat64_infra_prefix_publisher_routable_omr_prefix_went_away),
1240 1.1 christos NAT64_EVENT_NAME_DECL(nat64_infra_prefix_publisher_routable_omr_prefix_showed_up),
1241 1.1 christos NAT64_EVENT_NAME_DECL(nat64_infra_prefix_publisher_shutdown),
1242 1.1 christos };
1243 1.1 christos #define INFRA_PREFIX_PUBLISHER_NUM_EVENT_TYPES (sizeof(nat64_infra_prefix_publisher_event_configurations) / sizeof(nat64_infra_prefix_publisher_event_configuration_t))
1244 1.1 christos
1245 1.1 christos DECLARE_NAT64_EVENT_CONFIGURATION_GET(nat64_infra_prefix_publisher_event, INFRA_PREFIX_PUBLISHER);
1246 1.1 christos DECLARE_NAT64_EVENT_INIT(nat64_infra_prefix_publisher_event);
1247 1.1 christos DECLARE_NAT64_EVENT_DELIVER(nat64_infra_prefix_publisher);
1248 1.1 christos
1249 1.1 christos void
1250 1.1 christos nat64_omr_route_update(nat64_t *NONNULL nat64, bool has_routable_omr_prefix)
1251 1.1 christos {
1252 1.1 christos if (!has_routable_omr_prefix && nat64->nat64_infra_prefix_publisher->routable_omr_prefix_present){
1253 1.1 christos nat64_infra_prefix_publisher_event_t event;
1254 1.1 christos
1255 1.1 christos nat64->nat64_infra_prefix_publisher->routable_omr_prefix_present = false;
1256 1.1 christos nat64_infra_prefix_publisher_event_init(&event, nat64_event_nat64_infra_prefix_publisher_routable_omr_prefix_went_away);
1257 1.1 christos NAT64_EVENT_ANNOUNCE(nat64->nat64_infra_prefix_publisher, event);
1258 1.1 christos nat64_infra_prefix_publisher_event_deliver(nat64->nat64_infra_prefix_publisher, &event);
1259 1.1 christos } else if (has_routable_omr_prefix && !nat64->nat64_infra_prefix_publisher->routable_omr_prefix_present){
1260 1.1 christos nat64_infra_prefix_publisher_event_t event;
1261 1.1 christos
1262 1.1 christos nat64->nat64_infra_prefix_publisher->routable_omr_prefix_present = true;
1263 1.1 christos nat64_infra_prefix_publisher_event_init(&event, nat64_event_nat64_infra_prefix_publisher_routable_omr_prefix_showed_up);
1264 1.1 christos NAT64_EVENT_ANNOUNCE(nat64->nat64_infra_prefix_publisher, event);
1265 1.1 christos nat64_infra_prefix_publisher_event_deliver(nat64->nat64_infra_prefix_publisher, &event);
1266 1.1 christos }
1267 1.1 christos }
1268 1.1 christos // Infrastructure nat64 prefix publisher state machine end
1269 1.1 christos
1270 1.1 christos
1271 1.1 christos // BR nat64 prefix publisher state machine start
1272 1.1 christos typedef nat64_br_prefix_publisher_state_type_t (*nat64_br_prefix_publisher_action_t)(nat64_br_prefix_publisher_t *NONNULL sm, nat64_br_prefix_publisher_event_t *NULLABLE event);
1273 1.1 christos
1274 1.1 christos typedef struct {
1275 1.1 christos nat64_br_prefix_publisher_state_type_t state;
1276 1.1 christos char *name;
1277 1.1 christos nat64_br_prefix_publisher_action_t action;
1278 1.1 christos } nat64_br_prefix_publisher_state_t;
1279 1.1 christos
1280 1.1 christos static nat64_br_prefix_publisher_state_type_t
1281 1.1 christos nat64_br_prefix_publisher_init_action(nat64_br_prefix_publisher_t *state_machine, nat64_br_prefix_publisher_event_t * event)
1282 1.1 christos {
1283 1.1 christos NAT64_STATE_ANNOUNCE(state_machine, event);
1284 1.1 christos // Setup BR nat64 prefix
1285 1.1 christos state_machine->br_prefix = nat64_prefix_create(&state_machine->nat64->route_state->srp_server->ula_prefix, NAT64_PREFIX_SLASH_96_BYTES, nat64_preference_low, state_machine->nat64->route_state->srp_server->rloc16);
1286 1.1 christos if (state_machine->br_prefix == NULL) {
1287 1.1 christos ERROR("no memory when create br prefix");
1288 1.1 christos return nat64_br_prefix_publisher_state_invalid;
1289 1.1 christos }
1290 1.1 christos // Add 0xFFFF to make it different from OMR prefix
1291 1.1 christos memset(&state_machine->br_prefix->prefix.s6_addr[6], 0xFF, 2);
1292 1.1 christos SEGMENTED_IPv6_ADDR_GEN_SRP(state_machine->br_prefix->prefix.s6_addr, nat64_prefix_buf);
1293 1.1 christos INFO("set br prefix to " PRI_SEGMENTED_IPv6_ADDR_SRP,
1294 1.1 christos SEGMENTED_IPv6_ADDR_PARAM_SRP(state_machine->br_prefix->prefix.s6_addr, nat64_prefix_buf));
1295 1.1 christos // Switch to next state.
1296 1.1 christos return nat64_br_prefix_publisher_state_start_timer;
1297 1.1 christos }
1298 1.1 christos
1299 1.1 christos static void
1300 1.1 christos nat64_br_prefix_publisher_context_release(void *context)
1301 1.1 christos {
1302 1.1 christos nat64_br_prefix_publisher_t *state_machine = context;
1303 1.1 christos RELEASE_HERE(state_machine, nat64_br_prefix_publisher);
1304 1.1 christos }
1305 1.1 christos
1306 1.1 christos static void
1307 1.1 christos nat64_br_prefix_publisher_wakeup(void *context)
1308 1.1 christos {
1309 1.1 christos nat64_br_prefix_publisher_t *state_machine = context;
1310 1.1 christos nat64_br_prefix_publisher_event_t out_event;
1311 1.1 christos
1312 1.1 christos state_machine->wait_finished = true;
1313 1.1 christos nat64_br_prefix_publisher_event_init(&out_event, nat64_event_nat64_br_prefix_publisher_okay_to_publish);
1314 1.1 christos NAT64_EVENT_ANNOUNCE(state_machine, out_event);
1315 1.1 christos nat64_br_prefix_publisher_event_deliver(state_machine, &out_event);
1316 1.1 christos }
1317 1.1 christos
1318 1.1 christos static nat64_br_prefix_publisher_state_type_t
1319 1.1 christos nat64_br_prefix_publisher_start_timer_action(nat64_br_prefix_publisher_t *state_machine, nat64_br_prefix_publisher_event_t * event)
1320 1.1 christos {
1321 1.1 christos NAT64_STATE_ANNOUNCE(state_machine, event);
1322 1.1 christos if (state_machine->timer == NULL) {
1323 1.1 christos state_machine->timer = ioloop_wakeup_create();
1324 1.1 christos if (state_machine->timer == NULL) {
1325 1.1 christos ERROR("no memory when create timer");
1326 1.1 christos return nat64_br_prefix_publisher_state_invalid;
1327 1.1 christos }
1328 1.1 christos RETAIN_HERE(state_machine, nat64_br_prefix_publisher);
1329 1.1 christos // wait rand(10,30) seconds, will start after thread monitor is settled
1330 1.1 christos ioloop_add_wake_event(state_machine->timer, state_machine, nat64_br_prefix_publisher_wakeup, nat64_br_prefix_publisher_context_release,
1331 1.1 christos NAT64_THREAD_PREFIX_SETTLING_TIME * IOLOOP_SECOND + srp_random16() % (NAT64_BR_PREFIX_PUBLISHER_WAIT_TIME * IOLOOP_SECOND));
1332 1.1 christos state_machine->wait_finished = false;
1333 1.1 christos } else {
1334 1.1 christos INFO("thread prefix monitor timer already started");
1335 1.1 christos }
1336 1.1 christos // Switch to next state.
1337 1.1 christos return nat64_br_prefix_publisher_state_wait_for_anything;
1338 1.1 christos }
1339 1.1 christos
1340 1.1 christos static nat64_br_prefix_publisher_state_type_t
1341 1.1 christos nat64_br_prefix_publisher_wait_for_anything_action(nat64_br_prefix_publisher_t *state_machine, nat64_br_prefix_publisher_event_t *event)
1342 1.1 christos {
1343 1.1 christos NAT64_STATE_ANNOUNCE(state_machine, event);
1344 1.1 christos if (event == NULL) {
1345 1.1 christos return nat64_br_prefix_publisher_state_invalid;
1346 1.1 christos } else if (event->event_type == nat64_event_nat64_br_prefix_publisher_ipv4_default_route_showed_up) {
1347 1.1 christos if (state_machine->nat64->thread_monitor->thread_nat64_prefixes == NULL
1348 1.1 christos && state_machine->nat64->nat64_infra_prefix_publisher->proposed_prefix == NULL
1349 1.1 christos && state_machine->wait_finished) {
1350 1.1 christos return nat64_br_prefix_publisher_state_publish;
1351 1.1 christos }
1352 1.1 christos } else if (event->event_type == nat64_event_nat64_br_prefix_publisher_thread_prefix_changed) {
1353 1.1 christos if (event->prefix == NULL
1354 1.1 christos && state_machine->nat64->nat64_infra_prefix_publisher->proposed_prefix == NULL
1355 1.1 christos && state_machine->wait_finished
1356 1.1 christos && state_machine->nat64->ipv4_monitor->has_ipv4_default_route) {
1357 1.1 christos return nat64_br_prefix_publisher_state_publish;
1358 1.1 christos }
1359 1.1 christos } else if (event->event_type == nat64_event_nat64_br_prefix_publisher_okay_to_publish) {
1360 1.1 christos if (state_machine->nat64->thread_monitor->thread_nat64_prefixes == NULL
1361 1.1 christos && state_machine->nat64->nat64_infra_prefix_publisher->proposed_prefix == NULL
1362 1.1 christos && state_machine->nat64->ipv4_monitor->has_ipv4_default_route) {
1363 1.1 christos return nat64_br_prefix_publisher_state_publish;
1364 1.1 christos }
1365 1.1 christos } else if (event->event_type == nat64_event_nat64_br_prefix_publisher_infra_prefix_changed) {
1366 1.1 christos if (event->prefix == NULL
1367 1.1 christos && state_machine->nat64->thread_monitor->thread_nat64_prefixes == NULL
1368 1.1 christos && state_machine->wait_finished
1369 1.1 christos && state_machine->nat64->ipv4_monitor->has_ipv4_default_route) {
1370 1.1 christos return nat64_br_prefix_publisher_state_publish;
1371 1.1 christos }
1372 1.1 christos } else {
1373 1.1 christos NAT64_UNEXPECTED_EVENT(state_machine, event);
1374 1.1 christos }
1375 1.1 christos return nat64_br_prefix_publisher_state_invalid;
1376 1.1 christos }
1377 1.1 christos
1378 1.1 christos static nat64_br_prefix_publisher_state_type_t
1379 1.1 christos nat64_br_prefix_publisher_publish_action(nat64_br_prefix_publisher_t *state_machine, nat64_br_prefix_publisher_event_t *event)
1380 1.1 christos {
1381 1.1 christos NAT64_STATE_ANNOUNCE(state_machine, event);
1382 1.1 christos // Enable NAT64 translation
1383 1.1 christos INFO("starting NAT64 translation on BR");
1384 1.1 christos nat64_start_translation(dispatch_get_main_queue());
1385 1.1 christos SEGMENTED_IPv6_ADDR_GEN_SRP(state_machine->br_prefix->prefix.s6_addr, nat64_prefix_buf);
1386 1.1 christos INFO("publishing br prefix " PRI_SEGMENTED_IPv6_ADDR_SRP,
1387 1.1 christos SEGMENTED_IPv6_ADDR_PARAM_SRP(state_machine->br_prefix->prefix.s6_addr, nat64_prefix_buf));
1388 1.1 christos nat64_add_prefix_to_update_queue(state_machine->nat64, state_machine->br_prefix,
1389 1.1 christos nat64_prefix_action_add);
1390 1.1 christos return nat64_br_prefix_publisher_state_publishing;
1391 1.1 christos }
1392 1.1 christos
1393 1.1 christos static void
1394 1.1 christos nat64_unpublish_br_prefix(nat64_br_prefix_publisher_t *state_machine)
1395 1.1 christos {
1396 1.1 christos SEGMENTED_IPv6_ADDR_GEN_SRP(state_machine->br_prefix->prefix.s6_addr, nat64_prefix_buf);
1397 1.1 christos INFO("unpublishing br prefix " PRI_SEGMENTED_IPv6_ADDR_SRP,
1398 1.1 christos SEGMENTED_IPv6_ADDR_PARAM_SRP(state_machine->br_prefix->prefix.s6_addr, nat64_prefix_buf));
1399 1.1 christos nat64_add_prefix_to_update_queue(state_machine->nat64, state_machine->br_prefix,
1400 1.1 christos nat64_prefix_action_remove);
1401 1.1 christos // Remove it from thread_monitor prefix database
1402 1.1 christos nat64_remove_prefix_from_thread_monitor(state_machine->nat64, state_machine->br_prefix);
1403 1.1 christos INFO("stopping NAT64 translation on BR");
1404 1.1 christos nat64_stop_translation();
1405 1.1 christos }
1406 1.1 christos
1407 1.1 christos static nat64_br_prefix_publisher_state_type_t
1408 1.1 christos nat64_br_prefix_publisher_publishing_action(nat64_br_prefix_publisher_t *state_machine, nat64_br_prefix_publisher_event_t *event)
1409 1.1 christos {
1410 1.1 christos NAT64_STATE_ANNOUNCE(state_machine, event);
1411 1.1 christos if (event == NULL) {
1412 1.1 christos return nat64_br_prefix_publisher_state_invalid;
1413 1.1 christos } else if (event->event_type == nat64_event_nat64_br_prefix_publisher_thread_prefix_changed) {
1414 1.1 christos nat64_prefix_t *thread_prefix;
1415 1.1 christos for (thread_prefix = event->prefix; thread_prefix; thread_prefix = thread_prefix->next) {
1416 1.1 christos if (nat64_preference_has_higher_priority(thread_prefix->priority, nat64_preference_low)) {
1417 1.1 christos // The thread prefix has higher preference
1418 1.1 christos nat64_unpublish_br_prefix(state_machine);
1419 1.1 christos return nat64_br_prefix_publisher_state_wait_for_anything;
1420 1.1 christos } else if (thread_prefix->priority == nat64_preference_low) {
1421 1.1 christos if (in6addr_compare(&state_machine->br_prefix->prefix, &thread_prefix->prefix) > 0) {
1422 1.1 christos nat64_unpublish_br_prefix(state_machine);
1423 1.1 christos return nat64_br_prefix_publisher_state_wait_for_anything;
1424 1.1 christos }
1425 1.1 christos }
1426 1.1 christos }
1427 1.1 christos } else if (event->event_type == nat64_event_nat64_br_prefix_publisher_ipv4_default_route_went_away ||
1428 1.1 christos event->event_type == nat64_event_nat64_br_prefix_publisher_shutdown)
1429 1.1 christos {
1430 1.1 christos nat64_unpublish_br_prefix(state_machine);
1431 1.1 christos return nat64_br_prefix_publisher_state_wait_for_anything;
1432 1.1 christos } else if (event->event_type == nat64_event_nat64_br_prefix_publisher_infra_prefix_changed) {
1433 1.1 christos // Only unpublish br prefix if there is infra prefix and routable OMR prefix
1434 1.1 christos if (event->prefix && nat64_thread_has_routable_prefix(state_machine->nat64->route_state)) {
1435 1.1 christos nat64_unpublish_br_prefix(state_machine);
1436 1.1 christos return nat64_br_prefix_publisher_state_wait_for_anything;
1437 1.1 christos }
1438 1.1 christos } else {
1439 1.1 christos NAT64_UNEXPECTED_EVENT(state_machine, event);
1440 1.1 christos }
1441 1.1 christos return nat64_br_prefix_publisher_state_invalid;
1442 1.1 christos }
1443 1.1 christos
1444 1.1 christos #define BR_PUBLISHER_STATE_NAME_DECL(name) nat64_br_prefix_publisher_state_##name, #name
1445 1.1 christos static nat64_br_prefix_publisher_state_t
1446 1.1 christos nat64_br_prefix_publisher_states[] = {
1447 1.1 christos { BR_PUBLISHER_STATE_NAME_DECL(invalid), NULL },
1448 1.1 christos { BR_PUBLISHER_STATE_NAME_DECL(init), nat64_br_prefix_publisher_init_action },
1449 1.1 christos { BR_PUBLISHER_STATE_NAME_DECL(start_timer), nat64_br_prefix_publisher_start_timer_action },
1450 1.1 christos { BR_PUBLISHER_STATE_NAME_DECL(wait_for_anything), nat64_br_prefix_publisher_wait_for_anything_action },
1451 1.1 christos { BR_PUBLISHER_STATE_NAME_DECL(publish), nat64_br_prefix_publisher_publish_action },
1452 1.1 christos { BR_PUBLISHER_STATE_NAME_DECL(publishing), nat64_br_prefix_publisher_publishing_action },
1453 1.1 christos };
1454 1.1 christos #define BR_PREFIX_PUBLISHER_NUM_STATES (sizeof(nat64_br_prefix_publisher_states) / sizeof(nat64_br_prefix_publisher_state_t))
1455 1.1 christos
1456 1.1 christos DECLARE_NAT64_STATE_GET(nat64_br_prefix_publisher, BR_PREFIX_PUBLISHER);
1457 1.1 christos DECLARE_NAT64_NEXT_STATE(nat64_br_prefix_publisher);
1458 1.1 christos
1459 1.1 christos // BR prefix publisher event functions
1460 1.1 christos typedef struct {
1461 1.1 christos nat64_br_prefix_publisher_event_type_t event_type;
1462 1.1 christos char *name;
1463 1.1 christos } nat64_br_prefix_publisher_event_configuration_t;
1464 1.1 christos
1465 1.1 christos nat64_br_prefix_publisher_event_configuration_t nat64_br_prefix_publisher_event_configurations[] = {
1466 1.1 christos NAT64_EVENT_NAME_DECL(nat64_br_prefix_publisher_invalid),
1467 1.1 christos NAT64_EVENT_NAME_DECL(nat64_br_prefix_publisher_okay_to_publish),
1468 1.1 christos NAT64_EVENT_NAME_DECL(nat64_br_prefix_publisher_ipv4_default_route_showed_up),
1469 1.1 christos NAT64_EVENT_NAME_DECL(nat64_br_prefix_publisher_ipv4_default_route_went_away),
1470 1.1 christos NAT64_EVENT_NAME_DECL(nat64_br_prefix_publisher_thread_prefix_changed),
1471 1.1 christos NAT64_EVENT_NAME_DECL(nat64_br_prefix_publisher_infra_prefix_changed),
1472 1.1 christos NAT64_EVENT_NAME_DECL(nat64_br_prefix_publisher_shutdown),
1473 1.1 christos };
1474 1.1 christos #define BR_PREFIX_PUBLISHER_NUM_EVENT_TYPES (sizeof(nat64_br_prefix_publisher_event_configurations) / sizeof(nat64_br_prefix_publisher_event_configuration_t))
1475 1.1 christos
1476 1.1 christos DECLARE_NAT64_EVENT_CONFIGURATION_GET(nat64_br_prefix_publisher_event, BR_PREFIX_PUBLISHER);
1477 1.1 christos DECLARE_NAT64_EVENT_INIT(nat64_br_prefix_publisher_event);
1478 1.1 christos DECLARE_NAT64_EVENT_DELIVER(nat64_br_prefix_publisher);
1479 1.1 christos
1480 1.1 christos // BR nat64 prefix publisher state machine end
1481 1.1 christos
1482 1.1 christos void
1483 1.1 christos nat64_init(route_state_t *NONNULL route_state)
1484 1.1 christos {
1485 1.1 christos INFO("nat64_init");
1486 1.1 christos // Start state machines
1487 1.1 christos nat64_ipv4_default_route_monitor_next_state(route_state->nat64->ipv4_monitor, nat64_ipv4_default_route_monitor_state_init);
1488 1.1 christos nat64_infra_prefix_monitor_next_state(route_state->nat64->infra_monitor, nat64_infra_prefix_monitor_state_init);
1489 1.1 christos nat64_thread_prefix_monitor_next_state(route_state->nat64->thread_monitor, nat64_thread_prefix_monitor_state_init);
1490 1.1 christos nat64_infra_prefix_publisher_next_state(route_state->nat64->nat64_infra_prefix_publisher, nat64_infra_prefix_publisher_state_init);
1491 1.1 christos nat64_br_prefix_publisher_next_state(route_state->nat64->nat64_br_prefix_publisher, nat64_br_prefix_publisher_state_init);
1492 1.1 christos }
1493 1.1 christos
1494 1.1 christos void
1495 1.1 christos nat64_stop(route_state_t *NONNULL route_state)
1496 1.1 christos {
1497 1.1 christos if (route_state->nat64) {
1498 1.1 christos INFO("stopping nat64.");
1499 1.1 christos nat64_cancel(route_state->nat64);
1500 1.1 christos RELEASE_HERE(route_state->nat64, nat64);
1501 1.1 christos route_state->nat64 = NULL;
1502 1.1 christos }
1503 1.1 christos }
1504 1.1 christos
1505 1.1 christos void
1506 1.1 christos nat64_start(route_state_t *NONNULL route_state)
1507 1.1 christos {
1508 1.1 christos route_state->nat64 = nat64_create(route_state);
1509 1.1 christos if (route_state->nat64 == NULL) {
1510 1.1 christos ERROR("nat64 create failed");
1511 1.1 christos return;
1512 1.1 christos }
1513 1.1 christos nat64_init(route_state);
1514 1.1 christos }
1515 1.1 christos
1516 1.1 christos static void
1517 1.1 christos nat64_add_route_callback(void *context, cti_status_t status)
1518 1.1 christos {
1519 1.1 christos (void)context;
1520 1.1 christos INFO("%d", status);
1521 1.1 christos }
1522 1.1 christos
1523 1.1 christos void
1524 1.1 christos nat64_add_prefix(route_state_t *route_state, const uint8_t *const data, offmesh_route_preference_t route_pref)
1525 1.1 christos {
1526 1.1 christos SEGMENTED_IPv6_ADDR_GEN_SRP(data, nat64_prefix_buf);
1527 1.1 christos INFO("nat64_add_prefix(" PRI_SEGMENTED_IPv6_ADDR_SRP ")",
1528 1.1 christos SEGMENTED_IPv6_ADDR_PARAM_SRP(data, nat64_prefix_buf));
1529 1.1 christos int status = cti_add_route(route_state->srp_server, route_state, nat64_add_route_callback, NULL,
1530 1.1 christos (struct in6_addr *)data, NAT64_PREFIX_SLASH_96_BYTES * 8,
1531 1.1 christos route_pref, 0, true, true);
1532 1.1 christos if (status != kCTIStatus_NoError) {
1533 1.1 christos ERROR("Unable to add nat64 prefix.");
1534 1.1 christos }
1535 1.1 christos }
1536 1.1 christos
1537 1.1 christos static void
1538 1.1 christos nat64_remove_route_callback(void *context, cti_status_t status)
1539 1.1 christos {
1540 1.1 christos (void)context;
1541 1.1 christos INFO("%d", status);
1542 1.1 christos }
1543 1.1 christos
1544 1.1 christos void
1545 1.1 christos nat64_remove_prefix(route_state_t *route_state, const uint8_t *const data)
1546 1.1 christos {
1547 1.1 christos SEGMENTED_IPv6_ADDR_GEN_SRP(data, nat64_prefix_buf);
1548 1.1 christos INFO("nat64_remove_prefix(" PRI_SEGMENTED_IPv6_ADDR_SRP ")",
1549 1.1 christos SEGMENTED_IPv6_ADDR_PARAM_SRP(data, nat64_prefix_buf));
1550 1.1 christos int status = cti_remove_route(route_state->srp_server, route_state, nat64_remove_route_callback, NULL,
1551 1.1 christos (struct in6_addr *)data, NAT64_PREFIX_SLASH_96_BYTES * 8, 0);
1552 1.1 christos if (status != kCTIStatus_NoError) {
1553 1.1 christos ERROR("Unable to remove nat64 prefix.");
1554 1.1 christos }
1555 1.1 christos }
1556 1.1 christos
1557 1.1 christos static offmesh_route_preference_t
1558 1.1 christos nat64_pref_to_route_pref(nat64_preference nat64_pref)
1559 1.1 christos {
1560 1.1 christos if (nat64_pref == nat64_preference_low) {
1561 1.1 christos return offmesh_route_preference_low;
1562 1.1 christos } else if (nat64_pref == nat64_preference_high) {
1563 1.1 christos return offmesh_route_preference_high;
1564 1.1 christos } else if (nat64_pref == nat64_preference_medium) {
1565 1.1 christos return offmesh_route_preference_medium;
1566 1.1 christos } else {
1567 1.1 christos ERROR("Unknown nat64 prefix preference %d", nat64_pref);
1568 1.1 christos return offmesh_route_preference_low;
1569 1.1 christos }
1570 1.1 christos }
1571 1.1 christos
1572 1.1 christos static void
1573 1.1 christos nat64_prefix_update_callback(void *context, cti_status_t status)
1574 1.1 christos {
1575 1.1 christos nat64_t *nat64 = context;
1576 1.1 christos nat64_prefix_t *prefix = nat64->update_queue;
1577 1.1 christos INFO("status %d", status);
1578 1.1 christos if (prefix == NULL) {
1579 1.1 christos ERROR("update seems to have disappeared");
1580 1.1 christos return;
1581 1.1 christos }
1582 1.1 christos SEGMENTED_IPv6_ADDR_GEN_SRP(&prefix->prefix, prefix_buf);
1583 1.1 christos INFO(PRI_SEGMENTED_IPv6_ADDR_SRP " was " PUB_S_SRP,
1584 1.1 christos SEGMENTED_IPv6_ADDR_PARAM_SRP(&prefix->prefix, prefix_buf),
1585 1.1 christos prefix->action == nat64_prefix_action_add ? "added" : "removed");
1586 1.1 christos // The pending flag was set to true in nat64_prefix_start_next_update(), meaning that
1587 1.1 christos // we sent the request to threadradiod, but it's not finished yet, so the status is pending.
1588 1.1 christos // when this callback function is called, the status is not pending anymore.
1589 1.1 christos if (prefix->pending) {
1590 1.1 christos prefix->pending = false;
1591 1.1 christos nat64->update_queue = prefix->next;
1592 1.1 christos prefix->next = NULL;
1593 1.1 christos RELEASE_HERE(prefix, nat64_prefix);
1594 1.1 christos }
1595 1.1 christos // Start next update
1596 1.1 christos if (nat64->update_queue != NULL) {
1597 1.1 christos nat64_prefix_start_next_update(nat64);
1598 1.1 christos } else {
1599 1.1 christos // The update queue holds a reference to nat64 when there is something on the queue.
1600 1.1 christos // Release here if there is nothing on the queue.
1601 1.1 christos RELEASE_HERE(nat64, nat64);
1602 1.1 christos }
1603 1.1 christos }
1604 1.1 christos
1605 1.1 christos static void
1606 1.1 christos nat64_prefix_start_next_update(nat64_t *nat64)
1607 1.1 christos {
1608 1.1 christos cti_status_t status;
1609 1.1 christos nat64_prefix_t *prefix = nat64->update_queue;
1610 1.1 christos if (prefix == NULL) {
1611 1.1 christos ERROR("nat64_prefix_start_next_update called with no update");
1612 1.1 christos return;
1613 1.1 christos }
1614 1.1 christos route_state_t *route_state = nat64->route_state;
1615 1.1 christos srp_server_t *server_state = route_state->srp_server;
1616 1.1 christos
1617 1.1 christos SEGMENTED_IPv6_ADDR_GEN_SRP(&prefix->prefix, prefix_buf);
1618 1.1 christos if (prefix->action == nat64_prefix_action_remove) {
1619 1.1 christos INFO("removing: " PRI_SEGMENTED_IPv6_ADDR_SRP ,
1620 1.1 christos SEGMENTED_IPv6_ADDR_PARAM_SRP(&prefix->prefix, prefix_buf));
1621 1.1 christos status = cti_remove_route(server_state, nat64, nat64_prefix_update_callback, NULL,
1622 1.1 christos &prefix->prefix, NAT64_PREFIX_SLASH_96_BYTES * 8, 0);
1623 1.1 christos } else if (prefix->action == nat64_prefix_action_add){
1624 1.1 christos INFO("adding: " PRI_SEGMENTED_IPv6_ADDR_SRP ,
1625 1.1 christos SEGMENTED_IPv6_ADDR_PARAM_SRP(&prefix->prefix, prefix_buf));
1626 1.1 christos status = cti_add_route(server_state, nat64, nat64_prefix_update_callback, NULL,
1627 1.1 christos &prefix->prefix, NAT64_PREFIX_SLASH_96_BYTES * 8,
1628 1.1 christos nat64_pref_to_route_pref(prefix->priority), 0, true, true);
1629 1.1 christos } else {
1630 1.1 christos ERROR("updating: " PRI_SEGMENTED_IPv6_ADDR_SRP " with action %d",
1631 1.1 christos SEGMENTED_IPv6_ADDR_PARAM_SRP(&prefix->prefix, prefix_buf), prefix->action);
1632 1.1 christos nat64->update_queue = prefix->next;
1633 1.1 christos prefix->next = NULL;
1634 1.1 christos RELEASE_HERE(prefix, nat64_prefix);
1635 1.1 christos return;
1636 1.1 christos }
1637 1.1 christos if (status != kCTIStatus_NoError) {
1638 1.1 christos ERROR("route update failed: %d", status);
1639 1.1 christos } else {
1640 1.1 christos prefix->pending = true;
1641 1.1 christos }
1642 1.1 christos }
1643 1.1 christos
1644 1.1 christos static void
1645 1.1 christos nat64_add_prefix_to_update_queue(nat64_t *nat64, nat64_prefix_t *prefix, nat64_prefix_action action)
1646 1.1 christos {
1647 1.1 christos nat64_prefix_t **ppref, *old_queue = nat64->update_queue;
1648 1.1 christos // Find the prefix on the queue, or find the end of the queue.
1649 1.1 christos for (ppref = &nat64->update_queue; *ppref != NULL && *ppref != prefix; ppref = &(*ppref)->next);
1650 1.1 christos // Not on the queue
1651 1.1 christos if (*ppref == NULL) {
1652 1.1 christos nat64_prefix_t * new_prefix = nat64_prefix_dup(prefix);
1653 1.1 christos if (new_prefix == NULL) {
1654 1.1 christos ERROR("no memory for nat64 prefix.");
1655 1.1 christos return;
1656 1.1 christos }
1657 1.1 christos new_prefix->action = action;
1658 1.1 christos // The pending flag will be set to true in nat64_prefix_start_next_update()
1659 1.1 christos // when we send the request to threadradiod.
1660 1.1 christos new_prefix->pending = false;
1661 1.1 christos *ppref = new_prefix;
1662 1.1 christos // Turns out we added it to the beginning of the queue.
1663 1.1 christos if (nat64->update_queue == new_prefix) {
1664 1.1 christos nat64_prefix_start_next_update(nat64);
1665 1.1 christos }
1666 1.1 christos goto out;
1667 1.1 christos }
1668 1.1 christos // We have started to update the prefix, but haven't gotten the callback yet. Since we have put the prefix
1669 1.1 christos // back on the update queue, and it's at the beginning, mark it not pending so that when we get the callback
1670 1.1 christos // from the update function, we update this route again rather than going on to the next.
1671 1.1 christos if (prefix == nat64->update_queue) {
1672 1.1 christos prefix->pending = false;
1673 1.1 christos }
1674 1.1 christos out:
1675 1.1 christos // As long as there is anything in the queue, the queue needs to hold a reference to nat64,
1676 1.1 christos // so that if it's canceled and released, we finish running the queue before stopping.
1677 1.1 christos if (old_queue == NULL && nat64->update_queue != NULL) {
1678 1.1 christos RETAIN_HERE(nat64, nat64);
1679 1.1 christos }
1680 1.1 christos }
1681 1.1 christos
1682 1.1 christos // Check stale prefix on thread network.
1683 1.1 christos // For example, prefix that belongs to current BR, but current BR is not in publishing state, this can happen when srp-mdns-proxy daemon restarted.
1684 1.1 christos // Remove such prefix from thread network.
1685 1.1 christos static void
1686 1.1 christos nat64_check_stale_prefix(route_state_t *route_state, const cti_route_vec_t *const routes)
1687 1.1 christos {
1688 1.1 christos size_t i;
1689 1.1 christos for (i = 0; i < routes->num; i++) {
1690 1.1 christos cti_route_t *route = routes->routes[i];
1691 1.1 christos // This is nat64 prefix published by us
1692 1.1 christos if (route->nat64 && route->origin == offmesh_route_origin_ncp
1693 1.1 christos && route->rloc == route_state->srp_server->rloc16) {
1694 1.1 christos // br generated nat64 prefix
1695 1.1 christos if (route->preference == offmesh_route_preference_low) {
1696 1.1 christos nat64_prefix_t *prefix = route_state->nat64->nat64_br_prefix_publisher->br_prefix;
1697 1.1 christos // If we are not publishing or
1698 1.1 christos // we are publishing but the prefix is different, this can happen when ula changed
1699 1.1 christos if ((route_state->nat64->nat64_br_prefix_publisher->state != nat64_br_prefix_publisher_state_publishing) ||
1700 1.1 christos (prefix && in6prefix_compare(&prefix->prefix, &route->prefix, NAT64_PREFIX_SLASH_96_BYTES))) {
1701 1.1 christos nat64_prefix_t *tmp = nat64_prefix_create(&route->prefix, NAT64_PREFIX_SLASH_96_BYTES,
1702 1.1 christos route_pref_to_nat64_pref(route->preference), route->rloc);
1703 1.1 christos SEGMENTED_IPv6_ADDR_GEN_SRP(tmp->prefix.s6_addr, nat64_prefix_buf);
1704 1.1 christos INFO("stale br prefix " PRI_SEGMENTED_IPv6_ADDR_SRP " removing",
1705 1.1 christos SEGMENTED_IPv6_ADDR_PARAM_SRP(tmp->prefix.s6_addr, nat64_prefix_buf));
1706 1.1 christos nat64_add_prefix_to_update_queue(route_state->nat64, tmp, nat64_prefix_action_remove);
1707 1.1 christos RELEASE_HERE(tmp, nat64_prefix);
1708 1.1 christos }
1709 1.1 christos // prefix from infrastructure
1710 1.1 christos } else if (route->preference == offmesh_route_preference_medium) {
1711 1.1 christos nat64_prefix_t *prefix = route_state->nat64->nat64_infra_prefix_publisher->proposed_prefix;
1712 1.1 christos // If we are not publishing or
1713 1.1 christos // we are publishing but the prefix is different, this can happen when infra prefix changed
1714 1.1 christos if ((route_state->nat64->nat64_infra_prefix_publisher->state != nat64_infra_prefix_publisher_state_publishing) ||
1715 1.1 christos (prefix && in6prefix_compare(&prefix->prefix, &route->prefix, NAT64_PREFIX_SLASH_96_BYTES))) {
1716 1.1 christos nat64_prefix_t *tmp = nat64_prefix_create(&route->prefix, NAT64_PREFIX_SLASH_96_BYTES,
1717 1.1 christos route_pref_to_nat64_pref(route->preference), route->rloc);
1718 1.1 christos SEGMENTED_IPv6_ADDR_GEN_SRP(tmp->prefix.s6_addr, nat64_prefix_buf);
1719 1.1 christos INFO("stale infra prefix " PRI_SEGMENTED_IPv6_ADDR_SRP " removing",
1720 1.1 christos SEGMENTED_IPv6_ADDR_PARAM_SRP(tmp->prefix.s6_addr, nat64_prefix_buf));
1721 1.1 christos nat64_add_prefix_to_update_queue(route_state->nat64, tmp, nat64_prefix_action_remove);
1722 1.1 christos RELEASE_HERE(tmp, nat64_prefix);
1723 1.1 christos }
1724 1.1 christos }
1725 1.1 christos }
1726 1.1 christos }
1727 1.1 christos }
1728 1.1 christos
1729 1.1 christos void
1730 1.1 christos nat64_offmesh_route_list_callback(route_state_t *route_state, cti_route_vec_t *routes, cti_status_t status)
1731 1.1 christos {
1732 1.1 christos if (status != kCTIStatus_NoError) {
1733 1.1 christos ERROR("status %d", status);
1734 1.1 christos } else {
1735 1.1 christos INFO("got %zu offmesh routes", routes->num);
1736 1.1 christos nat64_check_stale_prefix(route_state, routes);
1737 1.1 christos nat64_thread_prefix_monitor_t *state_machine = route_state->nat64->thread_monitor;
1738 1.1 christos nat64_thread_prefix_monitor_event_t out_event;
1739 1.1 christos nat64_thread_prefix_monitor_event_init(&out_event, nat64_event_thread_prefix_update);
1740 1.1 christos out_event.routes = routes;
1741 1.1 christos NAT64_EVENT_ANNOUNCE(state_machine, out_event);
1742 1.1 christos nat64_thread_prefix_monitor_event_deliver(state_machine, &out_event);
1743 1.1 christos }
1744 1.1 christos }
1745 1.1 christos
1746 1.1 christos void
1747 1.1 christos nat64_thread_shutdown(route_state_t *route_state)
1748 1.1 christos {
1749 1.1 christos nat64_t *nat64 = route_state->nat64;
1750 1.1 christos if (nat64->nat64_infra_prefix_publisher != NULL) {
1751 1.1 christos nat64_infra_prefix_publisher_event_t infra_event;
1752 1.1 christos nat64_infra_prefix_publisher_event_init(&infra_event, nat64_event_nat64_infra_prefix_publisher_shutdown);
1753 1.1 christos nat64_infra_prefix_publisher_event_deliver(nat64->nat64_infra_prefix_publisher, &infra_event);
1754 1.1 christos }
1755 1.1 christos if (nat64->nat64_br_prefix_publisher != NULL) {
1756 1.1 christos nat64_br_prefix_publisher_event_t br_event;
1757 1.1 christos nat64_br_prefix_publisher_event_init(&br_event, nat64_event_nat64_br_prefix_publisher_shutdown);
1758 1.1 christos nat64_br_prefix_publisher_event_deliver(nat64->nat64_br_prefix_publisher, &br_event);
1759 1.1 christos }
1760 1.1 christos }
1761 1.1 christos #endif
1762 1.1 christos
1763 1.1 christos // Local Variables:
1764 1.1 christos // mode: C
1765 1.1 christos // tab-width: 4
1766 1.1 christos // c-file-style: "bsd"
1767 1.1 christos // c-basic-offset: 4
1768 1.1 christos // fill-column: 120
1769 1.1 christos // indent-tabs-mode: nil
1770 1.1 christos // End:
1771