1 /*
2 * Copyright (c) 2016-2024 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 /*
30 * This test exercises nexus port binding.
31 */
32
33 #include <assert.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <stdio.h>
37 #include <unistd.h>
38 #include <errno.h>
39 #include <darwintest.h>
40
41 #include "skywalk_test_common.h"
42 #include "skywalk_test_driver.h"
43 #include "skywalk_test_utils.h"
44
45 #define NRINGS 2
46
47 static channel_t ch00, ch01; /* ch0 ring 0,1 */
48 static channel_t ch10, ch11; /* ch1 ring 0,1 */
49 static channel_attr_t attr0, attr1;
50 static uuid_t key0, key1;
51 static uuid_t netif_provider, netif_instance, netif_attach;
52
53 static void
skt_bind_init(const char * name,nexus_type_t type,int anon,int add_netif)54 skt_bind_init(const char *name, nexus_type_t type, int anon, int add_netif)
55 {
56 int error;
57 struct sktc_nexus_attr attr = SKTC_NEXUS_ATTR_INIT();
58
59 strncpy((char *)attr.name, name, sizeof(nexus_name_t) - 1);
60 attr.type = type;
61 attr.ntxrings = NRINGS;
62 attr.nrxrings = NRINGS;
63 attr.anonymous = anon;
64
65 sktc_setup_nexus(&attr);
66
67 assert(uuid_is_null(netif_provider));
68 assert(uuid_is_null(netif_instance));
69 assert(uuid_is_null(netif_attach));
70 if (add_netif) {
71 strncpy((char *)attr.name, "skt_netif_feth0",
72 sizeof(nexus_name_t) - 1);
73 attr.type = NEXUS_TYPE_NET_IF;
74 attr.ntxrings = -1;
75 attr.nrxrings = -1;
76
77 sktc_build_nexus(sktc_nexus_controller, &attr,
78 &netif_provider, &netif_instance);
79
80 error = __os_nexus_ifattach(sktc_nexus_controller,
81 netif_instance, FETH0_NAME, NULL, false, &netif_attach);
82 SKTC_ASSERT_ERR(error == 0);
83
84 error = __os_nexus_ifattach(sktc_nexus_controller,
85 sktc_instance_uuid, NULL, netif_instance,
86 0, &netif_attach);
87 SKTC_ASSERT_ERR(error == 0);
88 }
89
90 uuid_generate_random(key0);
91 uuid_generate_random(key1);
92
93 attr0 = os_channel_attr_create();
94 assert(attr0 != NULL);
95 attr1 = os_channel_attr_create();
96 assert(attr1 != NULL);
97
98 error = os_channel_attr_set_key(attr0, key0, sizeof(key0));
99 SKTC_ASSERT_ERR(error == 0);
100 error = os_channel_attr_set_key(attr1, key1, sizeof(key1));
101 SKTC_ASSERT_ERR(error == 0);
102 }
103
104 static void
skt_bind_fini(void)105 skt_bind_fini(void)
106 {
107 if (ch00 != NULL) {
108 os_channel_destroy(ch00);
109 ch00 = NULL;
110 }
111 if (ch01 != NULL) {
112 os_channel_destroy(ch01);
113 ch01 = NULL;
114 }
115
116 if (ch10 != NULL) {
117 os_channel_destroy(ch10);
118 ch10 = NULL;
119 }
120 if (ch11 != NULL) {
121 os_channel_destroy(ch11);
122 ch11 = NULL;
123 }
124
125 if (attr0 != NULL) {
126 os_channel_attr_destroy(attr0);
127 attr0 = NULL;
128 }
129 if (attr1 != NULL) {
130 os_channel_attr_destroy(attr1);
131 attr1 = NULL;
132 }
133 uuid_clear(key0);
134 uuid_clear(key1);
135
136 if (!uuid_is_null(netif_attach)) {
137 int error;
138
139 error = __os_nexus_ifdetach(sktc_nexus_controller,
140 sktc_instance_uuid, netif_attach);
141 SKTC_ASSERT_ERR(error == 0);
142 uuid_clear(netif_attach);
143
144 error = os_nexus_controller_free_provider_instance(
145 sktc_nexus_controller, netif_instance);
146 SKTC_ASSERT_ERR(error == 0);
147 uuid_clear(netif_instance);
148
149 error = os_nexus_controller_deregister_provider(
150 sktc_nexus_controller, netif_provider);
151 SKTC_ASSERT_ERR(error == 0);
152 uuid_clear(netif_provider);
153 }
154
155 sktc_cleanup_nexus();
156 }
157
158 static void
skt_bind_common(nexus_type_t type,nexus_port_t port0,nexus_port_t port1)159 skt_bind_common(nexus_type_t type, nexus_port_t port0, nexus_port_t port1)
160 {
161 ring_id_t ringid;
162 uuid_t flow_id;
163 int error, upp;
164
165 error = sktc_bind_nexus_key(port0, key0, sizeof(key0));
166 SKTC_ASSERT_ERR(error == 0);
167
168 /* this must fail since the port has now been bound */
169 error = sktc_bind_nexus_key(port0, key0, sizeof(key0));
170 SKTC_ASSERT_ERR(error == -1);
171 SKTC_ASSERT_ERR(errno == EEXIST);
172
173 error = sktc_bind_nexus_key(port1, key1, sizeof(key1));
174 SKTC_ASSERT_ERR(error == 0);
175
176 /* this must fail since the port has now been bound */
177 error = sktc_bind_nexus_key(port1, key1, sizeof(key1));
178 SKTC_ASSERT_ERR(error == -1);
179 SKTC_ASSERT_ERR(errno == EEXIST);
180
181 /*
182 * flowswitch doesn't allow opening a channel without a flow bound
183 * to the port.
184 */
185 if (type == NEXUS_TYPE_FLOW_SWITCH) {
186 uuid_generate(flow_id);
187 error = sktc_bind_tcp4_flow(sktc_nexus_controller,
188 sktc_instance_uuid, 0, port0, flow_id);
189 SKTC_ASSERT_ERR(error == 0);
190 upp = 1;
191 } else {
192 upp = -1;
193 }
194
195 /* this must fail since the key attribute is missing */
196 ch00 = sktu_channel_create_extended(sktc_instance_uuid,
197 port0, CHANNEL_DIR_TX_RX, CHANNEL_RING_ID_ANY, NULL,
198 -1, -1, -1, -1, -1, -1, upp, 1, -1, -1);
199 assert(ch00 == NULL);
200 SKTC_ASSERT_ERR(errno == EACCES);
201
202 /* this must work (key attributes match) */
203 ch00 = sktu_channel_create_extended(sktc_instance_uuid,
204 port0, CHANNEL_DIR_TX_RX, CHANNEL_RING_ID_ANY, attr0,
205 -1, -1, -1, -1, -1, -1, upp, 1, -1, -1);
206 assert(ch00 != NULL);
207
208 /* we assume this won't change, so retrieve now */
209 ringid = os_channel_ring_id(ch00, CHANNEL_FIRST_TX_RING);
210 os_channel_destroy(ch00);
211
212 if (type == NEXUS_TYPE_FLOW_SWITCH) {
213 uuid_generate(flow_id);
214 error = sktc_bind_tcp4_flow(sktc_nexus_controller,
215 sktc_instance_uuid, 0, port1, flow_id);
216 SKTC_ASSERT_ERR(error == 0);
217 }
218
219 /* this must fail since the key attribute is missing */
220 ch10 = sktu_channel_create_extended(sktc_instance_uuid,
221 port1, CHANNEL_DIR_TX_RX, CHANNEL_RING_ID_ANY, NULL,
222 -1, -1, -1, -1, -1, -1, upp, 1, -1, -1);
223 assert(ch10 == NULL);
224 SKTC_ASSERT_ERR(errno == EACCES);
225
226 /* this must work (key attributes match) */
227 ch10 = sktu_channel_create_extended(sktc_instance_uuid,
228 port1, CHANNEL_DIR_TX_RX, CHANNEL_RING_ID_ANY, attr1,
229 -1, -1, -1, -1, -1, -1, upp, 1, -1, -1);
230 assert(ch10 != NULL);
231
232 os_channel_destroy(ch10);
233
234 if (type == NEXUS_TYPE_FLOW_SWITCH) {
235 error = sktc_bind_nexus_key(port0, key0, sizeof(key0));
236 SKTC_ASSERT_ERR(error == 0);
237
238 uuid_generate(flow_id);
239 error = sktc_bind_tcp4_flow(sktc_nexus_controller,
240 sktc_instance_uuid, 0, port0, flow_id);
241 SKTC_ASSERT_ERR(error == 0);
242 }
243
244 /* this must fail (key attributes swapped) */
245 ch00 = sktu_channel_create_extended(sktc_instance_uuid,
246 port0, CHANNEL_DIR_TX_RX, CHANNEL_RING_ID_ANY, attr1,
247 -1, -1, -1, -1, -1, -1, upp, 1, -1, -1);
248 assert(ch00 == NULL);
249 SKTC_ASSERT_ERR(errno == EACCES);
250
251 /*
252 * repeat on a per ring basis.
253 * these all must fail since the key attribute is missing
254 */
255 ch00 = sktu_channel_create_extended(sktc_instance_uuid,
256 port0, CHANNEL_DIR_TX_RX, ringid, NULL,
257 -1, -1, -1, -1, -1, -1, upp, 1, -1, -1);
258 assert(ch00 == NULL);
259 SKTC_ASSERT_ERR(errno == EACCES);
260
261 assert(ch01 == NULL);
262 ch01 = sktu_channel_create_extended(sktc_instance_uuid,
263 port0, CHANNEL_DIR_TX_RX, (ringid + 1), NULL,
264 -1, -1, -1, -1, -1, -1, upp, 1, -1, -1);
265 assert(ch01 == NULL);
266 SKTC_ASSERT_ERR(errno == EACCES);
267
268 /* these all must work (key attributes match) */
269 ch00 = sktu_channel_create_extended(sktc_instance_uuid,
270 port0, CHANNEL_DIR_TX_RX, ringid, attr0,
271 -1, -1, -1, -1, -1, -1, upp, 1, -1, -1);
272 assert(ch00 != NULL);
273
274 ch01 = sktu_channel_create_extended(sktc_instance_uuid,
275 port0, CHANNEL_DIR_TX_RX, (ringid + 1), attr0,
276 -1, -1, -1, -1, -1, -1, upp, 1, -1, -1);
277 assert(ch01 != NULL);
278
279 os_channel_destroy(ch00);
280 os_channel_destroy(ch01);
281
282 if (type == NEXUS_TYPE_FLOW_SWITCH) {
283 error = sktc_bind_nexus_key(port1, key1, sizeof(key1));
284 SKTC_ASSERT_ERR(error == 0);
285 uuid_generate(flow_id);
286 error = sktc_bind_tcp4_flow(sktc_nexus_controller,
287 sktc_instance_uuid, 0, port1, flow_id);
288 SKTC_ASSERT_ERR(error == 0);
289 }
290
291 /* this must fail (key attributes swapped) */
292 ch10 = sktu_channel_create_extended(sktc_instance_uuid,
293 port1, CHANNEL_DIR_TX_RX, CHANNEL_RING_ID_ANY, attr0,
294 -1, -1, -1, -1, -1, -1, upp, 1, -1, -1);
295 assert(ch10 == NULL);
296 SKTC_ASSERT_ERR(errno == EACCES);
297
298 /*
299 * repeat on a per ring basis.
300 * these all must fail since the key attribute is missing
301 */
302 ch10 = sktu_channel_create_extended(sktc_instance_uuid,
303 port1, CHANNEL_DIR_TX_RX, ringid, NULL,
304 -1, -1, -1, -1, -1, -1, upp, 1, -1, -1);
305 assert(ch10 == NULL);
306 SKTC_ASSERT_ERR(errno == EACCES);
307
308 assert(ch11 == NULL);
309 ch11 = sktu_channel_create_extended(sktc_instance_uuid,
310 port1, CHANNEL_DIR_TX_RX, (ringid + 1), NULL,
311 -1, -1, -1, -1, -1, -1, upp, 1, -1, -1);
312 assert(ch11 == NULL);
313 SKTC_ASSERT_ERR(errno == EACCES);
314
315 /* these all must work (key attributes match) */
316 ch10 = sktu_channel_create_extended(sktc_instance_uuid,
317 port1, CHANNEL_DIR_TX_RX, ringid, attr1,
318 -1, -1, -1, -1, -1, -1, upp, 1, -1, -1);
319 assert(ch10 != NULL);
320
321 ch11 = sktu_channel_create_extended(sktc_instance_uuid,
322 port1, CHANNEL_DIR_TX_RX, (ringid + 1), attr1,
323 -1, -1, -1, -1, -1, -1, upp, 1, -1, -1);
324 assert(ch11 != NULL);
325
326 os_channel_destroy(ch10);
327 os_channel_destroy(ch11);
328
329 if (type == NEXUS_TYPE_FLOW_SWITCH) {
330 error = sktc_bind_nexus_key(port0, key0, sizeof(key0));
331 SKTC_ASSERT_ERR(error == 0);
332 uuid_generate(flow_id);
333 error = sktc_bind_tcp4_flow(sktc_nexus_controller,
334 sktc_instance_uuid, 0, port0, flow_id);
335 SKTC_ASSERT_ERR(error == 0);
336 }
337
338 /* these all must fail (key attributes swapped) */
339 ch00 = sktu_channel_create_extended(sktc_instance_uuid,
340 port0, CHANNEL_DIR_TX_RX, ringid, attr1,
341 -1, -1, -1, -1, -1, -1, upp, 1, -1, -1);
342 assert(ch00 == NULL);
343 SKTC_ASSERT_ERR(errno == EACCES);
344
345 ch01 = sktu_channel_create_extended(sktc_instance_uuid,
346 port0, CHANNEL_DIR_TX_RX, (ringid + 1), attr1,
347 -1, -1, -1, -1, -1, -1, upp, 1, -1, -1);
348 assert(ch01 == NULL);
349 SKTC_ASSERT_ERR(errno == EACCES);
350
351 /* these all must work (key attributes match) */
352 ch00 = sktu_channel_create_extended(sktc_instance_uuid,
353 port0, CHANNEL_DIR_TX_RX, ringid, attr0,
354 -1, -1, -1, -1, -1, -1, upp, 1, -1, -1);
355 assert(ch00 != NULL);
356
357 ch01 = sktu_channel_create_extended(sktc_instance_uuid,
358 port0, CHANNEL_DIR_TX_RX, (ringid + 1), attr0,
359 -1, -1, -1, -1, -1, -1, upp, 1, -1, -1);
360 assert(ch01 != NULL);
361
362 os_channel_destroy(ch00);
363 ch00 = NULL;
364 os_channel_destroy(ch01);
365 ch01 = NULL;
366
367 if (type == NEXUS_TYPE_FLOW_SWITCH) {
368 error = sktc_bind_nexus_key(port1, key1, sizeof(key1));
369 SKTC_ASSERT_ERR(error == 0);
370 uuid_generate(flow_id);
371 error = sktc_bind_tcp4_flow(sktc_nexus_controller,
372 sktc_instance_uuid, 0, port1, flow_id);
373 SKTC_ASSERT_ERR(error == 0);
374 }
375
376 /* these all must fail (key attributes swapped) */
377 ch10 = sktu_channel_create_extended(sktc_instance_uuid,
378 port1, CHANNEL_DIR_TX_RX, ringid, attr0,
379 -1, -1, -1, -1, -1, -1, upp, 1, -1, -1);
380 assert(ch10 == NULL);
381 SKTC_ASSERT_ERR(errno == EACCES);
382
383 ch11 = sktu_channel_create_extended(sktc_instance_uuid,
384 port1, CHANNEL_DIR_TX_RX, (ringid + 1), attr0,
385 -1, -1, -1, -1, -1, -1, upp, 1, -1, -1);
386 assert(ch11 == NULL);
387 SKTC_ASSERT_ERR(errno == EACCES);
388
389 /* these all must work (key attributes match) */
390 ch10 = sktu_channel_create_extended(sktc_instance_uuid,
391 port1, CHANNEL_DIR_TX_RX, ringid, attr1,
392 -1, -1, -1, -1, -1, -1, upp, 1, -1, -1);
393 assert(ch10 != NULL);
394
395 ch11 = sktu_channel_create_extended(sktc_instance_uuid,
396 port1, CHANNEL_DIR_TX_RX, (ringid + 1), attr1,
397 -1, -1, -1, -1, -1, -1, upp, 1, -1, -1);
398 assert(ch11 != NULL);
399
400 os_channel_destroy(ch10);
401 ch10 = NULL;
402 os_channel_destroy(ch11);
403 ch11 = NULL;
404 }
405
406 static int
skt_bindupipeanon_main(int argc,char * argv[])407 skt_bindupipeanon_main(int argc, char *argv[])
408 {
409 int error;
410
411 skt_bind_init("skywalk_test_upipe_anon", NEXUS_TYPE_USER_PIPE, 1, 0);
412
413 error = sktc_bind_nexus_key(NEXUS_PORT_USER_PIPE_CLIENT,
414 key0, sizeof(key0));
415 SKTC_ASSERT_ERR(error == -1);
416 SKTC_ASSERT_ERR(errno == ENXIO);
417
418 error = sktc_bind_nexus_key(NEXUS_PORT_USER_PIPE_SERVER,
419 key1, sizeof(key1));
420 SKTC_ASSERT_ERR(error == -1);
421 SKTC_ASSERT_ERR(errno == ENXIO);
422
423 skt_bind_fini();
424
425 return 0;
426 }
427
428 static int
skt_bindupipekey_main(int argc,char * argv[])429 skt_bindupipekey_main(int argc, char *argv[])
430 {
431 skt_bind_init("skywalk_test_upipe", NEXUS_TYPE_USER_PIPE, 0, 0);
432
433 skt_bind_common(NEXUS_TYPE_USER_PIPE, NEXUS_PORT_USER_PIPE_CLIENT,
434 NEXUS_PORT_USER_PIPE_SERVER);
435
436 skt_bind_fini();
437
438 return 0;
439 }
440
441 static int
skt_bindfswanon_common(const char * name,int add_netif)442 skt_bindfswanon_common(const char *name, int add_netif)
443 {
444 int error;
445
446 skt_bind_init(name, NEXUS_TYPE_FLOW_SWITCH, 1, add_netif);
447
448 error = sktc_bind_nexus_key(NEXUS_PORT_FLOW_SWITCH_CLIENT,
449 key0, sizeof(key0));
450 SKTC_ASSERT_ERR(error == -1);
451 SKTC_ASSERT_ERR(errno == ENXIO);
452
453 error = sktc_bind_nexus_key((NEXUS_PORT_FLOW_SWITCH_CLIENT + 1),
454 key1, sizeof(key1));
455 SKTC_ASSERT_ERR(error == -1);
456 SKTC_ASSERT_ERR(errno == ENXIO);
457
458 skt_bind_fini();
459
460 return 0;
461 }
462
463 static int
skt_bindfswkey_common(const char * name,int add_netif)464 skt_bindfswkey_common(const char *name, int add_netif)
465 {
466 skt_bind_init(name, NEXUS_TYPE_FLOW_SWITCH, 0, add_netif);
467
468 skt_bind_common(NEXUS_TYPE_FLOW_SWITCH,
469 NEXUS_PORT_FLOW_SWITCH_CLIENT,
470 (NEXUS_PORT_FLOW_SWITCH_CLIENT + 1));
471
472 skt_bind_fini();
473
474 return 0;
475 }
476
477 static int
skt_bindnetifkey_common(const char * name,int add_netif)478 skt_bindnetifkey_common(const char *name, int add_netif)
479 {
480 skt_bind_init(name, NEXUS_TYPE_FLOW_SWITCH, 0, 1);
481
482 int error;
483 for (int i = NEXUS_PORT_NET_IF_CLIENT; i < 128; i++) {
484 error = os_nexus_controller_bind_provider_instance(
485 sktc_nexus_controller, netif_instance, i,
486 getpid(), NULL, key0, sizeof(key0),
487 NEXUS_BIND_PID | NEXUS_BIND_KEY);
488 if (error != 0) {
489 T_LOG("failed early at %d", i);
490 }
491 SKTC_ASSERT_ERR(error == 0);
492 }
493
494 // 128 is NETIF DOM max, should reject
495 error = os_nexus_controller_bind_provider_instance(
496 sktc_nexus_controller, netif_instance, 128,
497 getpid(), NULL, key0, sizeof(key0),
498 NEXUS_BIND_PID | NEXUS_BIND_KEY);
499 SKTC_ASSERT_ERR(error != 0);
500
501 for (int i = NEXUS_PORT_NET_IF_CLIENT; i < 128; i++) {
502 error = os_nexus_controller_unbind_provider_instance(
503 sktc_nexus_controller, netif_instance, i);
504 SKTC_ASSERT_ERR(error == 0);
505 }
506
507 return 0;
508 }
509
510 static int
skt_bindfswanon_main(int argc,char * argv[])511 skt_bindfswanon_main(int argc, char *argv[])
512 {
513 return skt_bindfswanon_common("skywalk_test_fsw_anon", 1);
514 }
515
516 static int
skt_bindfswkey_main(int argc,char * argv[])517 skt_bindfswkey_main(int argc, char *argv[])
518 {
519 return skt_bindfswkey_common("skywalk_test_fsw", 1);
520 }
521
522 static int
skt_bindnetifkey_main(int argc,char * argv[])523 skt_bindnetifkey_main(int argc, char *argv[])
524 {
525 return skt_bindnetifkey_common("skywalk_test_netif", 1);
526 }
527
528 struct skywalk_test skt_bindupipeanon = {
529 "bindupipeanon", "bind a channel to an anonymous user pipe nexus",
530 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_USER_PIPE,
531 skt_bindupipeanon_main,
532 };
533
534 struct skywalk_test skt_bindupipekey = {
535 "bindupipekey", "bind a channel to a non-anonymous user pipe nexus",
536 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_USER_PIPE,
537 skt_bindupipekey_main,
538 };
539
540 struct skywalk_test skt_bindfswanon = {
541 "bindfswanon",
542 "bind a channel to an anonymous flow switch nexus",
543 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF |
544 SK_FEATURE_NEXUS_FLOWSWITCH,
545 skt_bindfswanon_main, { NULL },
546 sktc_ifnet_feth0_create, sktc_ifnet_feth0_destroy,
547 };
548
549 struct skywalk_test skt_bindfswkey = {
550 "bindfswkey",
551 "bind a channel to a non-anonymous flow switch nexus",
552 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF |
553 SK_FEATURE_NEXUS_FLOWSWITCH | SK_FEATURE_NETNS,
554 skt_bindfswkey_main, { NULL },
555 sktc_ifnet_feth0_create, sktc_ifnet_feth0_destroy,
556 };
557
558 struct skywalk_test skt_bindnetifkey = {
559 "bindnetifkey",
560 "bind a channel to a non-anonymous netif nexus",
561 SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_NETIF,
562 skt_bindnetifkey_main, { NULL },
563 sktc_ifnet_feth0_create, sktc_ifnet_feth0_destroy,
564 };
565