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