blob: 9b42ae71a8018812c88a686b633722207574f8e0 [file] [log] [blame]
Filip Tehlar0ad06082021-07-25 14:38:45 +00001/* SPDX-License-Identifier: Apache-2.0
2 * Copyright(c) 2021 Cisco Systems, Inc.
3 */
4
5#include <vat/vat.h>
6#include <vlibapi/api.h>
7#include <vlibmemory/api.h>
8#include <vppinfra/error.h>
9#include <vpp/api/types.h>
10
11#include <vnet/ipsec/ipsec.h>
12#include <vnet/ip/ip_types_api.h>
13
14#define __plugin_msg_base ipsec_test_main.msg_id_base
15#include <vlibapi/vat_helper_macros.h>
16
17#include <vlibmemory/vlib.api_enum.h>
18#include <vlibmemory/vlib.api_types.h>
19
20/* Declare message IDs */
21#include <vnet/format_fns.h>
22#include <vnet/ipsec/ipsec.api_enum.h>
23#include <vnet/ipsec/ipsec.api_types.h>
24
25#define vl_endianfun /* define message structures */
26#include <vnet/ipsec/ipsec.api.h>
27#undef vl_endianfun
28
Klement Sekera9b7e8ac2021-11-22 21:26:20 +010029#define vl_calcsizefun
30#include <vnet/ipsec/ipsec.api.h>
31#undef vl_calcsizefun
32
Filip Tehlar0ad06082021-07-25 14:38:45 +000033typedef struct
34{
35 /* API message ID base */
36 u16 msg_id_base;
37 u32 ping_id;
38 vat_main_t *vat_main;
39} ipsec_test_main_t;
40
41static ipsec_test_main_t ipsec_test_main;
42
43static void
44vl_api_ipsec_spds_details_t_handler (vl_api_ipsec_spds_details_t *mp)
45{
46}
47
48static void
49vl_api_ipsec_itf_details_t_handler (vl_api_ipsec_itf_details_t *mp)
50{
51}
52
53static int
54api_ipsec_itf_delete (vat_main_t *vat)
55{
56 return -1;
57}
58
59static int
60api_ipsec_itf_create (vat_main_t *vat)
61{
62 return -1;
63}
64
65static void
66vl_api_ipsec_itf_create_reply_t_handler (vl_api_ipsec_itf_create_reply_t *vat)
67{
68}
69
70static int
71api_ipsec_spd_entry_add_del (vat_main_t *vam)
72{
73 unformat_input_t *i = vam->input;
74 vl_api_ipsec_spd_entry_add_del_t *mp;
75 u8 is_add = 1, is_outbound = 0;
Piotr Bronowski815c6a42022-06-09 09:09:28 +000076 u32 spd_id = 0, sa_id = 0, protocol = IPSEC_POLICY_PROTOCOL_ANY, policy = 0;
77 i32 priority = 0;
78 u32 rport_start = 0, rport_stop = (u32) ~0;
79 u32 lport_start = 0, lport_stop = (u32) ~0;
80 vl_api_address_t laddr_start = {}, laddr_stop = {}, raddr_start = {},
81 raddr_stop = {};
82 int ret;
83
84 while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
85 {
86 if (unformat (i, "del"))
87 is_add = 0;
88 if (unformat (i, "outbound"))
89 is_outbound = 1;
90 if (unformat (i, "inbound"))
91 is_outbound = 0;
92 else if (unformat (i, "spd_id %d", &spd_id))
93 ;
94 else if (unformat (i, "sa_id %d", &sa_id))
95 ;
96 else if (unformat (i, "priority %d", &priority))
97 ;
98 else if (unformat (i, "protocol %d", &protocol))
99 ;
100 else if (unformat (i, "lport_start %d", &lport_start))
101 ;
102 else if (unformat (i, "lport_stop %d", &lport_stop))
103 ;
104 else if (unformat (i, "rport_start %d", &rport_start))
105 ;
106 else if (unformat (i, "rport_stop %d", &rport_stop))
107 ;
108 else if (unformat (i, "laddr_start %U", unformat_vl_api_address,
109 &laddr_start))
110 ;
111 else if (unformat (i, "laddr_stop %U", unformat_vl_api_address,
112 &laddr_stop))
113 ;
114 else if (unformat (i, "raddr_start %U", unformat_vl_api_address,
115 &raddr_start))
116 ;
117 else if (unformat (i, "raddr_stop %U", unformat_vl_api_address,
118 &raddr_stop))
119 ;
120 else if (unformat (i, "action %U", unformat_ipsec_policy_action,
121 &policy))
122 {
123 if (policy == IPSEC_POLICY_ACTION_RESOLVE)
124 {
125 clib_warning ("unsupported action: 'resolve'");
126 return -99;
127 }
128 }
129 else
130 {
131 clib_warning ("parse error '%U'", format_unformat_error, i);
132 return -99;
133 }
134 }
135
136 M (IPSEC_SPD_ENTRY_ADD_DEL, mp);
137
138 mp->is_add = is_add;
139
140 mp->entry.spd_id = ntohl (spd_id);
141 mp->entry.priority = ntohl (priority);
142 mp->entry.is_outbound = is_outbound;
143
144 clib_memcpy (&mp->entry.remote_address_start, &raddr_start,
145 sizeof (vl_api_address_t));
146 clib_memcpy (&mp->entry.remote_address_stop, &raddr_stop,
147 sizeof (vl_api_address_t));
148 clib_memcpy (&mp->entry.local_address_start, &laddr_start,
149 sizeof (vl_api_address_t));
150 clib_memcpy (&mp->entry.local_address_stop, &laddr_stop,
151 sizeof (vl_api_address_t));
152
153 mp->entry.protocol = protocol ? (u8) protocol : IPSEC_POLICY_PROTOCOL_ANY;
154 mp->entry.local_port_start = ntohs ((u16) lport_start);
155 mp->entry.local_port_stop = ntohs ((u16) lport_stop);
156 mp->entry.remote_port_start = ntohs ((u16) rport_start);
157 mp->entry.remote_port_stop = ntohs ((u16) rport_stop);
158 mp->entry.policy = (u8) policy;
159 mp->entry.sa_id = ntohl (sa_id);
160
161 S (mp);
162 W (ret);
163 return ret;
164}
165
166static int
167api_ipsec_spd_entry_add_del_v2 (vat_main_t *vam)
168{
169 unformat_input_t *i = vam->input;
170 vl_api_ipsec_spd_entry_add_del_t *mp;
171 u8 is_add = 1, is_outbound = 0;
172 u32 spd_id = 0, sa_id = 0, protocol = IPSEC_POLICY_PROTOCOL_ANY, policy = 0;
Filip Tehlar0ad06082021-07-25 14:38:45 +0000173 i32 priority = 0;
174 u32 rport_start = 0, rport_stop = (u32) ~0;
175 u32 lport_start = 0, lport_stop = (u32) ~0;
176 vl_api_address_t laddr_start = {}, laddr_stop = {}, raddr_start = {},
177 raddr_stop = {};
178 int ret;
179
180 while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
181 {
182 if (unformat (i, "del"))
183 is_add = 0;
184 if (unformat (i, "outbound"))
185 is_outbound = 1;
186 if (unformat (i, "inbound"))
187 is_outbound = 0;
188 else if (unformat (i, "spd_id %d", &spd_id))
189 ;
190 else if (unformat (i, "sa_id %d", &sa_id))
191 ;
192 else if (unformat (i, "priority %d", &priority))
193 ;
194 else if (unformat (i, "protocol %d", &protocol))
195 ;
196 else if (unformat (i, "lport_start %d", &lport_start))
197 ;
198 else if (unformat (i, "lport_stop %d", &lport_stop))
199 ;
200 else if (unformat (i, "rport_start %d", &rport_start))
201 ;
202 else if (unformat (i, "rport_stop %d", &rport_stop))
203 ;
204 else if (unformat (i, "laddr_start %U", unformat_vl_api_address,
205 &laddr_start))
206 ;
207 else if (unformat (i, "laddr_stop %U", unformat_vl_api_address,
208 &laddr_stop))
209 ;
210 else if (unformat (i, "raddr_start %U", unformat_vl_api_address,
211 &raddr_start))
212 ;
213 else if (unformat (i, "raddr_stop %U", unformat_vl_api_address,
214 &raddr_stop))
215 ;
216 else if (unformat (i, "action %U", unformat_ipsec_policy_action,
217 &policy))
218 {
219 if (policy == IPSEC_POLICY_ACTION_RESOLVE)
220 {
221 clib_warning ("unsupported action: 'resolve'");
222 return -99;
223 }
224 }
225 else
226 {
227 clib_warning ("parse error '%U'", format_unformat_error, i);
228 return -99;
229 }
230 }
231
232 M (IPSEC_SPD_ENTRY_ADD_DEL, mp);
233
234 mp->is_add = is_add;
235
236 mp->entry.spd_id = ntohl (spd_id);
237 mp->entry.priority = ntohl (priority);
238 mp->entry.is_outbound = is_outbound;
239
240 clib_memcpy (&mp->entry.remote_address_start, &raddr_start,
241 sizeof (vl_api_address_t));
242 clib_memcpy (&mp->entry.remote_address_stop, &raddr_stop,
243 sizeof (vl_api_address_t));
244 clib_memcpy (&mp->entry.local_address_start, &laddr_start,
245 sizeof (vl_api_address_t));
246 clib_memcpy (&mp->entry.local_address_stop, &laddr_stop,
247 sizeof (vl_api_address_t));
248
249 mp->entry.protocol = (u8) protocol;
250 mp->entry.local_port_start = ntohs ((u16) lport_start);
251 mp->entry.local_port_stop = ntohs ((u16) lport_stop);
252 mp->entry.remote_port_start = ntohs ((u16) rport_start);
253 mp->entry.remote_port_stop = ntohs ((u16) rport_stop);
254 mp->entry.policy = (u8) policy;
255 mp->entry.sa_id = ntohl (sa_id);
256
257 S (mp);
258 W (ret);
259 return ret;
260}
261
262static void
263vl_api_ipsec_spd_details_t_handler (vl_api_ipsec_spd_details_t *mp)
264{
265}
266
267static void
268vl_api_ipsec_sad_entry_add_del_reply_t_handler (
269 vl_api_ipsec_sad_entry_add_del_reply_t *mp)
270{
271}
272
273static void
274vl_api_ipsec_sad_entry_add_del_v3_reply_t_handler (
275 vl_api_ipsec_sad_entry_add_del_v3_reply_t *mp)
276{
277}
278
279static void
280vl_api_ipsec_sad_entry_add_reply_t_handler (
281 vl_api_ipsec_sad_entry_add_reply_t *mp)
282{
283}
284
285static int
286api_ipsec_sad_entry_del (vat_main_t *vat)
287{
288 return -1;
289}
290
Maxime Peim1271e3a2023-03-20 14:13:56 +0000291static int
292api_ipsec_sad_bind (vat_main_t *vat)
293{
294 return -1;
295}
296
297static int
298api_ipsec_sad_unbind (vat_main_t *vat)
299{
300 return -1;
301}
302
Filip Tehlar0ad06082021-07-25 14:38:45 +0000303static void
304vl_api_ipsec_sad_entry_add_del_v2_reply_t_handler (
305 vl_api_ipsec_sad_entry_add_del_v2_reply_t *mp)
306{
307}
308
309static void
310vl_api_ipsec_spd_interface_details_t_handler (
311 vl_api_ipsec_spd_interface_details_t *vat)
312{
313}
314
315static int
316api_ipsec_sad_entry_add_del_v3 (vat_main_t *vat)
317{
318 return -1;
319}
320
321static int
Arthur de Kerhor4117b242022-08-31 19:13:03 +0200322api_ipsec_sad_entry_update (vat_main_t *vat)
323{
324 return -1;
325}
326
327static int
Filip Tehlar0ad06082021-07-25 14:38:45 +0000328api_ipsec_tunnel_protect_update (vat_main_t *vat)
329{
330 return -1;
331}
332
333static void
334vl_api_ipsec_backend_details_t_handler (vl_api_ipsec_backend_details_t *mp)
335{
336}
337
338static int
339api_ipsec_sa_v3_dump (vat_main_t *vat)
340{
341 return -1;
342}
343
344static int
345api_ipsec_tunnel_protect_dump (vat_main_t *vat)
346{
347 return -1;
348}
349
350static int
351api_ipsec_tunnel_protect_del (vat_main_t *vat)
352{
353 return -1;
354}
355
356static void
357vl_api_ipsec_tunnel_protect_details_t_handler (
358 vl_api_ipsec_tunnel_protect_details_t *mp)
359{
360}
361
362static int
363api_ipsec_sad_entry_add (vat_main_t *vat)
364{
365 return -1;
366}
367
368static void
369vl_api_ipsec_spd_entry_add_del_reply_t_handler (
370 vl_api_ipsec_spd_entry_add_del_reply_t *mp)
371{
372}
373
Piotr Bronowski815c6a42022-06-09 09:09:28 +0000374static void
375vl_api_ipsec_spd_entry_add_del_v2_reply_t_handler (
376 vl_api_ipsec_spd_entry_add_del_v2_reply_t *mp)
377{
378}
379
Filip Tehlar0ad06082021-07-25 14:38:45 +0000380static int
381api_ipsec_spds_dump (vat_main_t *vam)
382{
383 return -1;
384}
385
386static int
387api_ipsec_itf_dump (vat_main_t *vam)
388{
389 return -1;
390}
391
392static void
393vl_api_ipsec_sa_v3_details_t_handler (vl_api_ipsec_sa_v3_details_t *mp)
394{
395}
396
397static int
398api_ipsec_spd_interface_dump (vat_main_t *vat)
399{
400 return -1;
401}
402
403static void
404vl_api_ipsec_sa_v2_details_t_handler (vl_api_ipsec_sa_v2_details_t *mp)
405{
406}
407
408static int
409api_ipsec_sa_v2_dump (vat_main_t *mp)
410{
411 return -1;
412}
413
414static int
415api_ipsec_sa_dump (vat_main_t *vam)
416{
417 unformat_input_t *i = vam->input;
418 vl_api_ipsec_sa_dump_t *mp;
419 vl_api_control_ping_t *mp_ping;
420 u32 sa_id = ~0;
421 int ret;
422
423 while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
424 {
425 if (unformat (i, "sa_id %d", &sa_id))
426 ;
427 else
428 {
429 clib_warning ("parse error '%U'", format_unformat_error, i);
430 return -99;
431 }
432 }
433
434 M (IPSEC_SA_DUMP, mp);
435
436 mp->sa_id = ntohl (sa_id);
437
438 S (mp);
439
440 /* Use a control ping for synchronization */
441 PING (&ipsec_test_main, mp_ping);
442 S (mp_ping);
443
444 W (ret);
445 return ret;
446}
447
448static void
Maxime Peim1271e3a2023-03-20 14:13:56 +0000449vl_api_ipsec_sa_v4_details_t_handler (vl_api_ipsec_sa_v4_details_t *mp)
450{
451}
452
453static int
454api_ipsec_sa_v4_dump (vat_main_t *mp)
455{
456 return -1;
457}
458
459static void
Filip Tehlar0ad06082021-07-25 14:38:45 +0000460vl_api_ipsec_sa_details_t_handler (vl_api_ipsec_sa_details_t *mp)
461{
462 vat_main_t *vam = &vat_main;
463
464 print (vam->ofp,
465 "sa_id %u sw_if_index %u spi %u proto %u crypto_alg %u "
466 "crypto_key %U integ_alg %u integ_key %U flags %x "
467 "tunnel_src_addr %U tunnel_dst_addr %U "
468 "salt %u seq_outbound %lu last_seq_inbound %lu "
469 "replay_window %lu stat_index %u\n",
470 ntohl (mp->entry.sad_id), ntohl (mp->sw_if_index),
471 ntohl (mp->entry.spi), ntohl (mp->entry.protocol),
472 ntohl (mp->entry.crypto_algorithm), format_hex_bytes,
473 mp->entry.crypto_key.data, mp->entry.crypto_key.length,
474 ntohl (mp->entry.integrity_algorithm), format_hex_bytes,
475 mp->entry.integrity_key.data, mp->entry.integrity_key.length,
476 ntohl (mp->entry.flags), format_vl_api_address, &mp->entry.tunnel_src,
477 format_vl_api_address, &mp->entry.tunnel_dst, ntohl (mp->salt),
478 clib_net_to_host_u64 (mp->seq_outbound),
479 clib_net_to_host_u64 (mp->last_seq_inbound),
480 clib_net_to_host_u64 (mp->replay_window), ntohl (mp->stat_index));
481}
482
483static int
484api_ipsec_spd_dump (vat_main_t *vam)
485{
486 return -1;
487}
488
489uword
490unformat_ipsec_api_crypto_alg (unformat_input_t *input, va_list *args)
491{
492 u32 *r = va_arg (*args, u32 *);
493
494 if (0)
495 ;
496#define _(v, f, s) else if (unformat (input, s)) *r = IPSEC_API_CRYPTO_ALG_##f;
497 foreach_ipsec_crypto_alg
498#undef _
499 else return 0;
500 return 1;
501}
502
503uword
504unformat_ipsec_api_integ_alg (unformat_input_t *input, va_list *args)
505{
506 u32 *r = va_arg (*args, u32 *);
507
508 if (0)
509 ;
510#define _(v, f, s) else if (unformat (input, s)) *r = IPSEC_API_INTEG_ALG_##f;
511 foreach_ipsec_integ_alg
512#undef _
513 else return 0;
514 return 1;
515}
516
517static int
518api_ipsec_sad_entry_add_del (vat_main_t *vam)
519{
520 unformat_input_t *i = vam->input;
521 vl_api_ipsec_sad_entry_add_del_t *mp;
522 u32 sad_id = 0, spi = 0;
523 u8 *ck = 0, *ik = 0;
524 u8 is_add = 1;
525
526 vl_api_ipsec_crypto_alg_t crypto_alg = IPSEC_API_CRYPTO_ALG_NONE;
527 vl_api_ipsec_integ_alg_t integ_alg = IPSEC_API_INTEG_ALG_NONE;
528 vl_api_ipsec_sad_flags_t flags = IPSEC_API_SAD_FLAG_NONE;
529 vl_api_ipsec_proto_t protocol = IPSEC_API_PROTO_AH;
530 vl_api_address_t tun_src, tun_dst;
531 int ret;
532
533 while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
534 {
535 if (unformat (i, "del"))
536 is_add = 0;
537 else if (unformat (i, "sad_id %d", &sad_id))
538 ;
539 else if (unformat (i, "spi %d", &spi))
540 ;
541 else if (unformat (i, "esp"))
542 protocol = IPSEC_API_PROTO_ESP;
543 else if (unformat (i, "tunnel_src %U", unformat_vl_api_address,
544 &tun_src))
545 {
546 flags |= IPSEC_API_SAD_FLAG_IS_TUNNEL;
547 if (ADDRESS_IP6 == tun_src.af)
548 flags |= IPSEC_API_SAD_FLAG_IS_TUNNEL_V6;
549 }
550 else if (unformat (i, "tunnel_dst %U", unformat_vl_api_address,
551 &tun_dst))
552 {
553 flags |= IPSEC_API_SAD_FLAG_IS_TUNNEL;
554 if (ADDRESS_IP6 == tun_src.af)
555 flags |= IPSEC_API_SAD_FLAG_IS_TUNNEL_V6;
556 }
557 else if (unformat (i, "crypto_alg %U", unformat_ipsec_api_crypto_alg,
558 &crypto_alg))
559 ;
560 else if (unformat (i, "crypto_key %U", unformat_hex_string, &ck))
561 ;
562 else if (unformat (i, "integ_alg %U", unformat_ipsec_api_integ_alg,
563 &integ_alg))
564 ;
565 else if (unformat (i, "integ_key %U", unformat_hex_string, &ik))
566 ;
567 else
568 {
569 clib_warning ("parse error '%U'", format_unformat_error, i);
570 return -99;
571 }
572 }
573
574 M (IPSEC_SAD_ENTRY_ADD_DEL, mp);
575
576 mp->is_add = is_add;
577 mp->entry.sad_id = ntohl (sad_id);
578 mp->entry.protocol = protocol;
579 mp->entry.spi = ntohl (spi);
580 mp->entry.flags = flags;
581
582 mp->entry.crypto_algorithm = crypto_alg;
583 mp->entry.integrity_algorithm = integ_alg;
584 mp->entry.crypto_key.length = vec_len (ck);
585 mp->entry.integrity_key.length = vec_len (ik);
586
587 if (mp->entry.crypto_key.length > sizeof (mp->entry.crypto_key.data))
588 mp->entry.crypto_key.length = sizeof (mp->entry.crypto_key.data);
589
590 if (mp->entry.integrity_key.length > sizeof (mp->entry.integrity_key.data))
591 mp->entry.integrity_key.length = sizeof (mp->entry.integrity_key.data);
592
593 if (ck)
594 clib_memcpy (mp->entry.crypto_key.data, ck, mp->entry.crypto_key.length);
595 if (ik)
596 clib_memcpy (mp->entry.integrity_key.data, ik,
597 mp->entry.integrity_key.length);
598
599 if (flags & IPSEC_API_SAD_FLAG_IS_TUNNEL)
600 {
601 clib_memcpy (&mp->entry.tunnel_src, &tun_src,
602 sizeof (mp->entry.tunnel_src));
603 clib_memcpy (&mp->entry.tunnel_dst, &tun_dst,
604 sizeof (mp->entry.tunnel_dst));
605 }
606
607 S (mp);
608 W (ret);
609 return ret;
610}
611
612static int
613api_ipsec_sad_entry_add_del_v2 (vat_main_t *vam)
614{
615 return -1;
616}
617
618static int
619api_ipsec_interface_add_del_spd (vat_main_t *vam)
620{
621 vnet_main_t *vnm = vnet_get_main ();
622 unformat_input_t *i = vam->input;
623 vl_api_ipsec_interface_add_del_spd_t *mp;
624 u32 sw_if_index;
625 u8 sw_if_index_set = 0;
626 u32 spd_id = (u32) ~0;
627 u8 is_add = 1;
628 int ret;
629
630 while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
631 {
632 if (unformat (i, "del"))
633 is_add = 0;
634 else if (unformat (i, "spd_id %d", &spd_id))
635 ;
636 else if (unformat (i, "%U", unformat_vnet_sw_interface, vnm,
637 &sw_if_index))
638 sw_if_index_set = 1;
639 else if (unformat (i, "sw_if_index %d", &sw_if_index))
640 sw_if_index_set = 1;
641 else
642 {
643 clib_warning ("parse error '%U'", format_unformat_error, i);
644 return -99;
645 }
646 }
647
648 if (spd_id == (u32) ~0)
649 {
650 errmsg ("spd_id must be set");
651 return -99;
652 }
653
654 if (sw_if_index_set == 0)
655 {
656 errmsg ("missing interface name or sw_if_index");
657 return -99;
658 }
659
660 M (IPSEC_INTERFACE_ADD_DEL_SPD, mp);
661
662 mp->spd_id = ntohl (spd_id);
663 mp->sw_if_index = ntohl (sw_if_index);
664 mp->is_add = is_add;
665
666 S (mp);
667 W (ret);
668 return ret;
669}
670
671static int
672api_ipsec_backend_dump (vat_main_t *vam)
673{
674 return -1;
675}
676
677static int
678api_ipsec_select_backend (vat_main_t *vam)
679{
680 return -1;
681}
682
683static int
684api_ipsec_set_async_mode (vat_main_t *vam)
685{
686 return -1;
687}
688
689static int
690api_ipsec_spd_add_del (vat_main_t *vam)
691{
692 unformat_input_t *i = vam->input;
693 vl_api_ipsec_spd_add_del_t *mp;
694 u32 spd_id = ~0;
695 u8 is_add = 1;
696 int ret;
697
698 while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
699 {
700 if (unformat (i, "spd_id %d", &spd_id))
701 ;
702 else if (unformat (i, "del"))
703 is_add = 0;
704 else
705 {
706 clib_warning ("parse error '%U'", format_unformat_error, i);
707 return -99;
708 }
709 }
710 if (spd_id == ~0)
711 {
712 errmsg ("spd_id must be set");
713 return -99;
714 }
715
716 M (IPSEC_SPD_ADD_DEL, mp);
717
718 mp->spd_id = ntohl (spd_id);
719 mp->is_add = is_add;
720
721 S (mp);
722 W (ret);
723 return ret;
724}
725
726#include <vnet/ipsec/ipsec.api_test.c>
727
728/*
729 * Local Variables:
730 * eval: (c-set-style "gnu")
731 * End:
732 */