NAT: Buufer overflow for memcpy()
[vpp.git] / src / plugins / nat / nat64.c
1 /*
2  * Copyright (c) 2017 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /**
16  * @file
17  * @brief NAT64 implementation
18  */
19
20 #include <nat/nat64.h>
21 #include <nat/nat64_db.h>
22 #include <vnet/fib/ip4_fib.h>
23
24
25 nat64_main_t nat64_main;
26
27 /* *INDENT-OFF* */
28
29 /* Hook up input features */
30 VNET_FEATURE_INIT (nat64_in2out, static) = {
31   .arc_name = "ip6-unicast",
32   .node_name = "nat64-in2out",
33   .runs_before = VNET_FEATURES ("ip6-lookup"),
34 };
35 VNET_FEATURE_INIT (nat64_out2in, static) = {
36   .arc_name = "ip4-unicast",
37   .node_name = "nat64-out2in",
38   .runs_before = VNET_FEATURES ("ip4-lookup"),
39 };
40
41 static u8 well_known_prefix[] = {
42   0x00, 0x64, 0xff, 0x9b,
43   0x00, 0x00, 0x00, 0x00,
44   0x00, 0x00, 0x00, 0x00,
45   0x00, 0x00, 0x00, 0x00
46 };
47
48 /* *INDENT-ON* */
49
50 static void
51 nat64_ip4_add_del_interface_address_cb (ip4_main_t * im, uword opaque,
52                                         u32 sw_if_index,
53                                         ip4_address_t * address,
54                                         u32 address_length,
55                                         u32 if_address_index, u32 is_delete)
56 {
57   nat64_main_t *nm = &nat64_main;
58   int i, j;
59
60   for (i = 0; i < vec_len (nm->auto_add_sw_if_indices); i++)
61     {
62       if (sw_if_index == nm->auto_add_sw_if_indices[i])
63         {
64           if (!is_delete)
65             {
66               /* Don't trip over lease renewal, static config */
67               for (j = 0; j < vec_len (nm->addr_pool); j++)
68                 if (nm->addr_pool[j].addr.as_u32 == address->as_u32)
69                   return;
70
71               (void) nat64_add_del_pool_addr (address, ~0, 1);
72               return;
73             }
74           else
75             {
76               (void) nat64_add_del_pool_addr (address, ~0, 0);
77               return;
78             }
79         }
80     }
81 }
82
83 clib_error_t *
84 nat64_init (vlib_main_t * vm)
85 {
86   nat64_main_t *nm = &nat64_main;
87   clib_error_t *error = 0;
88   vlib_thread_main_t *tm = vlib_get_thread_main ();
89   ip4_add_del_interface_address_callback_t cb4;
90   ip4_main_t *im = &ip4_main;
91
92   nm->is_disabled = 0;
93
94   if (tm->n_vlib_mains > 1)
95     {
96       nm->is_disabled = 1;
97       goto error;
98     }
99
100   if (nat64_db_init (&nm->db))
101     {
102       error = clib_error_return (0, "NAT64 DB init failed");
103       goto error;
104     }
105
106   /* set session timeouts to default values */
107   nm->udp_timeout = SNAT_UDP_TIMEOUT;
108   nm->icmp_timeout = SNAT_ICMP_TIMEOUT;
109   nm->tcp_trans_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
110   nm->tcp_est_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
111   nm->tcp_incoming_syn_timeout = SNAT_TCP_INCOMING_SYN;
112
113   /* Set up the interface address add/del callback */
114   cb4.function = nat64_ip4_add_del_interface_address_cb;
115   cb4.function_opaque = 0;
116   vec_add1 (im->add_del_interface_address_callbacks, cb4);
117   nm->ip4_main = im;
118
119 error:
120   return error;
121 }
122
123 int
124 nat64_add_del_pool_addr (ip4_address_t * addr, u32 vrf_id, u8 is_add)
125 {
126   nat64_main_t *nm = &nat64_main;
127   snat_address_t *a = 0;
128   snat_interface_t *interface;
129   int i;
130
131   /* Check if address already exists */
132   for (i = 0; i < vec_len (nm->addr_pool); i++)
133     {
134       if (nm->addr_pool[i].addr.as_u32 == addr->as_u32)
135         {
136           a = nm->addr_pool + i;
137           break;
138         }
139     }
140
141   if (is_add)
142     {
143       if (a)
144         return VNET_API_ERROR_VALUE_EXIST;
145
146       vec_add2 (nm->addr_pool, a, 1);
147       a->addr = *addr;
148       a->fib_index = 0;
149       if (vrf_id != ~0)
150         a->fib_index =
151           fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id,
152                                              FIB_SOURCE_PLUGIN_HI);
153 #define _(N, i, n, s) \
154       clib_bitmap_alloc (a->busy_##n##_port_bitmap, 65535);
155       foreach_snat_protocol
156 #undef _
157     }
158   else
159     {
160       if (!a)
161         return VNET_API_ERROR_NO_SUCH_ENTRY;
162
163       if (a->fib_index)
164         fib_table_unlock (a->fib_index, FIB_PROTOCOL_IP6,
165                           FIB_SOURCE_PLUGIN_HI);
166
167 #define _(N, id, n, s) \
168       clib_bitmap_free (a->busy_##n##_port_bitmap);
169       foreach_snat_protocol
170 #undef _
171         /* Delete sessions using address */
172         nat64_db_free_out_addr (&nm->db, &a->addr);
173       vec_del1 (nm->addr_pool, i);
174     }
175
176   /* Add/del external address to FIB */
177   /* *INDENT-OFF* */
178   pool_foreach (interface, nm->interfaces,
179   ({
180     if (nat_interface_is_inside(interface))
181       continue;
182
183     snat_add_del_addr_to_fib (addr, 32, interface->sw_if_index, is_add);
184     break;
185   }));
186   /* *INDENT-ON* */
187
188   return 0;
189 }
190
191 void
192 nat64_pool_addr_walk (nat64_pool_addr_walk_fn_t fn, void *ctx)
193 {
194   nat64_main_t *nm = &nat64_main;
195   snat_address_t *a = 0;
196
197   /* *INDENT-OFF* */
198   vec_foreach (a, nm->addr_pool)
199     {
200       if (fn (a, ctx))
201         break;
202     };
203   /* *INDENT-ON* */
204 }
205
206 int
207 nat64_add_interface_address (u32 sw_if_index, int is_add)
208 {
209   nat64_main_t *nm = &nat64_main;
210   ip4_main_t *ip4_main = nm->ip4_main;
211   ip4_address_t *first_int_addr;
212   int i;
213
214   first_int_addr = ip4_interface_first_address (ip4_main, sw_if_index, 0);
215
216   for (i = 0; i < vec_len (nm->auto_add_sw_if_indices); i++)
217     {
218       if (nm->auto_add_sw_if_indices[i] == sw_if_index)
219         {
220           if (is_add)
221             return VNET_API_ERROR_VALUE_EXIST;
222           else
223             {
224               /* if have address remove it */
225               if (first_int_addr)
226                 (void) nat64_add_del_pool_addr (first_int_addr, ~0, 0);
227
228               vec_del1 (nm->auto_add_sw_if_indices, i);
229               return 0;
230             }
231         }
232     }
233
234   if (!is_add)
235     return VNET_API_ERROR_NO_SUCH_ENTRY;
236
237   /* add to the auto-address list */
238   vec_add1 (nm->auto_add_sw_if_indices, sw_if_index);
239
240   /* If the address is already bound - or static - add it now */
241   if (first_int_addr)
242     (void) nat64_add_del_pool_addr (first_int_addr, ~0, 1);
243
244   return 0;
245 }
246
247 int
248 nat64_add_del_interface (u32 sw_if_index, u8 is_inside, u8 is_add)
249 {
250   nat64_main_t *nm = &nat64_main;
251   snat_interface_t *interface = 0, *i;
252   snat_address_t *ap;
253   const char *feature_name, *arc_name;
254
255   /* Check if interface already exists */
256   /* *INDENT-OFF* */
257   pool_foreach (i, nm->interfaces,
258   ({
259     if (i->sw_if_index == sw_if_index)
260       {
261         interface = i;
262         break;
263       }
264   }));
265   /* *INDENT-ON* */
266
267   if (is_add)
268     {
269       if (interface)
270         goto set_flags;
271
272       pool_get (nm->interfaces, interface);
273       interface->sw_if_index = sw_if_index;
274       interface->flags = 0;
275     set_flags:
276       if (is_inside)
277         interface->flags |= NAT_INTERFACE_FLAG_IS_INSIDE;
278       else
279         interface->flags |= NAT_INTERFACE_FLAG_IS_OUTSIDE;
280     }
281   else
282     {
283       if (!interface)
284         return VNET_API_ERROR_NO_SUCH_ENTRY;
285
286       if ((nat_interface_is_inside (interface)
287            && nat_interface_is_outside (interface)))
288         interface->flags &=
289           is_inside ? ~NAT_INTERFACE_FLAG_IS_INSIDE :
290           ~NAT_INTERFACE_FLAG_IS_OUTSIDE;
291       else
292         pool_put (nm->interfaces, interface);
293     }
294
295   if (!is_inside)
296     {
297       /* *INDENT-OFF* */
298       vec_foreach (ap, nm->addr_pool)
299         snat_add_del_addr_to_fib(&ap->addr, 32, sw_if_index, is_add);
300       /* *INDENT-ON* */
301     }
302
303   arc_name = is_inside ? "ip6-unicast" : "ip4-unicast";
304   feature_name = is_inside ? "nat64-in2out" : "nat64-out2in";
305
306   return vnet_feature_enable_disable (arc_name, feature_name, sw_if_index,
307                                       is_add, 0, 0);
308 }
309
310 void
311 nat64_interfaces_walk (nat64_interface_walk_fn_t fn, void *ctx)
312 {
313   nat64_main_t *nm = &nat64_main;
314   snat_interface_t *i = 0;
315
316   /* *INDENT-OFF* */
317   pool_foreach (i, nm->interfaces,
318   ({
319     if (fn (i, ctx))
320       break;
321   }));
322   /* *INDENT-ON* */
323 }
324
325 int
326 nat64_alloc_out_addr_and_port (u32 fib_index, snat_protocol_t proto,
327                                ip4_address_t * addr, u16 * port)
328 {
329   nat64_main_t *nm = &nat64_main;
330   snat_main_t *sm = &snat_main;
331   int i;
332   snat_address_t *a, *ga = 0;
333   u32 portnum;
334
335   for (i = 0; i < vec_len (nm->addr_pool); i++)
336     {
337       a = nm->addr_pool + i;
338       switch (proto)
339         {
340 #define _(N, j, n, s) \
341         case SNAT_PROTOCOL_##N: \
342           if (a->busy_##n##_ports < (65535-1024)) \
343             { \
344               if (a->fib_index == fib_index) \
345                 { \
346                   while (1) \
347                     { \
348                       portnum = random_u32 (&sm->random_seed); \
349                       portnum &= 0xFFFF; \
350                       if (portnum < 1024) \
351                         continue; \
352                       if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
353                                                     portnum)) \
354                         continue; \
355                       clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
356                                                 portnum, 1); \
357                       a->busy_##n##_ports++; \
358                       *port = portnum; \
359                       addr->as_u32 = a->addr.as_u32; \
360                       return 0; \
361                     } \
362                  } \
363                else if (a->fib_index == 0) \
364                  ga = a; \
365             } \
366           break;
367           foreach_snat_protocol
368 #undef _
369         default:
370           clib_warning ("unknown protocol");
371           return 1;
372         }
373     }
374
375   if (ga)
376     {
377       switch (proto)
378         {
379 #define _(N, j, n, s) \
380         case SNAT_PROTOCOL_##N: \
381           while (1) \
382             { \
383               portnum = random_u32 (&sm->random_seed); \
384               portnum &= 0xFFFF; \
385               if (portnum < 1024) \
386                 continue; \
387               if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
388                                             portnum)) \
389                 continue; \
390               clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
391                                         portnum, 1); \
392               a->busy_##n##_ports++; \
393               *port = portnum; \
394               addr->as_u32 = a->addr.as_u32; \
395               return 0; \
396             }
397           break;
398           foreach_snat_protocol
399 #undef _
400         default:
401           clib_warning ("unknown protocol");
402           return 1;
403         }
404     }
405
406   /* Totally out of translations to use... */
407   //TODO: IPFix
408   return 1;
409 }
410
411 void
412 nat64_free_out_addr_and_port (ip4_address_t * addr, u16 port,
413                               snat_protocol_t proto)
414 {
415   nat64_main_t *nm = &nat64_main;
416   int i;
417   snat_address_t *a;
418
419   for (i = 0; i < vec_len (nm->addr_pool); i++)
420     {
421       a = nm->addr_pool + i;
422       if (addr->as_u32 != a->addr.as_u32)
423         continue;
424       switch (proto)
425         {
426 #define _(N, j, n, s) \
427         case SNAT_PROTOCOL_##N: \
428           ASSERT (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
429                   port) == 1); \
430           clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, port, 0); \
431           a->busy_##n##_ports--; \
432           break;
433           foreach_snat_protocol
434 #undef _
435         default:
436           clib_warning ("unknown protocol");
437           return;
438         }
439       break;
440     }
441 }
442
443 int
444 nat64_add_del_static_bib_entry (ip6_address_t * in_addr,
445                                 ip4_address_t * out_addr, u16 in_port,
446                                 u16 out_port, u8 proto, u32 vrf_id, u8 is_add)
447 {
448   nat64_main_t *nm = &nat64_main;
449   nat64_db_bib_entry_t *bibe;
450   u32 fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id,
451                                                      FIB_SOURCE_PLUGIN_HI);
452   snat_protocol_t p = ip_proto_to_snat_proto (proto);
453   ip46_address_t addr;
454   int i;
455   snat_address_t *a;
456
457   addr.as_u64[0] = in_addr->as_u64[0];
458   addr.as_u64[1] = in_addr->as_u64[1];
459   bibe =
460     nat64_db_bib_entry_find (&nm->db, &addr, clib_host_to_net_u16 (in_port),
461                              proto, fib_index, 1);
462
463   if (is_add)
464     {
465       if (bibe)
466         return VNET_API_ERROR_VALUE_EXIST;
467
468       for (i = 0; i < vec_len (nm->addr_pool); i++)
469         {
470           a = nm->addr_pool + i;
471           if (out_addr->as_u32 != a->addr.as_u32)
472             continue;
473           switch (p)
474             {
475 #define _(N, j, n, s) \
476             case SNAT_PROTOCOL_##N: \
477               if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
478                                             out_port)) \
479                 return VNET_API_ERROR_INVALID_VALUE; \
480               clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
481                                         out_port, 1); \
482               if (out_port > 1024) \
483                 a->busy_##n##_ports++; \
484               break;
485               foreach_snat_protocol
486 #undef _
487             default:
488               memset (&addr, 0, sizeof (addr));
489               addr.ip4.as_u32 = out_addr->as_u32;
490               if (nat64_db_bib_entry_find
491                   (&nm->db, &addr, 0, proto, fib_index, 0))
492                 return VNET_API_ERROR_INVALID_VALUE;
493             }
494           break;
495         }
496       bibe =
497         nat64_db_bib_entry_create (&nm->db, in_addr, out_addr,
498                                    clib_host_to_net_u16 (in_port),
499                                    clib_host_to_net_u16 (out_port), fib_index,
500                                    proto, 1);
501       if (!bibe)
502         return VNET_API_ERROR_UNSPECIFIED;
503     }
504   else
505     {
506       if (!bibe)
507         return VNET_API_ERROR_NO_SUCH_ENTRY;
508
509       nat64_free_out_addr_and_port (out_addr, out_port, p);
510       nat64_db_bib_entry_free (&nm->db, bibe);
511     }
512
513   return 0;
514 }
515
516 int
517 nat64_set_udp_timeout (u32 timeout)
518 {
519   nat64_main_t *nm = &nat64_main;
520
521   if (timeout == 0)
522     nm->udp_timeout = SNAT_UDP_TIMEOUT;
523   else if (timeout < SNAT_UDP_TIMEOUT_MIN)
524     return VNET_API_ERROR_INVALID_VALUE;
525   else
526     nm->udp_timeout = timeout;
527
528   return 0;
529 }
530
531 u32
532 nat64_get_udp_timeout (void)
533 {
534   nat64_main_t *nm = &nat64_main;
535
536   return nm->udp_timeout;
537 }
538
539 int
540 nat64_set_icmp_timeout (u32 timeout)
541 {
542   nat64_main_t *nm = &nat64_main;
543
544   if (timeout == 0)
545     nm->icmp_timeout = SNAT_ICMP_TIMEOUT;
546   else
547     nm->icmp_timeout = timeout;
548
549   return 0;
550 }
551
552 u32
553 nat64_get_icmp_timeout (void)
554 {
555   nat64_main_t *nm = &nat64_main;
556
557   return nm->icmp_timeout;
558 }
559
560 int
561 nat64_set_tcp_timeouts (u32 trans, u32 est, u32 incoming_syn)
562 {
563   nat64_main_t *nm = &nat64_main;
564
565   if (trans == 0)
566     nm->tcp_trans_timeout = SNAT_TCP_TRANSITORY_TIMEOUT;
567   else
568     nm->tcp_trans_timeout = trans;
569
570   if (est == 0)
571     nm->tcp_est_timeout = SNAT_TCP_ESTABLISHED_TIMEOUT;
572   else
573     nm->tcp_est_timeout = est;
574
575   if (incoming_syn == 0)
576     nm->tcp_incoming_syn_timeout = SNAT_TCP_INCOMING_SYN;
577   else
578     nm->tcp_incoming_syn_timeout = incoming_syn;
579
580   return 0;
581 }
582
583 u32
584 nat64_get_tcp_trans_timeout (void)
585 {
586   nat64_main_t *nm = &nat64_main;
587
588   return nm->tcp_trans_timeout;
589 }
590
591 u32
592 nat64_get_tcp_est_timeout (void)
593 {
594   nat64_main_t *nm = &nat64_main;
595
596   return nm->tcp_est_timeout;
597 }
598
599 u32
600 nat64_get_tcp_incoming_syn_timeout (void)
601 {
602   nat64_main_t *nm = &nat64_main;
603
604   return nm->tcp_incoming_syn_timeout;
605 }
606
607 void
608 nat64_session_reset_timeout (nat64_db_st_entry_t * ste, vlib_main_t * vm)
609 {
610   nat64_main_t *nm = &nat64_main;
611   u32 now = (u32) vlib_time_now (vm);
612
613   switch (ip_proto_to_snat_proto (ste->proto))
614     {
615     case SNAT_PROTOCOL_ICMP:
616       ste->expire = now + nm->icmp_timeout;
617       return;
618     case SNAT_PROTOCOL_TCP:
619       {
620         switch (ste->tcp_state)
621           {
622           case NAT64_TCP_STATE_V4_INIT:
623           case NAT64_TCP_STATE_V6_INIT:
624           case NAT64_TCP_STATE_V4_FIN_RCV:
625           case NAT64_TCP_STATE_V6_FIN_RCV:
626           case NAT64_TCP_STATE_V6_FIN_V4_FIN_RCV:
627           case NAT64_TCP_STATE_TRANS:
628             ste->expire = now + nm->tcp_trans_timeout;
629             return;
630           case NAT64_TCP_STATE_ESTABLISHED:
631             ste->expire = now + nm->tcp_est_timeout;
632             return;
633           default:
634             return;
635           }
636       }
637     case SNAT_PROTOCOL_UDP:
638       ste->expire = now + nm->udp_timeout;
639       return;
640     default:
641       ste->expire = now + nm->udp_timeout;
642       return;
643     }
644 }
645
646 void
647 nat64_tcp_session_set_state (nat64_db_st_entry_t * ste, tcp_header_t * tcp,
648                              u8 is_ip6)
649 {
650   switch (ste->tcp_state)
651     {
652     case NAT64_TCP_STATE_CLOSED:
653       {
654         if (tcp->flags & TCP_FLAG_SYN)
655           {
656             if (is_ip6)
657               ste->tcp_state = NAT64_TCP_STATE_V6_INIT;
658             else
659               ste->tcp_state = NAT64_TCP_STATE_V4_INIT;
660           }
661         return;
662       }
663     case NAT64_TCP_STATE_V4_INIT:
664       {
665         if (is_ip6 && (tcp->flags & TCP_FLAG_SYN))
666           ste->tcp_state = NAT64_TCP_STATE_ESTABLISHED;
667         return;
668       }
669     case NAT64_TCP_STATE_V6_INIT:
670       {
671         if (!is_ip6 && (tcp->flags & TCP_FLAG_SYN))
672           ste->tcp_state = NAT64_TCP_STATE_ESTABLISHED;
673         return;
674       }
675     case NAT64_TCP_STATE_ESTABLISHED:
676       {
677         if (tcp->flags & TCP_FLAG_FIN)
678           {
679             if (is_ip6)
680               ste->tcp_state = NAT64_TCP_STATE_V6_FIN_RCV;
681             else
682               ste->tcp_state = NAT64_TCP_STATE_V4_FIN_RCV;
683           }
684         else if (tcp->flags & TCP_FLAG_RST)
685           {
686             ste->tcp_state = NAT64_TCP_STATE_TRANS;
687           }
688         return;
689       }
690     case NAT64_TCP_STATE_V4_FIN_RCV:
691       {
692         if (is_ip6 && (tcp->flags & TCP_FLAG_FIN))
693           ste->tcp_state = NAT64_TCP_STATE_V6_FIN_V4_FIN_RCV;
694         return;
695       }
696     case NAT64_TCP_STATE_V6_FIN_RCV:
697       {
698         if (!is_ip6 && (tcp->flags & TCP_FLAG_FIN))
699           ste->tcp_state = NAT64_TCP_STATE_V6_FIN_V4_FIN_RCV;
700         return;
701       }
702     case NAT64_TCP_STATE_TRANS:
703       {
704         if (!(tcp->flags & TCP_FLAG_RST))
705           ste->tcp_state = NAT64_TCP_STATE_ESTABLISHED;
706         return;
707       }
708     default:
709       return;
710     }
711 }
712
713 int
714 nat64_add_del_prefix (ip6_address_t * prefix, u8 plen, u32 vrf_id, u8 is_add)
715 {
716   nat64_main_t *nm = &nat64_main;
717   nat64_prefix_t *p = 0;
718   int i;
719
720   /* Verify prefix length */
721   if (plen != 32 && plen != 40 && plen != 48 && plen != 56 && plen != 64
722       && plen != 96)
723     return VNET_API_ERROR_INVALID_VALUE;
724
725   /* Check if tenant already have prefix */
726   for (i = 0; i < vec_len (nm->pref64); i++)
727     {
728       if (nm->pref64[i].vrf_id == vrf_id)
729         {
730           p = nm->pref64 + i;
731           break;
732         }
733     }
734
735   if (is_add)
736     {
737       if (!p)
738         {
739           vec_add2 (nm->pref64, p, 1);
740           p->fib_index =
741             fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id,
742                                                FIB_SOURCE_PLUGIN_HI);
743           p->vrf_id = vrf_id;
744         }
745
746       p->prefix.as_u64[0] = prefix->as_u64[0];
747       p->prefix.as_u64[1] = prefix->as_u64[1];
748       p->plen = plen;
749     }
750   else
751     {
752       if (!p)
753         return VNET_API_ERROR_NO_SUCH_ENTRY;
754
755       vec_del1 (nm->pref64, i);
756     }
757
758   return 0;
759 }
760
761 void
762 nat64_prefix_walk (nat64_prefix_walk_fn_t fn, void *ctx)
763 {
764   nat64_main_t *nm = &nat64_main;
765   nat64_prefix_t *p = 0;
766
767   /* *INDENT-OFF* */
768   vec_foreach (p, nm->pref64)
769     {
770       if (fn (p, ctx))
771         break;
772     };
773   /* *INDENT-ON* */
774 }
775
776 void
777 nat64_compose_ip6 (ip6_address_t * ip6, ip4_address_t * ip4, u32 fib_index)
778 {
779   nat64_main_t *nm = &nat64_main;
780   nat64_prefix_t *p, *gp = 0, *prefix = 0;
781
782   /* *INDENT-OFF* */
783   vec_foreach (p, nm->pref64)
784     {
785       if (p->fib_index == fib_index)
786         {
787           prefix = p;
788           break;
789         }
790
791       if (p->fib_index == 0)
792         gp = p;
793     };
794   /* *INDENT-ON* */
795
796   if (!prefix)
797     prefix = gp;
798
799   if (prefix)
800     {
801       clib_memcpy (ip6, &p->prefix, sizeof (ip6_address_t));
802       switch (p->plen)
803         {
804         case 32:
805           ip6->as_u32[1] = ip4->as_u32;
806           break;
807         case 40:
808           ip6->as_u8[5] = ip4->as_u8[0];
809           ip6->as_u8[6] = ip4->as_u8[1];
810           ip6->as_u8[7] = ip4->as_u8[2];
811           ip6->as_u8[9] = ip4->as_u8[3];
812           break;
813         case 48:
814           ip6->as_u8[6] = ip4->as_u8[0];
815           ip6->as_u8[7] = ip4->as_u8[1];
816           ip6->as_u8[9] = ip4->as_u8[2];
817           ip6->as_u8[10] = ip4->as_u8[3];
818           break;
819         case 56:
820           ip6->as_u8[7] = ip4->as_u8[0];
821           ip6->as_u8[9] = ip4->as_u8[1];
822           ip6->as_u8[10] = ip4->as_u8[2];
823           ip6->as_u8[11] = ip4->as_u8[3];
824           break;
825         case 64:
826           ip6->as_u8[9] = ip4->as_u8[0];
827           ip6->as_u8[10] = ip4->as_u8[1];
828           ip6->as_u8[11] = ip4->as_u8[2];
829           ip6->as_u8[12] = ip4->as_u8[3];
830           break;
831         case 96:
832           ip6->as_u32[3] = ip4->as_u32;
833           break;
834         default:
835           clib_warning ("invalid prefix length");
836           break;
837         }
838     }
839   else
840     {
841       clib_memcpy (ip6, well_known_prefix, sizeof (ip6_address_t));
842       ip6->as_u32[3] = ip4->as_u32;
843     }
844 }
845
846 void
847 nat64_extract_ip4 (ip6_address_t * ip6, ip4_address_t * ip4, u32 fib_index)
848 {
849   nat64_main_t *nm = &nat64_main;
850   nat64_prefix_t *p, *gp = 0;
851   u8 plen = 0;
852
853   /* *INDENT-OFF* */
854   vec_foreach (p, nm->pref64)
855     {
856       if (p->fib_index == fib_index)
857         {
858           plen = p->plen;
859           break;
860         }
861
862       if (p->vrf_id == 0)
863         gp = p;
864     };
865   /* *INDENT-ON* */
866
867   if (!plen)
868     {
869       if (gp)
870         plen = gp->plen;
871       else
872         plen = 96;
873     }
874
875   switch (plen)
876     {
877     case 32:
878       ip4->as_u32 = ip6->as_u32[1];
879       break;
880     case 40:
881       ip4->as_u8[0] = ip6->as_u8[5];
882       ip4->as_u8[1] = ip6->as_u8[6];
883       ip4->as_u8[2] = ip6->as_u8[7];
884       ip4->as_u8[3] = ip6->as_u8[9];
885       break;
886     case 48:
887       ip4->as_u8[0] = ip6->as_u8[6];
888       ip4->as_u8[1] = ip6->as_u8[7];
889       ip4->as_u8[2] = ip6->as_u8[9];
890       ip4->as_u8[3] = ip6->as_u8[10];
891       break;
892     case 56:
893       ip4->as_u8[0] = ip6->as_u8[7];
894       ip4->as_u8[1] = ip6->as_u8[9];
895       ip4->as_u8[2] = ip6->as_u8[10];
896       ip4->as_u8[3] = ip6->as_u8[11];
897       break;
898     case 64:
899       ip4->as_u8[0] = ip6->as_u8[9];
900       ip4->as_u8[1] = ip6->as_u8[10];
901       ip4->as_u8[2] = ip6->as_u8[11];
902       ip4->as_u8[3] = ip6->as_u8[12];
903       break;
904     case 96:
905       ip4->as_u32 = ip6->as_u32[3];
906       break;
907     default:
908       clib_warning ("invalid prefix length");
909       break;
910     }
911 }
912
913 /**
914  * @brief The 'nat64-expire-walk' process's main loop.
915  *
916  * Check expire time for NAT64 sessions.
917  */
918 static uword
919 nat64_expire_walk_fn (vlib_main_t * vm, vlib_node_runtime_t * rt,
920                       vlib_frame_t * f)
921 {
922   nat64_main_t *nm = &nat64_main;
923
924   while (!nm->is_disabled)
925     {
926       vlib_process_wait_for_event_or_clock (vm, 10.0);
927       vlib_process_get_events (vm, NULL);
928       u32 now = (u32) vlib_time_now (vm);
929
930       nad64_db_st_free_expired (&nm->db, now);
931     }
932
933   return 0;
934 }
935
936 static vlib_node_registration_t nat64_expire_walk_node;
937
938 /* *INDENT-OFF* */
939 VLIB_REGISTER_NODE (nat64_expire_walk_node, static) = {
940     .function = nat64_expire_walk_fn,
941     .type = VLIB_NODE_TYPE_PROCESS,
942     .name = "nat64-expire-walk",
943 };
944 /* *INDENT-ON* */
945
946 /*
947  * fd.io coding-style-patch-verification: ON
948  *
949  * Local Variables:
950  * eval: (c-set-style "gnu")
951  * End:
952  */