IPSEC: tidy the policy types
[vpp.git] / src / vnet / ipsec / ipsec_api.c
1 /*
2  *------------------------------------------------------------------
3  * ipsec_api.c - ipsec api
4  *
5  * Copyright (c) 2016 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19
20 #include <vnet/vnet.h>
21 #include <vlibmemory/api.h>
22
23 #include <vnet/interface.h>
24 #include <vnet/api_errno.h>
25 #include <vnet/ip/ip.h>
26 #include <vnet/ip/ip_types_api.h>
27 #include <vnet/fib/fib.h>
28
29 #include <vnet/vnet_msg_enum.h>
30
31 #if WITH_LIBSSL > 0
32 #include <vnet/ipsec/ipsec.h>
33 #endif /* IPSEC */
34
35 #define vl_typedefs             /* define message structures */
36 #include <vnet/vnet_all_api_h.h>
37 #undef vl_typedefs
38
39 #define vl_endianfun            /* define message structures */
40 #include <vnet/vnet_all_api_h.h>
41 #undef vl_endianfun
42
43 /* instantiate all the print functions we know about */
44 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
45 #define vl_printfun
46 #include <vnet/vnet_all_api_h.h>
47 #undef vl_printfun
48
49 #include <vlibapi/api_helper_macros.h>
50
51 #define foreach_vpe_api_msg                                     \
52 _(IPSEC_SPD_ADD_DEL, ipsec_spd_add_del)                         \
53 _(IPSEC_INTERFACE_ADD_DEL_SPD, ipsec_interface_add_del_spd)     \
54 _(IPSEC_SPD_ENTRY_ADD_DEL, ipsec_spd_entry_add_del)             \
55 _(IPSEC_SAD_ENTRY_ADD_DEL, ipsec_sad_entry_add_del)             \
56 _(IPSEC_SA_SET_KEY, ipsec_sa_set_key)                           \
57 _(IPSEC_SA_DUMP, ipsec_sa_dump)                                 \
58 _(IPSEC_SPDS_DUMP, ipsec_spds_dump)                             \
59 _(IPSEC_SPD_DUMP, ipsec_spd_dump)                               \
60 _(IPSEC_SPD_INTERFACE_DUMP, ipsec_spd_interface_dump)           \
61 _(IPSEC_TUNNEL_IF_ADD_DEL, ipsec_tunnel_if_add_del)             \
62 _(IPSEC_TUNNEL_IF_SET_KEY, ipsec_tunnel_if_set_key)             \
63 _(IPSEC_TUNNEL_IF_SET_SA, ipsec_tunnel_if_set_sa)               \
64 _(IPSEC_SELECT_BACKEND, ipsec_select_backend)                   \
65 _(IPSEC_BACKEND_DUMP, ipsec_backend_dump)
66
67 static void
68 vl_api_ipsec_spd_add_del_t_handler (vl_api_ipsec_spd_add_del_t * mp)
69 {
70 #if WITH_LIBSSL == 0
71   clib_warning ("unimplemented");
72 #else
73
74   vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
75   vl_api_ipsec_spd_add_del_reply_t *rmp;
76   int rv;
77
78   rv = ipsec_add_del_spd (vm, ntohl (mp->spd_id), mp->is_add);
79
80   REPLY_MACRO (VL_API_IPSEC_SPD_ADD_DEL_REPLY);
81 #endif
82 }
83
84 static void vl_api_ipsec_interface_add_del_spd_t_handler
85   (vl_api_ipsec_interface_add_del_spd_t * mp)
86 {
87   vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
88   vl_api_ipsec_interface_add_del_spd_reply_t *rmp;
89   int rv;
90   u32 sw_if_index __attribute__ ((unused));
91   u32 spd_id __attribute__ ((unused));
92
93   sw_if_index = ntohl (mp->sw_if_index);
94   spd_id = ntohl (mp->spd_id);
95
96   VALIDATE_SW_IF_INDEX (mp);
97
98 #if WITH_LIBSSL > 0
99   rv = ipsec_set_interface_spd (vm, sw_if_index, spd_id, mp->is_add);
100 #else
101   rv = VNET_API_ERROR_UNIMPLEMENTED;
102 #endif
103
104   BAD_SW_IF_INDEX_LABEL;
105
106   REPLY_MACRO (VL_API_IPSEC_INTERFACE_ADD_DEL_SPD_REPLY);
107 }
108
109 static int
110 ipsec_spd_action_decode (vl_api_ipsec_spd_action_t in,
111                          ipsec_policy_action_t * out)
112 {
113   in = clib_net_to_host_u32 (in);
114
115   switch (in)
116     {
117 #define _(v,f,s) case IPSEC_API_SPD_ACTION_##f: \
118       *out = IPSEC_POLICY_ACTION_##f;              \
119       return (0);
120       foreach_ipsec_policy_action
121 #undef _
122     }
123   return (VNET_API_ERROR_UNIMPLEMENTED);
124 }
125
126 static void vl_api_ipsec_spd_entry_add_del_t_handler
127   (vl_api_ipsec_spd_entry_add_del_t * mp)
128 {
129   vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
130   vl_api_ipsec_spd_entry_add_del_reply_t *rmp;
131   ip46_type_t itype;
132   u32 stat_index;
133   int rv;
134
135   stat_index = ~0;
136
137 #if WITH_LIBSSL > 0
138   ipsec_policy_t p;
139
140   clib_memset (&p, 0, sizeof (p));
141
142   p.id = ntohl (mp->entry.spd_id);
143   p.priority = ntohl (mp->entry.priority);
144
145   itype = ip_address_decode (&mp->entry.remote_address_start, &p.raddr.start);
146   ip_address_decode (&mp->entry.remote_address_stop, &p.raddr.stop);
147   ip_address_decode (&mp->entry.local_address_start, &p.laddr.start);
148   ip_address_decode (&mp->entry.local_address_stop, &p.laddr.stop);
149
150   p.is_ipv6 = (itype == IP46_TYPE_IP6);
151
152   p.protocol = mp->entry.protocol;
153   p.rport.start = ntohs (mp->entry.remote_port_start);
154   p.rport.stop = ntohs (mp->entry.remote_port_stop);
155   p.lport.start = ntohs (mp->entry.local_port_start);
156   p.lport.stop = ntohs (mp->entry.local_port_stop);
157
158   rv = ipsec_spd_action_decode (mp->entry.policy, &p.policy);
159
160   if (rv)
161     goto out;
162
163   /* policy action resolve unsupported */
164   if (p.policy == IPSEC_POLICY_ACTION_RESOLVE)
165     {
166       clib_warning ("unsupported action: 'resolve'");
167       rv = VNET_API_ERROR_UNIMPLEMENTED;
168       goto out;
169     }
170   p.sa_id = ntohl (mp->entry.sa_id);
171   rv =
172     ipsec_policy_mk_type (mp->entry.is_outbound, p.is_ipv6, p.policy,
173                           &p.type);
174   if (rv)
175     goto out;
176
177   rv = ipsec_add_del_policy (vm, &p, mp->is_add, &stat_index);
178   if (rv)
179     goto out;
180
181 #else
182   rv = VNET_API_ERROR_UNIMPLEMENTED;
183   goto out;
184 #endif
185
186 out:
187   /* *INDENT-OFF* */
188   REPLY_MACRO2 (VL_API_IPSEC_SPD_ENTRY_ADD_DEL_REPLY,
189   ({
190     rmp->stat_index = ntohl(stat_index);
191   }));
192   /* *INDENT-ON* */
193 }
194
195 static int
196 ipsec_proto_decode (vl_api_ipsec_proto_t in, ipsec_protocol_t * out)
197 {
198   in = clib_net_to_host_u32 (in);
199
200   switch (in)
201     {
202     case IPSEC_API_PROTO_ESP:
203       *out = IPSEC_PROTOCOL_ESP;
204       return (0);
205     case IPSEC_API_PROTO_AH:
206       *out = IPSEC_PROTOCOL_AH;
207       return (0);
208     }
209   return (VNET_API_ERROR_UNIMPLEMENTED);
210 }
211
212 static vl_api_ipsec_proto_t
213 ipsec_proto_encode (ipsec_protocol_t p)
214 {
215   switch (p)
216     {
217     case IPSEC_PROTOCOL_ESP:
218       return clib_host_to_net_u32 (IPSEC_API_PROTO_ESP);
219     case IPSEC_PROTOCOL_AH:
220       return clib_host_to_net_u32 (IPSEC_API_PROTO_AH);
221     }
222   return (VNET_API_ERROR_UNIMPLEMENTED);
223 }
224
225 static int
226 ipsec_crypto_algo_decode (vl_api_ipsec_crypto_alg_t in,
227                           ipsec_crypto_alg_t * out)
228 {
229   in = clib_net_to_host_u32 (in);
230
231   switch (in)
232     {
233 #define _(v,f,s) case IPSEC_API_CRYPTO_ALG_##f: \
234       *out = IPSEC_CRYPTO_ALG_##f;              \
235       return (0);
236       foreach_ipsec_crypto_alg
237 #undef _
238     }
239   return (VNET_API_ERROR_UNIMPLEMENTED);
240 }
241
242 static vl_api_ipsec_crypto_alg_t
243 ipsec_crypto_algo_encode (ipsec_crypto_alg_t c)
244 {
245   switch (c)
246     {
247 #define _(v,f,s) case IPSEC_CRYPTO_ALG_##f:                     \
248       return clib_host_to_net_u32(IPSEC_API_CRYPTO_ALG_##f);
249       foreach_ipsec_crypto_alg
250 #undef _
251     case IPSEC_CRYPTO_N_ALG:
252       break;
253     }
254   ASSERT (0);
255   return (VNET_API_ERROR_UNIMPLEMENTED);
256 }
257
258
259 static int
260 ipsec_integ_algo_decode (vl_api_ipsec_integ_alg_t in, ipsec_integ_alg_t * out)
261 {
262   in = clib_net_to_host_u32 (in);
263
264   switch (in)
265     {
266 #define _(v,f,s) case IPSEC_API_INTEG_ALG_##f:  \
267       *out = IPSEC_INTEG_ALG_##f;               \
268       return (0);
269       foreach_ipsec_integ_alg
270 #undef _
271     }
272   return (VNET_API_ERROR_UNIMPLEMENTED);
273 }
274
275 static vl_api_ipsec_integ_alg_t
276 ipsec_integ_algo_encode (ipsec_integ_alg_t i)
277 {
278   switch (i)
279     {
280 #define _(v,f,s) case IPSEC_INTEG_ALG_##f:                      \
281       return (clib_host_to_net_u32(IPSEC_API_INTEG_ALG_##f));
282       foreach_ipsec_integ_alg
283 #undef _
284     case IPSEC_INTEG_N_ALG:
285       break;
286     }
287   ASSERT (0);
288   return (VNET_API_ERROR_UNIMPLEMENTED);
289 }
290
291 static void
292 ipsec_key_decode (const vl_api_key_t * key, ipsec_key_t * out)
293 {
294   ipsec_mk_key (out, key->data, key->length);
295 }
296
297 static void
298 ipsec_key_encode (const ipsec_key_t * in, vl_api_key_t * out)
299 {
300   out->length = in->len;
301   clib_memcpy (out->data, in->data, out->length);
302 }
303
304 static ipsec_sa_flags_t
305 ipsec_sa_flags_decode (vl_api_ipsec_sad_flags_t in)
306 {
307   ipsec_sa_flags_t flags = IPSEC_SA_FLAG_NONE;
308   in = clib_net_to_host_u32 (in);
309
310 #define _(v,f,s) if (in & IPSEC_API_SAD_FLAG_##f)    \
311     flags |= IPSEC_SA_FLAG_##f;
312   foreach_ipsec_sa_flags
313 #undef _
314     return (flags);
315 }
316
317 static vl_api_ipsec_sad_flags_t
318 ipsec_sad_flags_encode (const ipsec_sa_t * sa)
319 {
320   vl_api_ipsec_sad_flags_t flags = IPSEC_API_SAD_FLAG_NONE;
321
322   if (sa->use_esn)
323     flags |= IPSEC_API_SAD_FLAG_USE_EXTENDED_SEQ_NUM;
324   if (sa->use_anti_replay)
325     flags |= IPSEC_API_SAD_FLAG_USE_ANTI_REPLAY;
326   if (sa->is_tunnel)
327     flags |= IPSEC_API_SAD_FLAG_IS_TUNNEL;
328   if (sa->is_tunnel_ip6)
329     flags |= IPSEC_API_SAD_FLAG_IS_TUNNEL_V6;
330   if (sa->udp_encap)
331     flags |= IPSEC_API_SAD_FLAG_UDP_ENCAP;
332
333   return clib_host_to_net_u32 (flags);
334 }
335
336 static void vl_api_ipsec_sad_entry_add_del_t_handler
337   (vl_api_ipsec_sad_entry_add_del_t * mp)
338 {
339   vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
340   vl_api_ipsec_sad_entry_add_del_reply_t *rmp;
341   ip46_address_t tun_src = { }, tun_dst =
342   {
343   };
344   ipsec_key_t crypto_key, integ_key;
345   ipsec_crypto_alg_t crypto_alg;
346   ipsec_integ_alg_t integ_alg;
347   ipsec_protocol_t proto;
348   ipsec_sa_flags_t flags;
349   u32 id, spi, sa_index = ~0;
350   int rv;
351
352 #if WITH_LIBSSL > 0
353
354   id = ntohl (mp->entry.sad_id);
355   spi = ntohl (mp->entry.spi);
356
357   rv = ipsec_proto_decode (mp->entry.protocol, &proto);
358
359   if (rv)
360     goto out;
361
362   rv = ipsec_crypto_algo_decode (mp->entry.crypto_algorithm, &crypto_alg);
363
364   if (rv)
365     goto out;
366
367   rv = ipsec_integ_algo_decode (mp->entry.integrity_algorithm, &integ_alg);
368
369   if (rv)
370     goto out;
371
372   ipsec_key_decode (&mp->entry.crypto_key, &crypto_key);
373   ipsec_key_decode (&mp->entry.integrity_key, &integ_key);
374
375   flags = ipsec_sa_flags_decode (mp->entry.flags);
376
377   ip_address_decode (&mp->entry.tunnel_src, &tun_src);
378   ip_address_decode (&mp->entry.tunnel_dst, &tun_dst);
379
380
381   if (mp->is_add)
382     rv = ipsec_sa_add (id, spi, proto,
383                        crypto_alg, &crypto_key,
384                        integ_alg, &integ_key, flags,
385                        0, &tun_src, &tun_dst, &sa_index);
386   else
387     rv = ipsec_sa_del (id);
388
389 #else
390   rv = VNET_API_ERROR_UNIMPLEMENTED;
391 #endif
392
393 out:
394   /* *INDENT-OFF* */
395   REPLY_MACRO2 (VL_API_IPSEC_SAD_ENTRY_ADD_DEL_REPLY,
396   {
397     rmp->stat_index = htonl (sa_index);
398   });
399   /* *INDENT-ON* */
400 }
401
402 static void
403 send_ipsec_spds_details (ipsec_spd_t * spd, vl_api_registration_t * reg,
404                          u32 context)
405 {
406   vl_api_ipsec_spds_details_t *mp;
407   u32 n_policies = 0;
408
409   mp = vl_msg_api_alloc (sizeof (*mp));
410   clib_memset (mp, 0, sizeof (*mp));
411   mp->_vl_msg_id = ntohs (VL_API_IPSEC_SPDS_DETAILS);
412   mp->context = context;
413
414   mp->spd_id = htonl (spd->id);
415 #define _(s, n) n_policies += vec_len (spd->policies[IPSEC_SPD_POLICY_##s]);
416   foreach_ipsec_spd_policy_type
417 #undef _
418     mp->npolicies = htonl (n_policies);
419
420   vl_api_send_msg (reg, (u8 *) mp);
421 }
422
423 static void
424 vl_api_ipsec_spds_dump_t_handler (vl_api_ipsec_spds_dump_t * mp)
425 {
426   vl_api_registration_t *reg;
427   ipsec_main_t *im = &ipsec_main;
428   ipsec_spd_t *spd;
429 #if WITH_LIBSSL > 0
430   reg = vl_api_client_index_to_registration (mp->client_index);
431   if (!reg)
432     return;
433
434   /* *INDENT-OFF* */
435   pool_foreach (spd, im->spds, ({
436     send_ipsec_spds_details (spd, reg, mp->context);
437   }));
438   /* *INDENT-ON* */
439 #else
440   clib_warning ("unimplemented");
441 #endif
442 }
443
444 vl_api_ipsec_spd_action_t
445 ipsec_spd_action_encode (ipsec_policy_action_t in)
446 {
447   vl_api_ipsec_spd_action_t out = IPSEC_API_SPD_ACTION_BYPASS;
448
449   switch (in)
450     {
451 #define _(v,f,s) case IPSEC_POLICY_ACTION_##f: \
452       out = IPSEC_API_SPD_ACTION_##f;          \
453       break;
454       foreach_ipsec_policy_action
455 #undef _
456     }
457   return (clib_host_to_net_u32 (out));
458 }
459
460 static void
461 send_ipsec_spd_details (ipsec_policy_t * p, vl_api_registration_t * reg,
462                         u32 context)
463 {
464   vl_api_ipsec_spd_details_t *mp;
465
466   mp = vl_msg_api_alloc (sizeof (*mp));
467   clib_memset (mp, 0, sizeof (*mp));
468   mp->_vl_msg_id = ntohs (VL_API_IPSEC_SPD_DETAILS);
469   mp->context = context;
470
471   mp->entry.spd_id = htonl (p->id);
472   mp->entry.priority = htonl (p->priority);
473   mp->entry.is_outbound = ((p->type == IPSEC_SPD_POLICY_IP6_OUTBOUND) ||
474                            (p->type == IPSEC_SPD_POLICY_IP4_OUTBOUND));
475
476   ip_address_encode (&p->laddr.start, IP46_TYPE_ANY,
477                      &mp->entry.local_address_start);
478   ip_address_encode (&p->laddr.stop, IP46_TYPE_ANY,
479                      &mp->entry.local_address_stop);
480   ip_address_encode (&p->raddr.start, IP46_TYPE_ANY,
481                      &mp->entry.remote_address_start);
482   ip_address_encode (&p->raddr.stop, IP46_TYPE_ANY,
483                      &mp->entry.remote_address_stop);
484   mp->entry.local_port_start = htons (p->lport.start);
485   mp->entry.local_port_stop = htons (p->lport.stop);
486   mp->entry.remote_port_start = htons (p->rport.start);
487   mp->entry.remote_port_stop = htons (p->rport.stop);
488   mp->entry.protocol = p->protocol;
489   mp->entry.policy = ipsec_spd_action_encode (p->policy);
490   mp->entry.sa_id = htonl (p->sa_id);
491
492   vl_api_send_msg (reg, (u8 *) mp);
493 }
494
495 static void
496 vl_api_ipsec_spd_dump_t_handler (vl_api_ipsec_spd_dump_t * mp)
497 {
498   vl_api_registration_t *reg;
499   ipsec_main_t *im = &ipsec_main;
500   ipsec_spd_policy_type_t ptype;
501   ipsec_policy_t *policy;
502   ipsec_spd_t *spd;
503   uword *p;
504   u32 spd_index, *ii;
505 #if WITH_LIBSSL > 0
506   reg = vl_api_client_index_to_registration (mp->client_index);
507   if (!reg)
508     return;
509
510   p = hash_get (im->spd_index_by_spd_id, ntohl (mp->spd_id));
511   if (!p)
512     return;
513
514   spd_index = p[0];
515   spd = pool_elt_at_index (im->spds, spd_index);
516
517   /* *INDENT-OFF* */
518   FOR_EACH_IPSEC_SPD_POLICY_TYPE(ptype) {
519     vec_foreach(ii, spd->policies[ptype])
520       {
521         policy = pool_elt_at_index(im->policies, *ii);
522
523         if (mp->sa_id == ~(0) || ntohl (mp->sa_id) == policy->sa_id)
524           send_ipsec_spd_details (policy, reg, mp->context);
525       }
526   }
527   /* *INDENT-ON* */
528 #else
529   clib_warning ("unimplemented");
530 #endif
531 }
532
533 static void
534 send_ipsec_spd_interface_details (vl_api_registration_t * reg, u32 spd_index,
535                                   u32 sw_if_index, u32 context)
536 {
537   vl_api_ipsec_spd_interface_details_t *mp;
538
539   mp = vl_msg_api_alloc (sizeof (*mp));
540   clib_memset (mp, 0, sizeof (*mp));
541   mp->_vl_msg_id = ntohs (VL_API_IPSEC_SPD_INTERFACE_DETAILS);
542   mp->context = context;
543
544   mp->spd_index = htonl (spd_index);
545   mp->sw_if_index = htonl (sw_if_index);
546
547   vl_api_send_msg (reg, (u8 *) mp);
548 }
549
550 static void
551 vl_api_ipsec_spd_interface_dump_t_handler (vl_api_ipsec_spd_interface_dump_t *
552                                            mp)
553 {
554   ipsec_main_t *im = &ipsec_main;
555   vl_api_registration_t *reg;
556   u32 k, v, spd_index;
557
558 #if WITH_LIBSSL > 0
559   reg = vl_api_client_index_to_registration (mp->client_index);
560   if (!reg)
561     return;
562
563   if (mp->spd_index_valid)
564     {
565       spd_index = ntohl (mp->spd_index);
566       /* *INDENT-OFF* */
567       hash_foreach(k, v, im->spd_index_by_sw_if_index, ({
568         if (v == spd_index)
569           send_ipsec_spd_interface_details(reg, v, k, mp->context);
570       }));
571       /* *INDENT-ON* */
572     }
573   else
574     {
575       /* *INDENT-OFF* */
576       hash_foreach(k, v, im->spd_index_by_sw_if_index, ({
577         send_ipsec_spd_interface_details(reg, v, k, mp->context);
578       }));
579       /* *INDENT-ON* */
580     }
581
582 #else
583   clib_warning ("unimplemented");
584 #endif
585 }
586
587 static void
588 vl_api_ipsec_sa_set_key_t_handler (vl_api_ipsec_sa_set_key_t * mp)
589 {
590   vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
591   vl_api_ipsec_sa_set_key_reply_t *rmp;
592   ipsec_key_t ck, ik;
593   u32 id;
594   int rv;
595 #if WITH_LIBSSL > 0
596
597   id = ntohl (mp->sa_id);
598
599   ipsec_key_decode (&mp->crypto_key, &ck);
600   ipsec_key_decode (&mp->integrity_key, &ik);
601
602   rv = ipsec_set_sa_key (id, &ck, &ik);
603 #else
604   rv = VNET_API_ERROR_UNIMPLEMENTED;
605 #endif
606
607   REPLY_MACRO (VL_API_IPSEC_SA_SET_KEY_REPLY);
608 }
609
610 static void
611 vl_api_ipsec_tunnel_if_add_del_t_handler (vl_api_ipsec_tunnel_if_add_del_t *
612                                           mp)
613 {
614   vl_api_ipsec_tunnel_if_add_del_reply_t *rmp;
615   ipsec_main_t *im = &ipsec_main;
616   vnet_main_t *vnm = im->vnet_main;
617   u32 sw_if_index = ~0;
618   int rv;
619
620 #if WITH_LIBSSL > 0
621   ipsec_add_del_tunnel_args_t tun;
622
623   clib_memset (&tun, 0, sizeof (ipsec_add_del_tunnel_args_t));
624
625   tun.is_add = mp->is_add;
626   tun.esn = mp->esn;
627   tun.anti_replay = mp->anti_replay;
628   tun.local_spi = ntohl (mp->local_spi);
629   tun.remote_spi = ntohl (mp->remote_spi);
630   tun.crypto_alg = mp->crypto_alg;
631   tun.local_crypto_key_len = mp->local_crypto_key_len;
632   tun.remote_crypto_key_len = mp->remote_crypto_key_len;
633   tun.integ_alg = mp->integ_alg;
634   tun.local_integ_key_len = mp->local_integ_key_len;
635   tun.remote_integ_key_len = mp->remote_integ_key_len;
636   tun.udp_encap = mp->udp_encap;
637   tun.tx_table_id = ntohl (mp->tx_table_id);
638   memcpy (&tun.local_ip.ip4, mp->local_ip, 4);
639   memcpy (&tun.remote_ip.ip4, mp->remote_ip, 4);
640   memcpy (&tun.local_crypto_key, &mp->local_crypto_key,
641           mp->local_crypto_key_len);
642   memcpy (&tun.remote_crypto_key, &mp->remote_crypto_key,
643           mp->remote_crypto_key_len);
644   memcpy (&tun.local_integ_key, &mp->local_integ_key,
645           mp->local_integ_key_len);
646   memcpy (&tun.remote_integ_key, &mp->remote_integ_key,
647           mp->remote_integ_key_len);
648   tun.renumber = mp->renumber;
649   tun.show_instance = ntohl (mp->show_instance);
650
651   rv = ipsec_add_del_tunnel_if_internal (vnm, &tun, &sw_if_index);
652
653 #else
654   rv = VNET_API_ERROR_UNIMPLEMENTED;
655 #endif
656
657   /* *INDENT-OFF* */
658   REPLY_MACRO2 (VL_API_IPSEC_TUNNEL_IF_ADD_DEL_REPLY,
659   ({
660     rmp->sw_if_index = htonl (sw_if_index);
661   }));
662   /* *INDENT-ON* */
663 }
664
665 static void
666 send_ipsec_sa_details (ipsec_sa_t * sa, vl_api_registration_t * reg,
667                        u32 context, u32 sw_if_index)
668 {
669   vl_api_ipsec_sa_details_t *mp;
670
671   mp = vl_msg_api_alloc (sizeof (*mp));
672   clib_memset (mp, 0, sizeof (*mp));
673   mp->_vl_msg_id = ntohs (VL_API_IPSEC_SA_DETAILS);
674   mp->context = context;
675
676   mp->entry.sad_id = htonl (sa->id);
677   mp->entry.spi = htonl (sa->spi);
678   mp->entry.protocol = ipsec_proto_encode (sa->protocol);
679   mp->entry.tx_table_id =
680     htonl (fib_table_get_table_id (sa->tx_fib_index, FIB_PROTOCOL_IP4));
681
682   mp->entry.crypto_algorithm = ipsec_crypto_algo_encode (sa->crypto_alg);
683   ipsec_key_encode (&sa->crypto_key, &mp->entry.crypto_key);
684
685   mp->entry.integrity_algorithm = ipsec_integ_algo_encode (sa->integ_alg);
686   ipsec_key_encode (&sa->integ_key, &mp->entry.integrity_key);
687
688   mp->entry.flags = ipsec_sad_flags_encode (sa);
689
690   if (sa->is_tunnel)
691     {
692       ip_address_encode (&sa->tunnel_src_addr, IP46_TYPE_ANY,
693                          &mp->entry.tunnel_src);
694       ip_address_encode (&sa->tunnel_dst_addr, IP46_TYPE_ANY,
695                          &mp->entry.tunnel_dst);
696     }
697
698   mp->sw_if_index = htonl (sw_if_index);
699   mp->salt = clib_host_to_net_u32 (sa->salt);
700   mp->seq_outbound = clib_host_to_net_u64 (((u64) sa->seq));
701   mp->last_seq_inbound = clib_host_to_net_u64 (((u64) sa->last_seq));
702   if (sa->use_esn)
703     {
704       mp->seq_outbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
705       mp->last_seq_inbound |= (u64) (clib_host_to_net_u32 (sa->last_seq_hi));
706     }
707   if (sa->use_anti_replay)
708     mp->replay_window = clib_host_to_net_u64 (sa->replay_window);
709
710   vl_api_send_msg (reg, (u8 *) mp);
711 }
712
713
714 static void
715 vl_api_ipsec_sa_dump_t_handler (vl_api_ipsec_sa_dump_t * mp)
716 {
717   vl_api_registration_t *reg;
718   ipsec_main_t *im = &ipsec_main;
719   vnet_main_t *vnm = im->vnet_main;
720   ipsec_sa_t *sa;
721   ipsec_tunnel_if_t *t;
722   u32 *sa_index_to_tun_if_index = 0;
723
724 #if WITH_LIBSSL > 0
725   reg = vl_api_client_index_to_registration (mp->client_index);
726   if (!reg || pool_elts (im->sad) == 0)
727     return;
728
729   vec_validate_init_empty (sa_index_to_tun_if_index, vec_len (im->sad) - 1,
730                            ~0);
731
732   /* *INDENT-OFF* */
733   pool_foreach (t, im->tunnel_interfaces,
734   ({
735     vnet_hw_interface_t *hi;
736     u32 sw_if_index = ~0;
737
738     hi = vnet_get_hw_interface (vnm, t->hw_if_index);
739     sw_if_index = hi->sw_if_index;
740     sa_index_to_tun_if_index[t->input_sa_index] = sw_if_index;
741     sa_index_to_tun_if_index[t->output_sa_index] = sw_if_index;
742   }));
743
744   pool_foreach (sa, im->sad,
745   ({
746     if (mp->sa_id == ~(0) || ntohl (mp->sa_id) == sa->id)
747       send_ipsec_sa_details (sa, reg, mp->context,
748                              sa_index_to_tun_if_index[sa - im->sad]);
749   }));
750   /* *INDENT-ON* */
751
752   vec_free (sa_index_to_tun_if_index);
753 #else
754   clib_warning ("unimplemented");
755 #endif
756 }
757
758
759 static void
760 vl_api_ipsec_tunnel_if_set_key_t_handler (vl_api_ipsec_tunnel_if_set_key_t *
761                                           mp)
762 {
763   vl_api_ipsec_tunnel_if_set_key_reply_t *rmp;
764   ipsec_main_t *im = &ipsec_main;
765   vnet_main_t *vnm = im->vnet_main;
766   vnet_sw_interface_t *sw;
767   u8 *key = 0;
768   int rv;
769
770 #if WITH_LIBSSL > 0
771   sw = vnet_get_sw_interface (vnm, ntohl (mp->sw_if_index));
772
773   switch (mp->key_type)
774     {
775     case IPSEC_IF_SET_KEY_TYPE_LOCAL_CRYPTO:
776     case IPSEC_IF_SET_KEY_TYPE_REMOTE_CRYPTO:
777       if (mp->alg < IPSEC_CRYPTO_ALG_AES_CBC_128 ||
778           mp->alg >= IPSEC_CRYPTO_N_ALG)
779         {
780           rv = VNET_API_ERROR_UNIMPLEMENTED;
781           goto out;
782         }
783       break;
784     case IPSEC_IF_SET_KEY_TYPE_LOCAL_INTEG:
785     case IPSEC_IF_SET_KEY_TYPE_REMOTE_INTEG:
786       if (mp->alg >= IPSEC_INTEG_N_ALG)
787         {
788           rv = VNET_API_ERROR_UNIMPLEMENTED;
789           goto out;
790         }
791       break;
792     case IPSEC_IF_SET_KEY_TYPE_NONE:
793     default:
794       rv = VNET_API_ERROR_UNIMPLEMENTED;
795       goto out;
796       break;
797     }
798
799   key = vec_new (u8, mp->key_len);
800   clib_memcpy (key, mp->key, mp->key_len);
801
802   rv = ipsec_set_interface_key (vnm, sw->hw_if_index, mp->key_type, mp->alg,
803                                 key);
804   vec_free (key);
805 #else
806   clib_warning ("unimplemented");
807 #endif
808
809 out:
810   REPLY_MACRO (VL_API_IPSEC_TUNNEL_IF_SET_KEY_REPLY);
811 }
812
813
814 static void
815 vl_api_ipsec_tunnel_if_set_sa_t_handler (vl_api_ipsec_tunnel_if_set_sa_t * mp)
816 {
817   vl_api_ipsec_tunnel_if_set_sa_reply_t *rmp;
818   ipsec_main_t *im = &ipsec_main;
819   vnet_main_t *vnm = im->vnet_main;
820   vnet_sw_interface_t *sw;
821   int rv;
822
823 #if WITH_LIBSSL > 0
824   sw = vnet_get_sw_interface (vnm, ntohl (mp->sw_if_index));
825
826   rv = ipsec_set_interface_sa (vnm, sw->hw_if_index, ntohl (mp->sa_id),
827                                mp->is_outbound);
828 #else
829   clib_warning ("unimplemented");
830 #endif
831
832   REPLY_MACRO (VL_API_IPSEC_TUNNEL_IF_SET_SA_REPLY);
833 }
834
835 static void
836 vl_api_ipsec_backend_dump_t_handler (vl_api_ipsec_backend_dump_t * mp)
837 {
838   vl_api_registration_t *rp;
839   ipsec_main_t *im = &ipsec_main;
840   u32 context = mp->context;
841
842   rp = vl_api_client_index_to_registration (mp->client_index);
843
844   if (rp == 0)
845     {
846       clib_warning ("Client %d AWOL", mp->client_index);
847       return;
848     }
849
850   ipsec_ah_backend_t *ab;
851   ipsec_esp_backend_t *eb;
852   /* *INDENT-OFF* */
853   pool_foreach (ab, im->ah_backends, {
854     vl_api_ipsec_backend_details_t *mp = vl_msg_api_alloc (sizeof (*mp));
855     clib_memset (mp, 0, sizeof (*mp));
856     mp->_vl_msg_id = ntohs (VL_API_IPSEC_BACKEND_DETAILS);
857     mp->context = context;
858     snprintf ((char *)mp->name, sizeof (mp->name), "%.*s", vec_len (ab->name),
859               ab->name);
860     mp->protocol = ntohl (IPSEC_API_PROTO_AH);
861     mp->index = ab - im->ah_backends;
862     mp->active = mp->index == im->ah_current_backend ? 1 : 0;
863     vl_api_send_msg (rp, (u8 *)mp);
864   });
865   pool_foreach (eb, im->esp_backends, {
866     vl_api_ipsec_backend_details_t *mp = vl_msg_api_alloc (sizeof (*mp));
867     clib_memset (mp, 0, sizeof (*mp));
868     mp->_vl_msg_id = ntohs (VL_API_IPSEC_BACKEND_DETAILS);
869     mp->context = context;
870     snprintf ((char *)mp->name, sizeof (mp->name), "%.*s", vec_len (eb->name),
871               eb->name);
872     mp->protocol = ntohl (IPSEC_API_PROTO_ESP);
873     mp->index = eb - im->esp_backends;
874     mp->active = mp->index == im->esp_current_backend ? 1 : 0;
875     vl_api_send_msg (rp, (u8 *)mp);
876   });
877   /* *INDENT-ON* */
878 }
879
880 static void
881 vl_api_ipsec_select_backend_t_handler (vl_api_ipsec_select_backend_t * mp)
882 {
883   ipsec_main_t *im = &ipsec_main;
884   vl_api_ipsec_select_backend_reply_t *rmp;
885   ipsec_protocol_t protocol;
886   int rv = 0;
887   if (pool_elts (im->sad) > 0)
888     {
889       rv = VNET_API_ERROR_INSTANCE_IN_USE;
890       goto done;
891     }
892
893   rv = ipsec_proto_decode (mp->protocol, &protocol);
894
895   if (rv)
896     goto done;
897
898 #if WITH_LIBSSL > 0
899   switch (protocol)
900     {
901     case IPSEC_PROTOCOL_ESP:
902       if (pool_is_free_index (im->esp_backends, mp->index))
903         {
904           rv = VNET_API_ERROR_INVALID_VALUE;
905           break;
906         }
907       ipsec_select_esp_backend (im, mp->index);
908       break;
909     case IPSEC_PROTOCOL_AH:
910       if (pool_is_free_index (im->ah_backends, mp->index))
911         {
912           rv = VNET_API_ERROR_INVALID_VALUE;
913           break;
914         }
915       ipsec_select_ah_backend (im, mp->index);
916       break;
917     default:
918       rv = VNET_API_ERROR_INVALID_VALUE;
919       break;
920     }
921 #else
922   clib_warning ("unimplemented");       /* FIXME */
923 #endif
924 done:
925   REPLY_MACRO (VL_API_IPSEC_SELECT_BACKEND_REPLY);
926 }
927
928 /*
929  * ipsec_api_hookup
930  * Add vpe's API message handlers to the table.
931  * vlib has already mapped shared memory and
932  * added the client registration handlers.
933  * See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process()
934  */
935 #define vl_msg_name_crc_list
936 #include <vnet/vnet_all_api_h.h>
937 #undef vl_msg_name_crc_list
938
939 static void
940 setup_message_id_table (api_main_t * am)
941 {
942 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
943   foreach_vl_msg_name_crc_ipsec;
944 #undef _
945 }
946
947 static clib_error_t *
948 ipsec_api_hookup (vlib_main_t * vm)
949 {
950   api_main_t *am = &api_main;
951
952 #define _(N,n)                                                  \
953     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
954                            vl_api_##n##_t_handler,              \
955                            vl_noop_handler,                     \
956                            vl_api_##n##_t_endian,               \
957                            vl_api_##n##_t_print,                \
958                            sizeof(vl_api_##n##_t), 1);
959   foreach_vpe_api_msg;
960 #undef _
961
962   /*
963    * Set up the (msg_name, crc, message-id) table
964    */
965   setup_message_id_table (am);
966
967   return 0;
968 }
969
970 VLIB_API_INIT_FUNCTION (ipsec_api_hookup);
971
972 /*
973  * fd.io coding-style-patch-verification: ON
974  *
975  * Local Variables:
976  * eval: (c-set-style "gnu")
977  * End:
978  */