]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netpfil/ipfw/nat64/nat64lsn.c
MFV r354378,r354379,r354386: 10499 Multi-modifier protection (MMP)
[FreeBSD/FreeBSD.git] / sys / netpfil / ipfw / nat64 / nat64lsn.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2015-2019 Yandex LLC
5  * Copyright (c) 2015 Alexander V. Chernikov <melifaro@FreeBSD.org>
6  * Copyright (c) 2016-2019 Andrey V. Elsukov <ae@FreeBSD.org>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/counter.h>
36 #include <sys/ck.h>
37 #include <sys/epoch.h>
38 #include <sys/errno.h>
39 #include <sys/hash.h>
40 #include <sys/kernel.h>
41 #include <sys/lock.h>
42 #include <sys/malloc.h>
43 #include <sys/mbuf.h>
44 #include <sys/module.h>
45 #include <sys/rmlock.h>
46 #include <sys/socket.h>
47 #include <sys/syslog.h>
48 #include <sys/sysctl.h>
49
50 #include <net/if.h>
51 #include <net/if_var.h>
52 #include <net/if_pflog.h>
53 #include <net/pfil.h>
54
55 #include <netinet/in.h>
56 #include <netinet/ip.h>
57 #include <netinet/ip_var.h>
58 #include <netinet/ip_fw.h>
59 #include <netinet/ip6.h>
60 #include <netinet/icmp6.h>
61 #include <netinet/ip_icmp.h>
62 #include <netinet/tcp.h>
63 #include <netinet/udp.h>
64 #include <netinet6/in6_var.h>
65 #include <netinet6/ip6_var.h>
66 #include <netinet6/ip_fw_nat64.h>
67
68 #include <netpfil/ipfw/ip_fw_private.h>
69 #include <netpfil/pf/pf.h>
70
71 #include "nat64lsn.h"
72
73 MALLOC_DEFINE(M_NAT64LSN, "NAT64LSN", "NAT64LSN");
74
75 #define NAT64LSN_EPOCH_ENTER(et)  NET_EPOCH_ENTER(et)
76 #define NAT64LSN_EPOCH_EXIT(et)   NET_EPOCH_EXIT(et)
77 #define NAT64LSN_EPOCH_ASSERT()   NET_EPOCH_ASSERT()
78 #define NAT64LSN_EPOCH_CALL(c, f) epoch_call(net_epoch_preempt, (c), (f))
79
80 static uma_zone_t nat64lsn_host_zone;
81 static uma_zone_t nat64lsn_pgchunk_zone;
82 static uma_zone_t nat64lsn_pg_zone;
83 static uma_zone_t nat64lsn_aliaslink_zone;
84 static uma_zone_t nat64lsn_state_zone;
85 static uma_zone_t nat64lsn_job_zone;
86
87 static void nat64lsn_periodic(void *data);
88 #define PERIODIC_DELAY          4
89 #define NAT64_LOOKUP(chain, cmd)        \
90         (struct nat64lsn_cfg *)SRV_OBJECT((chain), (cmd)->arg1)
91 /*
92  * Delayed job queue, used to create new hosts
93  * and new portgroups
94  */
95 enum nat64lsn_jtype {
96         JTYPE_NEWHOST = 1,
97         JTYPE_NEWPORTGROUP,
98         JTYPE_DESTROY,
99 };
100
101 struct nat64lsn_job_item {
102         STAILQ_ENTRY(nat64lsn_job_item) entries;
103         enum nat64lsn_jtype     jtype;
104
105         union {
106                 struct { /* used by JTYPE_NEWHOST, JTYPE_NEWPORTGROUP */
107                         struct mbuf             *m;
108                         struct nat64lsn_host    *host;
109                         struct nat64lsn_state   *state;
110                         uint32_t                src6_hval;
111                         uint32_t                state_hval;
112                         struct ipfw_flow_id     f_id;
113                         in_addr_t               faddr;
114                         uint16_t                port;
115                         uint8_t                 proto;
116                         uint8_t                 done;
117                 };
118                 struct { /* used by JTYPE_DESTROY */
119                         struct nat64lsn_hosts_slist     hosts;
120                         struct nat64lsn_pg_slist        portgroups;
121                         struct nat64lsn_pgchunk         *pgchunk;
122                         struct epoch_context            epoch_ctx;
123                 };
124         };
125 };
126
127 static struct mtx jmtx;
128 #define JQUEUE_LOCK_INIT()      mtx_init(&jmtx, "qlock", NULL, MTX_DEF)
129 #define JQUEUE_LOCK_DESTROY()   mtx_destroy(&jmtx)
130 #define JQUEUE_LOCK()           mtx_lock(&jmtx)
131 #define JQUEUE_UNLOCK()         mtx_unlock(&jmtx)
132
133 static int nat64lsn_alloc_host(struct nat64lsn_cfg *cfg,
134     struct nat64lsn_job_item *ji);
135 static int nat64lsn_alloc_pg(struct nat64lsn_cfg *cfg,
136     struct nat64lsn_job_item *ji);
137 static struct nat64lsn_job_item *nat64lsn_create_job(
138     struct nat64lsn_cfg *cfg, int jtype);
139 static void nat64lsn_enqueue_job(struct nat64lsn_cfg *cfg,
140     struct nat64lsn_job_item *ji);
141 static void nat64lsn_job_destroy(epoch_context_t ctx);
142 static void nat64lsn_destroy_host(struct nat64lsn_host *host);
143 static void nat64lsn_destroy_pg(struct nat64lsn_pg *pg);
144
145 static int nat64lsn_translate4(struct nat64lsn_cfg *cfg,
146     const struct ipfw_flow_id *f_id, struct mbuf **mp);
147 static int nat64lsn_translate6(struct nat64lsn_cfg *cfg,
148     struct ipfw_flow_id *f_id, struct mbuf **mp);
149 static int nat64lsn_translate6_internal(struct nat64lsn_cfg *cfg,
150     struct mbuf **mp, struct nat64lsn_state *state, uint8_t flags);
151
152 #define NAT64_BIT_TCP_FIN       0       /* FIN was seen */
153 #define NAT64_BIT_TCP_SYN       1       /* First syn in->out */
154 #define NAT64_BIT_TCP_ESTAB     2       /* Packet with Ack */
155 #define NAT64_BIT_READY_IPV4    6       /* state is ready for translate4 */
156 #define NAT64_BIT_STALE         7       /* state is going to be expired */
157
158 #define NAT64_FLAG_FIN          (1 << NAT64_BIT_TCP_FIN)
159 #define NAT64_FLAG_SYN          (1 << NAT64_BIT_TCP_SYN)
160 #define NAT64_FLAG_ESTAB        (1 << NAT64_BIT_TCP_ESTAB)
161 #define NAT64_FLAGS_TCP (NAT64_FLAG_SYN|NAT64_FLAG_ESTAB|NAT64_FLAG_FIN)
162
163 #define NAT64_FLAG_READY        (1 << NAT64_BIT_READY_IPV4)
164 #define NAT64_FLAG_STALE        (1 << NAT64_BIT_STALE)
165
166 static inline uint8_t
167 convert_tcp_flags(uint8_t flags)
168 {
169         uint8_t result;
170
171         result = flags & (TH_FIN|TH_SYN);
172         result |= (flags & TH_RST) >> 2; /* Treat RST as FIN */
173         result |= (flags & TH_ACK) >> 2; /* Treat ACK as estab */
174
175         return (result);
176 }
177
178 static void
179 nat64lsn_log(struct pfloghdr *plog, struct mbuf *m, sa_family_t family,
180     struct nat64lsn_state *state)
181 {
182
183         memset(plog, 0, sizeof(*plog));
184         plog->length = PFLOG_REAL_HDRLEN;
185         plog->af = family;
186         plog->action = PF_NAT;
187         plog->dir = PF_IN;
188         plog->rulenr = htonl(state->ip_src);
189         plog->subrulenr = htonl((uint32_t)(state->aport << 16) |
190             (state->proto << 8) | (state->ip_dst & 0xff));
191         plog->ruleset[0] = '\0';
192         strlcpy(plog->ifname, "NAT64LSN", sizeof(plog->ifname));
193         ipfw_bpf_mtap2(plog, PFLOG_HDRLEN, m);
194 }
195
196 #define HVAL(p, n, s)   jenkins_hash32((const uint32_t *)(p), (n), (s))
197 #define HOST_HVAL(c, a) HVAL((a),\
198     sizeof(struct in6_addr) / sizeof(uint32_t), (c)->hash_seed)
199 #define HOSTS(c, v)     ((c)->hosts_hash[(v) & ((c)->hosts_hashsize - 1)])
200
201 #define ALIASLINK_HVAL(c, f)    HVAL(&(f)->dst_ip6,\
202     sizeof(struct in6_addr) * 2 / sizeof(uint32_t), (c)->hash_seed)
203 #define ALIAS_BYHASH(c, v)      \
204     ((c)->aliases[(v) & ((1 << (32 - (c)->plen4)) - 1)])
205 static struct nat64lsn_aliaslink*
206 nat64lsn_get_aliaslink(struct nat64lsn_cfg *cfg __unused,
207     struct nat64lsn_host *host, const struct ipfw_flow_id *f_id __unused)
208 {
209
210         /*
211          * We can implement some different algorithms how
212          * select an alias address.
213          * XXX: for now we use first available.
214          */
215         return (CK_SLIST_FIRST(&host->aliases));
216 }
217
218 #define STATE_HVAL(c, d)        HVAL((d), 2, (c)->hash_seed)
219 #define STATE_HASH(h, v)        \
220     ((h)->states_hash[(v) & ((h)->states_hashsize - 1)])
221 #define STATES_CHUNK(p, v)      \
222     ((p)->chunks_count == 1 ? (p)->states : \
223         ((p)->states_chunk[CHUNK_BY_FADDR(p, v)]))
224
225 #ifdef __LP64__
226 #define FREEMASK_FFSLL(pg, faddr)               \
227     ffsll(*FREEMASK_CHUNK((pg), (faddr)))
228 #define FREEMASK_BTR(pg, faddr, bit)    \
229     ck_pr_btr_64(FREEMASK_CHUNK((pg), (faddr)), (bit))
230 #define FREEMASK_BTS(pg, faddr, bit)    \
231     ck_pr_bts_64(FREEMASK_CHUNK((pg), (faddr)), (bit))
232 #define FREEMASK_ISSET(pg, faddr, bit)  \
233     ISSET64(*FREEMASK_CHUNK((pg), (faddr)), (bit))
234 #define FREEMASK_COPY(pg, n, out)       \
235     (out) = ck_pr_load_64(FREEMASK_CHUNK((pg), (n)))
236 #else
237 static inline int
238 freemask_ffsll(uint32_t *freemask)
239 {
240         int i;
241
242         if ((i = ffsl(freemask[0])) != 0)
243                 return (i);
244         if ((i = ffsl(freemask[1])) != 0)
245                 return (i + 32);
246         return (0);
247 }
248 #define FREEMASK_FFSLL(pg, faddr)               \
249     freemask_ffsll(FREEMASK_CHUNK((pg), (faddr)))
250 #define FREEMASK_BTR(pg, faddr, bit)    \
251     ck_pr_btr_32(FREEMASK_CHUNK((pg), (faddr)) + (bit) / 32, (bit) % 32)
252 #define FREEMASK_BTS(pg, faddr, bit)    \
253     ck_pr_bts_32(FREEMASK_CHUNK((pg), (faddr)) + (bit) / 32, (bit) % 32)
254 #define FREEMASK_ISSET(pg, faddr, bit)  \
255     ISSET32(*(FREEMASK_CHUNK((pg), (faddr)) + (bit) / 32), (bit) % 32)
256 #define FREEMASK_COPY(pg, n, out)       \
257     (out) = ck_pr_load_32(FREEMASK_CHUNK((pg), (n))) | \
258         ((uint64_t)ck_pr_load_32(FREEMASK_CHUNK((pg), (n)) + 1) << 32)
259 #endif /* !__LP64__ */
260
261
262 #define NAT64LSN_TRY_PGCNT      32
263 static struct nat64lsn_pg*
264 nat64lsn_get_pg(uint32_t *chunkmask, uint32_t *pgmask,
265     struct nat64lsn_pgchunk **chunks, struct nat64lsn_pg **pgptr,
266     uint32_t *pgidx, in_addr_t faddr)
267 {
268         struct nat64lsn_pg *pg, *oldpg;
269         uint32_t idx, oldidx;
270         int cnt;
271
272         cnt = 0;
273         /* First try last used PG */
274         oldpg = pg = ck_pr_load_ptr(pgptr);
275         idx = oldidx = ck_pr_load_32(pgidx);
276         /* If pgidx is out of range, reset it to the first pgchunk */
277         if (!ISSET32(*chunkmask, idx / 32))
278                 idx = 0;
279         do {
280                 ck_pr_fence_load();
281                 if (pg != NULL && FREEMASK_BITCOUNT(pg, faddr) > 0) {
282                         /*
283                          * If last used PG has not free states,
284                          * try to update pointer.
285                          * NOTE: it can be already updated by jobs handler,
286                          *       thus we use CAS operation.
287                          */
288                         if (cnt > 0)
289                                 ck_pr_cas_ptr(pgptr, oldpg, pg);
290                         return (pg);
291                 }
292                 /* Stop if idx is out of range */
293                 if (!ISSET32(*chunkmask, idx / 32))
294                         break;
295
296                 if (ISSET32(pgmask[idx / 32], idx % 32))
297                         pg = ck_pr_load_ptr(
298                             &chunks[idx / 32]->pgptr[idx % 32]);
299                 else
300                         pg = NULL;
301
302                 idx++;
303         } while (++cnt < NAT64LSN_TRY_PGCNT);
304
305         /* If pgidx is out of range, reset it to the first pgchunk */
306         if (!ISSET32(*chunkmask, idx / 32))
307                 idx = 0;
308         ck_pr_cas_32(pgidx, oldidx, idx);
309         return (NULL);
310 }
311
312 static struct nat64lsn_state*
313 nat64lsn_get_state6to4(struct nat64lsn_cfg *cfg, struct nat64lsn_host *host,
314     const struct ipfw_flow_id *f_id, uint32_t hval, in_addr_t faddr,
315     uint16_t port, uint8_t proto)
316 {
317         struct nat64lsn_aliaslink *link;
318         struct nat64lsn_state *state;
319         struct nat64lsn_pg *pg;
320         int i, offset;
321
322         NAT64LSN_EPOCH_ASSERT();
323
324         /* Check that we already have state for given arguments */
325         CK_SLIST_FOREACH(state, &STATE_HASH(host, hval), entries) {
326                 if (state->proto == proto && state->ip_dst == faddr &&
327                     state->sport == port && state->dport == f_id->dst_port)
328                         return (state);
329         }
330
331         link = nat64lsn_get_aliaslink(cfg, host, f_id);
332         if (link == NULL)
333                 return (NULL);
334
335         switch (proto) {
336         case IPPROTO_TCP:
337                 pg = nat64lsn_get_pg(
338                     &link->alias->tcp_chunkmask, link->alias->tcp_pgmask,
339                     link->alias->tcp, &link->alias->tcp_pg,
340                     &link->alias->tcp_pgidx, faddr);
341                 break;
342         case IPPROTO_UDP:
343                 pg = nat64lsn_get_pg(
344                     &link->alias->udp_chunkmask, link->alias->udp_pgmask,
345                     link->alias->udp, &link->alias->udp_pg,
346                     &link->alias->udp_pgidx, faddr);
347                 break;
348         case IPPROTO_ICMP:
349                 pg = nat64lsn_get_pg(
350                     &link->alias->icmp_chunkmask, link->alias->icmp_pgmask,
351                     link->alias->icmp, &link->alias->icmp_pg,
352                     &link->alias->icmp_pgidx, faddr);
353                 break;
354         default:
355                 panic("%s: wrong proto %d", __func__, proto);
356         }
357         if (pg == NULL)
358                 return (NULL);
359
360         /* Check that PG has some free states */
361         state = NULL;
362         i = FREEMASK_BITCOUNT(pg, faddr);
363         while (i-- > 0) {
364                 offset = FREEMASK_FFSLL(pg, faddr);
365                 if (offset == 0) {
366                         /*
367                          * We lost the race.
368                          * No more free states in this PG.
369                          */
370                         break;
371                 }
372
373                 /* Lets try to atomically grab the state */
374                 if (FREEMASK_BTR(pg, faddr, offset - 1)) {
375                         state = &STATES_CHUNK(pg, faddr)->state[offset - 1];
376                         /* Initialize */
377                         state->flags = proto != IPPROTO_TCP ? 0 :
378                             convert_tcp_flags(f_id->_flags);
379                         state->proto = proto;
380                         state->aport = pg->base_port + offset - 1;
381                         state->dport = f_id->dst_port;
382                         state->sport = port;
383                         state->ip6_dst = f_id->dst_ip6;
384                         state->ip_dst = faddr;
385                         state->ip_src = link->alias->addr;
386                         state->hval = hval;
387                         state->host = host;
388                         SET_AGE(state->timestamp);
389
390                         /* Insert new state into host's hash table */
391                         HOST_LOCK(host);
392                         CK_SLIST_INSERT_HEAD(&STATE_HASH(host, hval),
393                             state, entries);
394                         host->states_count++;
395                         /*
396                          * XXX: In case if host is going to be expired,
397                          * reset NAT64LSN_DEADHOST flag.
398                          */
399                         host->flags &= ~NAT64LSN_DEADHOST;
400                         HOST_UNLOCK(host);
401                         NAT64STAT_INC(&cfg->base.stats, screated);
402                         /* Mark the state as ready for translate4 */
403                         ck_pr_fence_store();
404                         ck_pr_bts_32(&state->flags, NAT64_BIT_READY_IPV4);
405                         break;
406                 }
407         }
408         return (state);
409 }
410
411 /*
412  * Inspects icmp packets to see if the message contains different
413  * packet header so we need to alter @addr and @port.
414  */
415 static int
416 inspect_icmp_mbuf(struct mbuf **mp, uint8_t *proto, uint32_t *addr,
417     uint16_t *port)
418 {
419         struct icmp *icmp;
420         struct ip *ip;
421         int off;
422         uint8_t inner_proto;
423
424         ip = mtod(*mp, struct ip *); /* Outer IP header */
425         off = (ip->ip_hl << 2) + ICMP_MINLEN;
426         if ((*mp)->m_len < off)
427                 *mp = m_pullup(*mp, off);
428         if (*mp == NULL)
429                 return (ENOMEM);
430
431         ip = mtod(*mp, struct ip *); /* Outer IP header */
432         icmp = L3HDR(ip, struct icmp *);
433         switch (icmp->icmp_type) {
434         case ICMP_ECHO:
435         case ICMP_ECHOREPLY:
436                 /* Use icmp ID as distinguisher */
437                 *port = ntohs(icmp->icmp_id);
438                 return (0);
439         case ICMP_UNREACH:
440         case ICMP_TIMXCEED:
441                 break;
442         default:
443                 return (EOPNOTSUPP);
444         }
445         /*
446          * ICMP_UNREACH and ICMP_TIMXCEED contains IP header + 64 bits
447          * of ULP header.
448          */
449         if ((*mp)->m_pkthdr.len < off + sizeof(struct ip) + ICMP_MINLEN)
450                 return (EINVAL);
451         if ((*mp)->m_len < off + sizeof(struct ip) + ICMP_MINLEN)
452                 *mp = m_pullup(*mp, off + sizeof(struct ip) + ICMP_MINLEN);
453         if (*mp == NULL)
454                 return (ENOMEM);
455         ip = mtodo(*mp, off); /* Inner IP header */
456         inner_proto = ip->ip_p;
457         off += ip->ip_hl << 2; /* Skip inner IP header */
458         *addr = ntohl(ip->ip_src.s_addr);
459         if ((*mp)->m_len < off + ICMP_MINLEN)
460                 *mp = m_pullup(*mp, off + ICMP_MINLEN);
461         if (*mp == NULL)
462                 return (ENOMEM);
463         switch (inner_proto) {
464         case IPPROTO_TCP:
465         case IPPROTO_UDP:
466                 /* Copy source port from the header */
467                 *port = ntohs(*((uint16_t *)mtodo(*mp, off)));
468                 *proto = inner_proto;
469                 return (0);
470         case IPPROTO_ICMP:
471                 /*
472                  * We will translate only ICMP errors for our ICMP
473                  * echo requests.
474                  */
475                 icmp = mtodo(*mp, off);
476                 if (icmp->icmp_type != ICMP_ECHO)
477                         return (EOPNOTSUPP);
478                 *port = ntohs(icmp->icmp_id);
479                 return (0);
480         };
481         return (EOPNOTSUPP);
482 }
483
484 static struct nat64lsn_state*
485 nat64lsn_get_state4to6(struct nat64lsn_cfg *cfg, struct nat64lsn_alias *alias,
486     in_addr_t faddr, uint16_t port, uint8_t proto)
487 {
488         struct nat64lsn_state *state;
489         struct nat64lsn_pg *pg;
490         int chunk_idx, pg_idx, state_idx;
491
492         NAT64LSN_EPOCH_ASSERT();
493
494         if (port < NAT64_MIN_PORT)
495                 return (NULL);
496         /*
497          * Alias keeps 32 pgchunks for each protocol.
498          * Each pgchunk has 32 pointers to portgroup.
499          * Each portgroup has 64 states for ports.
500          */
501         port -= NAT64_MIN_PORT;
502         chunk_idx = port / 2048;
503
504         port -= chunk_idx * 2048;
505         pg_idx = port / 64;
506         state_idx = port % 64;
507
508         /*
509          * First check in proto_chunkmask that we have allocated PG chunk.
510          * Then check in proto_pgmask that we have valid PG pointer.
511          */
512         pg = NULL;
513         switch (proto) {
514         case IPPROTO_TCP:
515                 if (ISSET32(alias->tcp_chunkmask, chunk_idx) &&
516                     ISSET32(alias->tcp_pgmask[chunk_idx], pg_idx)) {
517                         pg = alias->tcp[chunk_idx]->pgptr[pg_idx];
518                         break;
519                 }
520                 return (NULL);
521         case IPPROTO_UDP:
522                 if (ISSET32(alias->udp_chunkmask, chunk_idx) &&
523                     ISSET32(alias->udp_pgmask[chunk_idx], pg_idx)) {
524                         pg = alias->udp[chunk_idx]->pgptr[pg_idx];
525                         break;
526                 }
527                 return (NULL);
528         case IPPROTO_ICMP:
529                 if (ISSET32(alias->icmp_chunkmask, chunk_idx) &&
530                     ISSET32(alias->icmp_pgmask[chunk_idx], pg_idx)) {
531                         pg = alias->icmp[chunk_idx]->pgptr[pg_idx];
532                         break;
533                 }
534                 return (NULL);
535         default:
536                 panic("%s: wrong proto %d", __func__, proto);
537         }
538         if (pg == NULL)
539                 return (NULL);
540
541         if (FREEMASK_ISSET(pg, faddr, state_idx))
542                 return (NULL);
543
544         state = &STATES_CHUNK(pg, faddr)->state[state_idx];
545         ck_pr_fence_load();
546         if (ck_pr_load_32(&state->flags) & NAT64_FLAG_READY)
547                 return (state);
548         return (NULL);
549 }
550
551 static int
552 nat64lsn_translate4(struct nat64lsn_cfg *cfg,
553     const struct ipfw_flow_id *f_id, struct mbuf **mp)
554 {
555         struct pfloghdr loghdr, *logdata;
556         struct in6_addr src6;
557         struct nat64lsn_state *state;
558         struct nat64lsn_alias *alias;
559         uint32_t addr, flags;
560         uint16_t port, ts;
561         int ret;
562         uint8_t proto;
563
564         addr = f_id->dst_ip;
565         port = f_id->dst_port;
566         proto = f_id->proto;
567         if (addr < cfg->prefix4 || addr > cfg->pmask4) {
568                 NAT64STAT_INC(&cfg->base.stats, nomatch4);
569                 return (cfg->nomatch_verdict);
570         }
571
572         /* Check if protocol is supported */
573         switch (proto) {
574         case IPPROTO_ICMP:
575                 ret = inspect_icmp_mbuf(mp, &proto, &addr, &port);
576                 if (ret != 0) {
577                         if (ret == ENOMEM) {
578                                 NAT64STAT_INC(&cfg->base.stats, nomem);
579                                 return (IP_FW_DENY);
580                         }
581                         NAT64STAT_INC(&cfg->base.stats, noproto);
582                         return (cfg->nomatch_verdict);
583                 }
584                 if (addr < cfg->prefix4 || addr > cfg->pmask4) {
585                         NAT64STAT_INC(&cfg->base.stats, nomatch4);
586                         return (cfg->nomatch_verdict);
587                 }
588                 /* FALLTHROUGH */
589         case IPPROTO_TCP:
590         case IPPROTO_UDP:
591                 break;
592         default:
593                 NAT64STAT_INC(&cfg->base.stats, noproto);
594                 return (cfg->nomatch_verdict);
595         }
596
597         alias = &ALIAS_BYHASH(cfg, addr);
598         MPASS(addr == alias->addr);
599
600         /* Check that we have state for this port */
601         state = nat64lsn_get_state4to6(cfg, alias, f_id->src_ip,
602             port, proto);
603         if (state == NULL) {
604                 NAT64STAT_INC(&cfg->base.stats, nomatch4);
605                 return (cfg->nomatch_verdict);
606         }
607
608         /* TODO: Check flags to see if we need to do some static mapping */
609
610         /* Update some state fields if need */
611         SET_AGE(ts);
612         if (f_id->proto == IPPROTO_TCP)
613                 flags = convert_tcp_flags(f_id->_flags);
614         else
615                 flags = 0;
616         if (state->timestamp != ts)
617                 state->timestamp = ts;
618         if ((state->flags & flags) != flags)
619                 state->flags |= flags;
620
621         port = htons(state->sport);
622         src6 = state->ip6_dst;
623
624         if (cfg->base.flags & NAT64_LOG) {
625                 logdata = &loghdr;
626                 nat64lsn_log(logdata, *mp, AF_INET, state);
627         } else
628                 logdata = NULL;
629
630         /*
631          * We already have src6 with embedded address, but it is possible,
632          * that src_ip is different than state->ip_dst, this is why we
633          * do embedding again.
634          */
635         nat64_embed_ip4(&src6, cfg->base.plat_plen, htonl(f_id->src_ip));
636         ret = nat64_do_handle_ip4(*mp, &src6, &state->host->addr, port,
637             &cfg->base, logdata);
638         if (ret == NAT64SKIP)
639                 return (cfg->nomatch_verdict);
640         if (ret == NAT64RETURN)
641                 *mp = NULL;
642         return (IP_FW_DENY);
643 }
644
645 /*
646  * Check if particular state is stale and should be deleted.
647  * Return 1 if true, 0 otherwise.
648  */
649 static int
650 nat64lsn_check_state(struct nat64lsn_cfg *cfg, struct nat64lsn_state *state)
651 {
652         int age, ttl;
653
654         /* State was marked as stale in previous pass. */
655         if (ISSET32(state->flags, NAT64_BIT_STALE))
656                 return (1);
657
658         /* State is not yet initialized, it is going to be READY */
659         if (!ISSET32(state->flags, NAT64_BIT_READY_IPV4))
660                 return (0);
661
662         age = GET_AGE(state->timestamp);
663         switch (state->proto) {
664         case IPPROTO_TCP:
665                 if (ISSET32(state->flags, NAT64_BIT_TCP_FIN))
666                         ttl = cfg->st_close_ttl;
667                 else if (ISSET32(state->flags, NAT64_BIT_TCP_ESTAB))
668                         ttl = cfg->st_estab_ttl;
669                 else if (ISSET32(state->flags, NAT64_BIT_TCP_SYN))
670                         ttl = cfg->st_syn_ttl;
671                 else
672                         ttl = cfg->st_syn_ttl;
673                 if (age > ttl)
674                         return (1);
675                 break;
676         case IPPROTO_UDP:
677                 if (age > cfg->st_udp_ttl)
678                         return (1);
679                 break;
680         case IPPROTO_ICMP:
681                 if (age > cfg->st_icmp_ttl)
682                         return (1);
683                 break;
684         }
685         return (0);
686 }
687
688 static int
689 nat64lsn_maintain_pg(struct nat64lsn_cfg *cfg, struct nat64lsn_pg *pg)
690 {
691         struct nat64lsn_state *state;
692         struct nat64lsn_host *host;
693         uint64_t freemask;
694         int c, i, update_age;
695
696         update_age = 0;
697         for (c = 0; c < pg->chunks_count; c++) {
698                 FREEMASK_COPY(pg, c, freemask);
699                 for (i = 0; i < 64; i++) {
700                         if (ISSET64(freemask, i))
701                                 continue;
702                         state = &STATES_CHUNK(pg, c)->state[i];
703                         if (nat64lsn_check_state(cfg, state) == 0) {
704                                 update_age = 1;
705                                 continue;
706                         }
707                         /*
708                          * Expire state:
709                          * 1. Mark as STALE and unlink from host's hash.
710                          * 2. Set bit in freemask.
711                          */
712                         if (ISSET32(state->flags, NAT64_BIT_STALE)) {
713                                 /*
714                                  * State was marked as STALE in previous
715                                  * pass. Now it is safe to release it.
716                                  */
717                                 state->flags = 0;
718                                 ck_pr_fence_store();
719                                 FREEMASK_BTS(pg, c, i);
720                                 NAT64STAT_INC(&cfg->base.stats, sdeleted);
721                                 continue;
722                         }
723                         MPASS(state->flags & NAT64_FLAG_READY);
724
725                         host = state->host;
726                         HOST_LOCK(host);
727                         CK_SLIST_REMOVE(&STATE_HASH(host, state->hval),
728                             state, nat64lsn_state, entries);
729                         host->states_count--;
730                         HOST_UNLOCK(host);
731
732                         /* Reset READY flag */
733                         ck_pr_btr_32(&state->flags, NAT64_BIT_READY_IPV4);
734                         /* And set STALE flag */
735                         ck_pr_bts_32(&state->flags, NAT64_BIT_STALE);
736                         ck_pr_fence_store();
737                         /*
738                          * Now translate6 will not use this state, wait
739                          * until it become safe for translate4, then mark
740                          * state as free.
741                          */
742                 }
743         }
744
745         /*
746          * We have some alive states, update timestamp.
747          */
748         if (update_age)
749                 SET_AGE(pg->timestamp);
750
751         if (GET_AGE(pg->timestamp) < cfg->pg_delete_delay)
752                 return (0);
753
754         return (1);
755 }
756
757 static void
758 nat64lsn_expire_portgroups(struct nat64lsn_cfg *cfg,
759     struct nat64lsn_pg_slist *portgroups)
760 {
761         struct nat64lsn_alias *alias;
762         struct nat64lsn_pg *pg, *tpg, *firstpg, **pgptr;
763         uint32_t *pgmask, *pgidx;
764         int i, idx;
765
766         for (i = 0; i < 1 << (32 - cfg->plen4); i++) {
767                 alias = &cfg->aliases[i];
768                 CK_SLIST_FOREACH_SAFE(pg, &alias->portgroups, entries, tpg) {
769                         if (nat64lsn_maintain_pg(cfg, pg) == 0)
770                                 continue;
771                         /* Always keep first PG */
772                         if (pg->base_port == NAT64_MIN_PORT)
773                                 continue;
774                         /*
775                          * PG is expired, unlink it and schedule for
776                          * deferred destroying.
777                          */
778                         idx = (pg->base_port - NAT64_MIN_PORT) / 64;
779                         switch (pg->proto) {
780                         case IPPROTO_TCP:
781                                 pgmask = alias->tcp_pgmask;
782                                 pgptr = &alias->tcp_pg;
783                                 pgidx = &alias->tcp_pgidx;
784                                 firstpg = alias->tcp[0]->pgptr[0];
785                                 break;
786                         case IPPROTO_UDP:
787                                 pgmask = alias->udp_pgmask;
788                                 pgptr = &alias->udp_pg;
789                                 pgidx = &alias->udp_pgidx;
790                                 firstpg = alias->udp[0]->pgptr[0];
791                                 break;
792                         case IPPROTO_ICMP:
793                                 pgmask = alias->icmp_pgmask;
794                                 pgptr = &alias->icmp_pg;
795                                 pgidx = &alias->icmp_pgidx;
796                                 firstpg = alias->icmp[0]->pgptr[0];
797                                 break;
798                         }
799                         /* Reset the corresponding bit in pgmask array. */
800                         ck_pr_btr_32(&pgmask[idx / 32], idx % 32);
801                         ck_pr_fence_store();
802                         /* If last used PG points to this PG, reset it. */
803                         ck_pr_cas_ptr(pgptr, pg, firstpg);
804                         ck_pr_cas_32(pgidx, idx, 0);
805                         /* Unlink PG from alias's chain */
806                         ALIAS_LOCK(alias);
807                         CK_SLIST_REMOVE(&alias->portgroups, pg,
808                             nat64lsn_pg, entries);
809                         alias->portgroups_count--;
810                         ALIAS_UNLOCK(alias);
811                         /* And link to job's chain for deferred destroying */
812                         NAT64STAT_INC(&cfg->base.stats, spgdeleted);
813                         CK_SLIST_INSERT_HEAD(portgroups, pg, entries);
814                 }
815         }
816 }
817
818 static void
819 nat64lsn_expire_hosts(struct nat64lsn_cfg *cfg,
820     struct nat64lsn_hosts_slist *hosts)
821 {
822         struct nat64lsn_host *host, *tmp;
823         int i;
824
825         for (i = 0; i < cfg->hosts_hashsize; i++) {
826                 CK_SLIST_FOREACH_SAFE(host, &cfg->hosts_hash[i],
827                     entries, tmp) {
828                         /* Is host was marked in previous call? */
829                         if (host->flags & NAT64LSN_DEADHOST) {
830                                 if (host->states_count > 0) {
831                                         host->flags &= ~NAT64LSN_DEADHOST;
832                                         continue;
833                                 }
834                                 /*
835                                  * Unlink host from hash table and schedule
836                                  * it for deferred destroying.
837                                  */
838                                 CFG_LOCK(cfg);
839                                 CK_SLIST_REMOVE(&cfg->hosts_hash[i], host,
840                                     nat64lsn_host, entries);
841                                 cfg->hosts_count--;
842                                 CFG_UNLOCK(cfg);
843                                 CK_SLIST_INSERT_HEAD(hosts, host, entries);
844                                 continue;
845                         }
846                         if (GET_AGE(host->timestamp) < cfg->host_delete_delay)
847                                 continue;
848                         if (host->states_count > 0)
849                                 continue;
850                         /* Mark host as going to be expired in next pass */
851                         host->flags |= NAT64LSN_DEADHOST;
852                         ck_pr_fence_store();
853                 }
854         }
855 }
856
857 static struct nat64lsn_pgchunk*
858 nat64lsn_expire_pgchunk(struct nat64lsn_cfg *cfg)
859 {
860 #if 0
861         struct nat64lsn_alias *alias;
862         struct nat64lsn_pgchunk *chunk;
863         uint32_t pgmask;
864         int i, c;
865
866         for (i = 0; i < 1 << (32 - cfg->plen4); i++) {
867                 alias = &cfg->aliases[i];
868                 if (GET_AGE(alias->timestamp) < cfg->pgchunk_delete_delay)
869                         continue;
870                 /* Always keep single chunk allocated */
871                 for (c = 1; c < 32; c++) {
872                         if ((alias->tcp_chunkmask & (1 << c)) == 0)
873                                 break;
874                         chunk = ck_pr_load_ptr(&alias->tcp[c]);
875                         if (ck_pr_load_32(&alias->tcp_pgmask[c]) != 0)
876                                 continue;
877                         ck_pr_btr_32(&alias->tcp_chunkmask, c);
878                         ck_pr_fence_load();
879                         if (ck_pr_load_32(&alias->tcp_pgmask[c]) != 0)
880                                 continue;
881                 }
882         }
883 #endif
884         return (NULL);
885 }
886
887 #if 0
888 static void
889 nat64lsn_maintain_hosts(struct nat64lsn_cfg *cfg)
890 {
891         struct nat64lsn_host *h;
892         struct nat64lsn_states_slist *hash;
893         int i, j, hsize;
894
895         for (i = 0; i < cfg->hosts_hashsize; i++) {
896                 CK_SLIST_FOREACH(h, &cfg->hosts_hash[i], entries) {
897                          if (h->states_count / 2 < h->states_hashsize ||
898                              h->states_hashsize >= NAT64LSN_MAX_HSIZE)
899                                  continue;
900                          hsize = h->states_hashsize * 2;
901                          hash = malloc(sizeof(*hash)* hsize, M_NOWAIT);
902                          if (hash == NULL)
903                                  continue;
904                          for (j = 0; j < hsize; j++)
905                                 CK_SLIST_INIT(&hash[i]);
906
907                          ck_pr_bts_32(&h->flags, NAT64LSN_GROWHASH);
908                 }
909         }
910 }
911 #endif
912
913 /*
914  * This procedure is used to perform various maintance
915  * on dynamic hash list. Currently it is called every 4 seconds.
916  */
917 static void
918 nat64lsn_periodic(void *data)
919 {
920         struct nat64lsn_job_item *ji;
921         struct nat64lsn_cfg *cfg;
922
923         cfg = (struct nat64lsn_cfg *) data;
924         CURVNET_SET(cfg->vp);
925         if (cfg->hosts_count > 0) {
926                 ji = uma_zalloc(nat64lsn_job_zone, M_NOWAIT);
927                 if (ji != NULL) {
928                         ji->jtype = JTYPE_DESTROY;
929                         CK_SLIST_INIT(&ji->hosts);
930                         CK_SLIST_INIT(&ji->portgroups);
931                         nat64lsn_expire_hosts(cfg, &ji->hosts);
932                         nat64lsn_expire_portgroups(cfg, &ji->portgroups);
933                         ji->pgchunk = nat64lsn_expire_pgchunk(cfg);
934                         NAT64LSN_EPOCH_CALL(&ji->epoch_ctx,
935                             nat64lsn_job_destroy);
936                 } else
937                         NAT64STAT_INC(&cfg->base.stats, jnomem);
938         }
939         callout_schedule(&cfg->periodic, hz * PERIODIC_DELAY);
940         CURVNET_RESTORE();
941 }
942
943 #define ALLOC_ERROR(stage, type)        ((stage) ? 10 * (type) + (stage): 0)
944 #define HOST_ERROR(stage)               ALLOC_ERROR(stage, 1)
945 #define PG_ERROR(stage)                 ALLOC_ERROR(stage, 2)
946 static int
947 nat64lsn_alloc_host(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
948 {
949         char a[INET6_ADDRSTRLEN];
950         struct nat64lsn_aliaslink *link;
951         struct nat64lsn_host *host;
952         struct nat64lsn_state *state;
953         uint32_t hval, data[2];
954         int i;
955
956         /* Check that host was not yet added. */
957         NAT64LSN_EPOCH_ASSERT();
958         CK_SLIST_FOREACH(host, &HOSTS(cfg, ji->src6_hval), entries) {
959                 if (IN6_ARE_ADDR_EQUAL(&ji->f_id.src_ip6, &host->addr)) {
960                         /* The host was allocated in previous call. */
961                         ji->host = host;
962                         goto get_state;
963                 }
964         }
965
966         host = ji->host = uma_zalloc(nat64lsn_host_zone, M_NOWAIT);
967         if (ji->host == NULL)
968                 return (HOST_ERROR(1));
969
970         host->states_hashsize = NAT64LSN_HSIZE;
971         host->states_hash = malloc(sizeof(struct nat64lsn_states_slist) *
972             host->states_hashsize, M_NAT64LSN, M_NOWAIT);
973         if (host->states_hash == NULL) {
974                 uma_zfree(nat64lsn_host_zone, host);
975                 return (HOST_ERROR(2));
976         }
977
978         link = uma_zalloc(nat64lsn_aliaslink_zone, M_NOWAIT);
979         if (link == NULL) {
980                 free(host->states_hash, M_NAT64LSN);
981                 uma_zfree(nat64lsn_host_zone, host);
982                 return (HOST_ERROR(3));
983         }
984
985         /* Initialize */
986         HOST_LOCK_INIT(host);
987         SET_AGE(host->timestamp);
988         host->addr = ji->f_id.src_ip6;
989         host->hval = ji->src6_hval;
990         host->flags = 0;
991         host->states_count = 0;
992         host->states_hashsize = NAT64LSN_HSIZE;
993         CK_SLIST_INIT(&host->aliases);
994         for (i = 0; i < host->states_hashsize; i++)
995                 CK_SLIST_INIT(&host->states_hash[i]);
996
997         /* Determine alias from flow hash. */
998         hval = ALIASLINK_HVAL(cfg, &ji->f_id);
999         link->alias = &ALIAS_BYHASH(cfg, hval);
1000         CK_SLIST_INSERT_HEAD(&host->aliases, link, host_entries);
1001
1002         ALIAS_LOCK(link->alias);
1003         CK_SLIST_INSERT_HEAD(&link->alias->hosts, link, alias_entries);
1004         link->alias->hosts_count++;
1005         ALIAS_UNLOCK(link->alias);
1006
1007         CFG_LOCK(cfg);
1008         CK_SLIST_INSERT_HEAD(&HOSTS(cfg, ji->src6_hval), host, entries);
1009         cfg->hosts_count++;
1010         CFG_UNLOCK(cfg);
1011
1012 get_state:
1013         data[0] = ji->faddr;
1014         data[1] = (ji->f_id.dst_port << 16) | ji->port;
1015         ji->state_hval = hval = STATE_HVAL(cfg, data);
1016         state = nat64lsn_get_state6to4(cfg, host, &ji->f_id, hval,
1017             ji->faddr, ji->port, ji->proto);
1018         /*
1019          * We failed to obtain new state, used alias needs new PG.
1020          * XXX: or another alias should be used.
1021          */
1022         if (state == NULL) {
1023                 /* Try to allocate new PG */
1024                 if (nat64lsn_alloc_pg(cfg, ji) != PG_ERROR(0))
1025                         return (HOST_ERROR(4));
1026                 /* We assume that nat64lsn_alloc_pg() got state */
1027         } else
1028                 ji->state = state;
1029
1030         ji->done = 1;
1031         DPRINTF(DP_OBJ, "ALLOC HOST %s %p",
1032             inet_ntop(AF_INET6, &host->addr, a, sizeof(a)), host);
1033         return (HOST_ERROR(0));
1034 }
1035
1036 static int
1037 nat64lsn_find_pg_place(uint32_t *data)
1038 {
1039         int i;
1040
1041         for (i = 0; i < 32; i++) {
1042                 if (~data[i] == 0)
1043                         continue;
1044                 return (i * 32 + ffs(~data[i]) - 1);
1045         }
1046         return (-1);
1047 }
1048
1049 static int
1050 nat64lsn_alloc_proto_pg(struct nat64lsn_cfg *cfg,
1051     struct nat64lsn_alias *alias, uint32_t *chunkmask,
1052     uint32_t *pgmask, struct nat64lsn_pgchunk **chunks,
1053     struct nat64lsn_pg **pgptr, uint8_t proto)
1054 {
1055         struct nat64lsn_pg *pg;
1056         int i, pg_idx, chunk_idx;
1057
1058         /* Find place in pgchunk where PG can be added */
1059         pg_idx = nat64lsn_find_pg_place(pgmask);
1060         if (pg_idx < 0) /* no more PGs */
1061                 return (PG_ERROR(1));
1062         /* Check that we have allocated pgchunk for given PG index */
1063         chunk_idx = pg_idx / 32;
1064         if (!ISSET32(*chunkmask, chunk_idx)) {
1065                 chunks[chunk_idx] = uma_zalloc(nat64lsn_pgchunk_zone,
1066                     M_NOWAIT);
1067                 if (chunks[chunk_idx] == NULL)
1068                         return (PG_ERROR(2));
1069                 ck_pr_bts_32(chunkmask, chunk_idx);
1070                 ck_pr_fence_store();
1071         }
1072         /* Allocate PG and states chunks */
1073         pg = uma_zalloc(nat64lsn_pg_zone, M_NOWAIT);
1074         if (pg == NULL)
1075                 return (PG_ERROR(3));
1076         pg->chunks_count = cfg->states_chunks;
1077         if (pg->chunks_count > 1) {
1078                 pg->freemask_chunk = malloc(pg->chunks_count *
1079                     sizeof(uint64_t), M_NAT64LSN, M_NOWAIT);
1080                 if (pg->freemask_chunk == NULL) {
1081                         uma_zfree(nat64lsn_pg_zone, pg);
1082                         return (PG_ERROR(4));
1083                 }
1084                 pg->states_chunk = malloc(pg->chunks_count *
1085                     sizeof(struct nat64lsn_states_chunk *), M_NAT64LSN,
1086                     M_NOWAIT | M_ZERO);
1087                 if (pg->states_chunk == NULL) {
1088                         free(pg->freemask_chunk, M_NAT64LSN);
1089                         uma_zfree(nat64lsn_pg_zone, pg);
1090                         return (PG_ERROR(5));
1091                 }
1092                 for (i = 0; i < pg->chunks_count; i++) {
1093                         pg->states_chunk[i] = uma_zalloc(
1094                             nat64lsn_state_zone, M_NOWAIT);
1095                         if (pg->states_chunk[i] == NULL)
1096                                 goto states_failed;
1097                 }
1098                 memset(pg->freemask_chunk, 0xff,
1099                     sizeof(uint64_t) * pg->chunks_count);
1100         } else {
1101                 pg->states = uma_zalloc(nat64lsn_state_zone, M_NOWAIT);
1102                 if (pg->states == NULL) {
1103                         uma_zfree(nat64lsn_pg_zone, pg);
1104                         return (PG_ERROR(6));
1105                 }
1106                 memset(&pg->freemask64, 0xff, sizeof(uint64_t));
1107         }
1108
1109         /* Initialize PG and hook it to pgchunk */
1110         SET_AGE(pg->timestamp);
1111         pg->proto = proto;
1112         pg->base_port = NAT64_MIN_PORT + 64 * pg_idx;
1113         ck_pr_store_ptr(&chunks[chunk_idx]->pgptr[pg_idx % 32], pg);
1114         ck_pr_fence_store();
1115         ck_pr_bts_32(&pgmask[pg_idx / 32], pg_idx % 32);
1116         ck_pr_store_ptr(pgptr, pg);
1117
1118         ALIAS_LOCK(alias);
1119         CK_SLIST_INSERT_HEAD(&alias->portgroups, pg, entries);
1120         SET_AGE(alias->timestamp);
1121         alias->portgroups_count++;
1122         ALIAS_UNLOCK(alias);
1123         NAT64STAT_INC(&cfg->base.stats, spgcreated);
1124         return (PG_ERROR(0));
1125
1126 states_failed:
1127         for (i = 0; i < pg->chunks_count; i++)
1128                 uma_zfree(nat64lsn_state_zone, pg->states_chunk[i]);
1129         free(pg->freemask_chunk, M_NAT64LSN);
1130         free(pg->states_chunk, M_NAT64LSN);
1131         uma_zfree(nat64lsn_pg_zone, pg);
1132         return (PG_ERROR(7));
1133 }
1134
1135 static int
1136 nat64lsn_alloc_pg(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
1137 {
1138         struct nat64lsn_aliaslink *link;
1139         struct nat64lsn_alias *alias;
1140         int ret;
1141
1142         link = nat64lsn_get_aliaslink(cfg, ji->host, &ji->f_id);
1143         if (link == NULL)
1144                 return (PG_ERROR(1));
1145
1146         /*
1147          * TODO: check that we did not already allocated PG in
1148          *       previous call.
1149          */
1150
1151         ret = 0;
1152         alias = link->alias;
1153         /* Find place in pgchunk where PG can be added */
1154         switch (ji->proto) {
1155         case IPPROTO_TCP:
1156                 ret = nat64lsn_alloc_proto_pg(cfg, alias,
1157                     &alias->tcp_chunkmask, alias->tcp_pgmask,
1158                     alias->tcp, &alias->tcp_pg, ji->proto);
1159                 break;
1160         case IPPROTO_UDP:
1161                 ret = nat64lsn_alloc_proto_pg(cfg, alias,
1162                     &alias->udp_chunkmask, alias->udp_pgmask,
1163                     alias->udp, &alias->udp_pg, ji->proto);
1164                 break;
1165         case IPPROTO_ICMP:
1166                 ret = nat64lsn_alloc_proto_pg(cfg, alias,
1167                     &alias->icmp_chunkmask, alias->icmp_pgmask,
1168                     alias->icmp, &alias->icmp_pg, ji->proto);
1169                 break;
1170         default:
1171                 panic("%s: wrong proto %d", __func__, ji->proto);
1172         }
1173         if (ret == PG_ERROR(1)) {
1174                 /*
1175                  * PG_ERROR(1) means that alias lacks free PGs
1176                  * XXX: try next alias.
1177                  */
1178                 printf("NAT64LSN: %s: failed to obtain PG\n",
1179                     __func__);
1180                 return (ret);
1181         }
1182         if (ret == PG_ERROR(0)) {
1183                 ji->state = nat64lsn_get_state6to4(cfg, ji->host, &ji->f_id,
1184                     ji->state_hval, ji->faddr, ji->port, ji->proto);
1185                 if (ji->state == NULL)
1186                         ret = PG_ERROR(8);
1187                 else
1188                         ji->done = 1;
1189         }
1190         return (ret);
1191 }
1192
1193 static void
1194 nat64lsn_do_request(void *data)
1195 {
1196         struct epoch_tracker et;
1197         struct nat64lsn_job_head jhead;
1198         struct nat64lsn_job_item *ji, *ji2;
1199         struct nat64lsn_cfg *cfg;
1200         int jcount;
1201         uint8_t flags;
1202
1203         cfg = (struct nat64lsn_cfg *)data;
1204         if (cfg->jlen == 0)
1205                 return;
1206
1207         CURVNET_SET(cfg->vp);
1208         STAILQ_INIT(&jhead);
1209
1210         /* Grab queue */
1211         JQUEUE_LOCK();
1212         STAILQ_SWAP(&jhead, &cfg->jhead, nat64lsn_job_item);
1213         jcount = cfg->jlen;
1214         cfg->jlen = 0;
1215         JQUEUE_UNLOCK();
1216
1217         /* TODO: check if we need to resize hash */
1218
1219         NAT64STAT_INC(&cfg->base.stats, jcalls);
1220         DPRINTF(DP_JQUEUE, "count=%d", jcount);
1221
1222         /*
1223          * TODO:
1224          * What we should do here is to build a hash
1225          * to ensure we don't have lots of duplicate requests.
1226          * Skip this for now.
1227          *
1228          * TODO: Limit per-call number of items
1229          */
1230
1231         NAT64LSN_EPOCH_ENTER(et);
1232         STAILQ_FOREACH(ji, &jhead, entries) {
1233                 switch (ji->jtype) {
1234                 case JTYPE_NEWHOST:
1235                         if (nat64lsn_alloc_host(cfg, ji) != HOST_ERROR(0))
1236                                 NAT64STAT_INC(&cfg->base.stats, jhostfails);
1237                         break;
1238                 case JTYPE_NEWPORTGROUP:
1239                         if (nat64lsn_alloc_pg(cfg, ji) != PG_ERROR(0))
1240                                 NAT64STAT_INC(&cfg->base.stats, jportfails);
1241                         break;
1242                 default:
1243                         continue;
1244                 }
1245                 if (ji->done != 0) {
1246                         flags = ji->proto != IPPROTO_TCP ? 0 :
1247                             convert_tcp_flags(ji->f_id._flags);
1248                         nat64lsn_translate6_internal(cfg, &ji->m,
1249                             ji->state, flags);
1250                         NAT64STAT_INC(&cfg->base.stats, jreinjected);
1251                 }
1252         }
1253         NAT64LSN_EPOCH_EXIT(et);
1254
1255         ji = STAILQ_FIRST(&jhead);
1256         while (ji != NULL) {
1257                 ji2 = STAILQ_NEXT(ji, entries);
1258                 /*
1259                  * In any case we must free mbuf if
1260                  * translator did not consumed it.
1261                  */
1262                 m_freem(ji->m);
1263                 uma_zfree(nat64lsn_job_zone, ji);
1264                 ji = ji2;
1265         }
1266         CURVNET_RESTORE();
1267 }
1268
1269 static struct nat64lsn_job_item *
1270 nat64lsn_create_job(struct nat64lsn_cfg *cfg, int jtype)
1271 {
1272         struct nat64lsn_job_item *ji;
1273
1274         /*
1275          * Do not try to lock possibly contested mutex if we're near the
1276          * limit. Drop packet instead.
1277          */
1278         ji = NULL;
1279         if (cfg->jlen >= cfg->jmaxlen)
1280                 NAT64STAT_INC(&cfg->base.stats, jmaxlen);
1281         else {
1282                 ji = uma_zalloc(nat64lsn_job_zone, M_NOWAIT);
1283                 if (ji == NULL)
1284                         NAT64STAT_INC(&cfg->base.stats, jnomem);
1285         }
1286         if (ji == NULL) {
1287                 NAT64STAT_INC(&cfg->base.stats, dropped);
1288                 DPRINTF(DP_DROPS, "failed to create job");
1289         } else {
1290                 ji->jtype = jtype;
1291                 ji->done = 0;
1292         }
1293         return (ji);
1294 }
1295
1296 static void
1297 nat64lsn_enqueue_job(struct nat64lsn_cfg *cfg, struct nat64lsn_job_item *ji)
1298 {
1299
1300         JQUEUE_LOCK();
1301         STAILQ_INSERT_TAIL(&cfg->jhead, ji, entries);
1302         NAT64STAT_INC(&cfg->base.stats, jrequests);
1303         cfg->jlen++;
1304
1305         if (callout_pending(&cfg->jcallout) == 0)
1306                 callout_reset(&cfg->jcallout, 1, nat64lsn_do_request, cfg);
1307         JQUEUE_UNLOCK();
1308 }
1309
1310 static void
1311 nat64lsn_job_destroy(epoch_context_t ctx)
1312 {
1313         struct nat64lsn_job_item *ji;
1314         struct nat64lsn_host *host;
1315         struct nat64lsn_pg *pg;
1316         int i;
1317
1318         ji = __containerof(ctx, struct nat64lsn_job_item, epoch_ctx);
1319         MPASS(ji->jtype == JTYPE_DESTROY);
1320         while (!CK_SLIST_EMPTY(&ji->hosts)) {
1321                 host = CK_SLIST_FIRST(&ji->hosts);
1322                 CK_SLIST_REMOVE_HEAD(&ji->hosts, entries);
1323                 if (host->states_count > 0) {
1324                         /*
1325                          * XXX: The state has been created
1326                          * during host deletion.
1327                          */
1328                         printf("NAT64LSN: %s: destroying host with %d "
1329                             "states\n", __func__, host->states_count);
1330                 }
1331                 nat64lsn_destroy_host(host);
1332         }
1333         while (!CK_SLIST_EMPTY(&ji->portgroups)) {
1334                 pg = CK_SLIST_FIRST(&ji->portgroups);
1335                 CK_SLIST_REMOVE_HEAD(&ji->portgroups, entries);
1336                 for (i = 0; i < pg->chunks_count; i++) {
1337                         if (FREEMASK_BITCOUNT(pg, i) != 64) {
1338                                 /*
1339                                  * XXX: The state has been created during
1340                                  * PG deletion.
1341                                  */
1342                                 printf("NAT64LSN: %s: destroying PG %p "
1343                                     "with non-empty chunk %d\n", __func__,
1344                                     pg, i);
1345                         }
1346                 }
1347                 nat64lsn_destroy_pg(pg);
1348         }
1349         uma_zfree(nat64lsn_pgchunk_zone, ji->pgchunk);
1350         uma_zfree(nat64lsn_job_zone, ji);
1351 }
1352
1353 static int
1354 nat64lsn_request_host(struct nat64lsn_cfg *cfg,
1355     const struct ipfw_flow_id *f_id, struct mbuf **mp, uint32_t hval,
1356     in_addr_t faddr, uint16_t port, uint8_t proto)
1357 {
1358         struct nat64lsn_job_item *ji;
1359
1360         ji = nat64lsn_create_job(cfg, JTYPE_NEWHOST);
1361         if (ji != NULL) {
1362                 ji->m = *mp;
1363                 ji->f_id = *f_id;
1364                 ji->faddr = faddr;
1365                 ji->port = port;
1366                 ji->proto = proto;
1367                 ji->src6_hval = hval;
1368
1369                 nat64lsn_enqueue_job(cfg, ji);
1370                 NAT64STAT_INC(&cfg->base.stats, jhostsreq);
1371                 *mp = NULL;
1372         }
1373         return (IP_FW_DENY);
1374 }
1375
1376 static int
1377 nat64lsn_request_pg(struct nat64lsn_cfg *cfg, struct nat64lsn_host *host,
1378     const struct ipfw_flow_id *f_id, struct mbuf **mp, uint32_t hval,
1379     in_addr_t faddr, uint16_t port, uint8_t proto)
1380 {
1381         struct nat64lsn_job_item *ji;
1382
1383         ji = nat64lsn_create_job(cfg, JTYPE_NEWPORTGROUP);
1384         if (ji != NULL) {
1385                 ji->m = *mp;
1386                 ji->f_id = *f_id;
1387                 ji->faddr = faddr;
1388                 ji->port = port;
1389                 ji->proto = proto;
1390                 ji->state_hval = hval;
1391                 ji->host = host;
1392
1393                 nat64lsn_enqueue_job(cfg, ji);
1394                 NAT64STAT_INC(&cfg->base.stats, jportreq);
1395                 *mp = NULL;
1396         }
1397         return (IP_FW_DENY);
1398 }
1399
1400 static int
1401 nat64lsn_translate6_internal(struct nat64lsn_cfg *cfg, struct mbuf **mp,
1402     struct nat64lsn_state *state, uint8_t flags)
1403 {
1404         struct pfloghdr loghdr, *logdata;
1405         int ret;
1406         uint16_t ts;
1407
1408         /* Update timestamp and flags if needed */
1409         SET_AGE(ts);
1410         if (state->timestamp != ts)
1411                 state->timestamp = ts;
1412         if ((state->flags & flags) != 0)
1413                 state->flags |= flags;
1414
1415         if (cfg->base.flags & NAT64_LOG) {
1416                 logdata = &loghdr;
1417                 nat64lsn_log(logdata, *mp, AF_INET6, state);
1418         } else
1419                 logdata = NULL;
1420
1421         ret = nat64_do_handle_ip6(*mp, htonl(state->ip_src),
1422             htons(state->aport), &cfg->base, logdata);
1423         if (ret == NAT64SKIP)
1424                 return (cfg->nomatch_verdict);
1425         if (ret == NAT64RETURN)
1426                 *mp = NULL;
1427         return (IP_FW_DENY);
1428 }
1429
1430 static int
1431 nat64lsn_translate6(struct nat64lsn_cfg *cfg, struct ipfw_flow_id *f_id,
1432     struct mbuf **mp)
1433 {
1434         struct nat64lsn_state *state;
1435         struct nat64lsn_host *host;
1436         struct icmp6_hdr *icmp6;
1437         uint32_t addr, hval, data[2];
1438         int offset, proto;
1439         uint16_t port;
1440         uint8_t flags;
1441
1442         /* Check if protocol is supported */
1443         port = f_id->src_port;
1444         proto = f_id->proto;
1445         switch (f_id->proto) {
1446         case IPPROTO_ICMPV6:
1447                 /*
1448                  * For ICMPv6 echo reply/request we use icmp6_id as
1449                  * local port.
1450                  */
1451                 offset = 0;
1452                 proto = nat64_getlasthdr(*mp, &offset);
1453                 if (proto < 0) {
1454                         NAT64STAT_INC(&cfg->base.stats, dropped);
1455                         DPRINTF(DP_DROPS, "mbuf isn't contigious");
1456                         return (IP_FW_DENY);
1457                 }
1458                 if (proto == IPPROTO_ICMPV6) {
1459                         icmp6 = mtodo(*mp, offset);
1460                         if (icmp6->icmp6_type == ICMP6_ECHO_REQUEST ||
1461                             icmp6->icmp6_type == ICMP6_ECHO_REPLY)
1462                                 port = ntohs(icmp6->icmp6_id);
1463                 }
1464                 proto = IPPROTO_ICMP;
1465                 /* FALLTHROUGH */
1466         case IPPROTO_TCP:
1467         case IPPROTO_UDP:
1468                 break;
1469         default:
1470                 NAT64STAT_INC(&cfg->base.stats, noproto);
1471                 return (cfg->nomatch_verdict);
1472         }
1473
1474         /* Extract IPv4 from destination IPv6 address */
1475         addr = nat64_extract_ip4(&f_id->dst_ip6, cfg->base.plat_plen);
1476         if (addr == 0 || nat64_check_private_ip4(&cfg->base, addr) != 0) {
1477                 char a[INET_ADDRSTRLEN];
1478
1479                 NAT64STAT_INC(&cfg->base.stats, dropped);
1480                 DPRINTF(DP_DROPS, "dropped due to embedded IPv4 address %s",
1481                     inet_ntop(AF_INET, &addr, a, sizeof(a)));
1482                 return (IP_FW_DENY); /* XXX: add extra stats? */
1483         }
1484
1485         /* Try to find host */
1486         hval = HOST_HVAL(cfg, &f_id->src_ip6);
1487         CK_SLIST_FOREACH(host, &HOSTS(cfg, hval), entries) {
1488                 if (IN6_ARE_ADDR_EQUAL(&f_id->src_ip6, &host->addr))
1489                         break;
1490         }
1491         /* We use IPv4 address in host byte order */
1492         addr = ntohl(addr);
1493         if (host == NULL)
1494                 return (nat64lsn_request_host(cfg, f_id, mp,
1495                     hval, addr, port, proto));
1496
1497         flags = proto != IPPROTO_TCP ? 0 : convert_tcp_flags(f_id->_flags);
1498
1499         data[0] = addr;
1500         data[1] = (f_id->dst_port << 16) | port;
1501         hval = STATE_HVAL(cfg, data);
1502         state = nat64lsn_get_state6to4(cfg, host, f_id, hval, addr,
1503             port, proto);
1504         if (state == NULL)
1505                 return (nat64lsn_request_pg(cfg, host, f_id, mp, hval, addr,
1506                     port, proto));
1507         return (nat64lsn_translate6_internal(cfg, mp, state, flags));
1508 }
1509
1510 /*
1511  * Main dataplane entry point.
1512  */
1513 int
1514 ipfw_nat64lsn(struct ip_fw_chain *ch, struct ip_fw_args *args,
1515     ipfw_insn *cmd, int *done)
1516 {
1517         struct nat64lsn_cfg *cfg;
1518         ipfw_insn *icmd;
1519         int ret;
1520
1521         IPFW_RLOCK_ASSERT(ch);
1522
1523         *done = 0;      /* continue the search in case of failure */
1524         icmd = cmd + 1;
1525         if (cmd->opcode != O_EXTERNAL_ACTION ||
1526             cmd->arg1 != V_nat64lsn_eid ||
1527             icmd->opcode != O_EXTERNAL_INSTANCE ||
1528             (cfg = NAT64_LOOKUP(ch, icmd)) == NULL)
1529                 return (IP_FW_DENY);
1530
1531         *done = 1;      /* terminate the search */
1532
1533         switch (args->f_id.addr_type) {
1534         case 4:
1535                 ret = nat64lsn_translate4(cfg, &args->f_id, &args->m);
1536                 break;
1537         case 6:
1538                 /*
1539                  * Check that destination IPv6 address matches our prefix6.
1540                  */
1541                 if ((cfg->base.flags & NAT64LSN_ANYPREFIX) == 0 &&
1542                     memcmp(&args->f_id.dst_ip6, &cfg->base.plat_prefix,
1543                     cfg->base.plat_plen / 8) != 0) {
1544                         ret = cfg->nomatch_verdict;
1545                         break;
1546                 }
1547                 ret = nat64lsn_translate6(cfg, &args->f_id, &args->m);
1548                 break;
1549         default:
1550                 ret = cfg->nomatch_verdict;
1551         }
1552
1553         if (ret != IP_FW_PASS && args->m != NULL) {
1554                 m_freem(args->m);
1555                 args->m = NULL;
1556         }
1557         return (ret);
1558 }
1559
1560 static int
1561 nat64lsn_state_ctor(void *mem, int size, void *arg, int flags)
1562 {
1563         struct nat64lsn_states_chunk *chunk;
1564         int i;
1565
1566         chunk = (struct nat64lsn_states_chunk *)mem;
1567         for (i = 0; i < 64; i++)
1568                 chunk->state[i].flags = 0;
1569         return (0);
1570 }
1571
1572 void
1573 nat64lsn_init_internal(void)
1574 {
1575
1576         nat64lsn_host_zone = uma_zcreate("NAT64LSN hosts",
1577             sizeof(struct nat64lsn_host), NULL, NULL, NULL, NULL,
1578             UMA_ALIGN_PTR, 0);
1579         nat64lsn_pgchunk_zone = uma_zcreate("NAT64LSN portgroup chunks",
1580             sizeof(struct nat64lsn_pgchunk), NULL, NULL, NULL, NULL,
1581             UMA_ALIGN_PTR, 0);
1582         nat64lsn_pg_zone = uma_zcreate("NAT64LSN portgroups",
1583             sizeof(struct nat64lsn_pg), NULL, NULL, NULL, NULL,
1584             UMA_ALIGN_PTR, 0);
1585         nat64lsn_aliaslink_zone = uma_zcreate("NAT64LSN links",
1586             sizeof(struct nat64lsn_aliaslink), NULL, NULL, NULL, NULL,
1587             UMA_ALIGN_PTR, 0);
1588         nat64lsn_state_zone = uma_zcreate("NAT64LSN states",
1589             sizeof(struct nat64lsn_states_chunk), nat64lsn_state_ctor,
1590             NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
1591         nat64lsn_job_zone = uma_zcreate("NAT64LSN jobs",
1592             sizeof(struct nat64lsn_job_item), NULL, NULL, NULL, NULL,
1593             UMA_ALIGN_PTR, 0);
1594         JQUEUE_LOCK_INIT();
1595 }
1596
1597 void
1598 nat64lsn_uninit_internal(void)
1599 {
1600
1601         /* XXX: epoch_task drain */
1602         JQUEUE_LOCK_DESTROY();
1603         uma_zdestroy(nat64lsn_host_zone);
1604         uma_zdestroy(nat64lsn_pgchunk_zone);
1605         uma_zdestroy(nat64lsn_pg_zone);
1606         uma_zdestroy(nat64lsn_aliaslink_zone);
1607         uma_zdestroy(nat64lsn_state_zone);
1608         uma_zdestroy(nat64lsn_job_zone);
1609 }
1610
1611 void
1612 nat64lsn_start_instance(struct nat64lsn_cfg *cfg)
1613 {
1614
1615         CALLOUT_LOCK(cfg);
1616         callout_reset(&cfg->periodic, hz * PERIODIC_DELAY,
1617             nat64lsn_periodic, cfg);
1618         CALLOUT_UNLOCK(cfg);
1619 }
1620
1621 struct nat64lsn_cfg *
1622 nat64lsn_init_instance(struct ip_fw_chain *ch, in_addr_t prefix, int plen)
1623 {
1624         struct nat64lsn_cfg *cfg;
1625         struct nat64lsn_alias *alias;
1626         int i, naddr;
1627
1628         cfg = malloc(sizeof(struct nat64lsn_cfg), M_NAT64LSN,
1629             M_WAITOK | M_ZERO);
1630
1631         CFG_LOCK_INIT(cfg);
1632         CALLOUT_LOCK_INIT(cfg);
1633         STAILQ_INIT(&cfg->jhead);
1634         cfg->vp = curvnet;
1635         COUNTER_ARRAY_ALLOC(cfg->base.stats.cnt, NAT64STATS, M_WAITOK);
1636
1637         cfg->hash_seed = arc4random();
1638         cfg->hosts_hashsize = NAT64LSN_HOSTS_HSIZE;
1639         cfg->hosts_hash = malloc(sizeof(struct nat64lsn_hosts_slist) *
1640             cfg->hosts_hashsize, M_NAT64LSN, M_WAITOK | M_ZERO);
1641         for (i = 0; i < cfg->hosts_hashsize; i++)
1642                 CK_SLIST_INIT(&cfg->hosts_hash[i]);
1643
1644         naddr = 1 << (32 - plen);
1645         cfg->prefix4 = prefix;
1646         cfg->pmask4 = prefix | (naddr - 1);
1647         cfg->plen4 = plen;
1648         cfg->aliases = malloc(sizeof(struct nat64lsn_alias) * naddr,
1649             M_NAT64LSN, M_WAITOK | M_ZERO);
1650         for (i = 0; i < naddr; i++) {
1651                 alias = &cfg->aliases[i];
1652                 alias->addr = prefix + i; /* host byte order */
1653                 CK_SLIST_INIT(&alias->hosts);
1654                 ALIAS_LOCK_INIT(alias);
1655         }
1656
1657         callout_init_mtx(&cfg->periodic, &cfg->periodic_lock, 0);
1658         callout_init(&cfg->jcallout, CALLOUT_MPSAFE);
1659
1660         return (cfg);
1661 }
1662
1663 static void
1664 nat64lsn_destroy_pg(struct nat64lsn_pg *pg)
1665 {
1666         int i;
1667
1668         if (pg->chunks_count == 1) {
1669                 uma_zfree(nat64lsn_state_zone, pg->states);
1670         } else {
1671                 for (i = 0; i < pg->chunks_count; i++)
1672                         uma_zfree(nat64lsn_state_zone, pg->states_chunk[i]);
1673                 free(pg->states_chunk, M_NAT64LSN);
1674                 free(pg->freemask_chunk, M_NAT64LSN);
1675         }
1676         uma_zfree(nat64lsn_pg_zone, pg);
1677 }
1678
1679 static void
1680 nat64lsn_destroy_alias(struct nat64lsn_cfg *cfg,
1681     struct nat64lsn_alias *alias)
1682 {
1683         struct nat64lsn_pg *pg;
1684         int i;
1685
1686         while (!CK_SLIST_EMPTY(&alias->portgroups)) {
1687                 pg = CK_SLIST_FIRST(&alias->portgroups);
1688                 CK_SLIST_REMOVE_HEAD(&alias->portgroups, entries);
1689                 nat64lsn_destroy_pg(pg);
1690         }
1691         for (i = 0; i < 32; i++) {
1692                 if (ISSET32(alias->tcp_chunkmask, i))
1693                         uma_zfree(nat64lsn_pgchunk_zone, alias->tcp[i]);
1694                 if (ISSET32(alias->udp_chunkmask, i))
1695                         uma_zfree(nat64lsn_pgchunk_zone, alias->udp[i]);
1696                 if (ISSET32(alias->icmp_chunkmask, i))
1697                         uma_zfree(nat64lsn_pgchunk_zone, alias->icmp[i]);
1698         }
1699         ALIAS_LOCK_DESTROY(alias);
1700 }
1701
1702 static void
1703 nat64lsn_destroy_host(struct nat64lsn_host *host)
1704 {
1705         struct nat64lsn_aliaslink *link;
1706
1707         while (!CK_SLIST_EMPTY(&host->aliases)) {
1708                 link = CK_SLIST_FIRST(&host->aliases);
1709                 CK_SLIST_REMOVE_HEAD(&host->aliases, host_entries);
1710
1711                 ALIAS_LOCK(link->alias);
1712                 CK_SLIST_REMOVE(&link->alias->hosts, link,
1713                     nat64lsn_aliaslink, alias_entries);
1714                 link->alias->hosts_count--;
1715                 ALIAS_UNLOCK(link->alias);
1716
1717                 uma_zfree(nat64lsn_aliaslink_zone, link);
1718         }
1719         HOST_LOCK_DESTROY(host);
1720         free(host->states_hash, M_NAT64LSN);
1721         uma_zfree(nat64lsn_host_zone, host);
1722 }
1723
1724 void
1725 nat64lsn_destroy_instance(struct nat64lsn_cfg *cfg)
1726 {
1727         struct nat64lsn_host *host;
1728         int i;
1729
1730         CALLOUT_LOCK(cfg);
1731         callout_drain(&cfg->periodic);
1732         CALLOUT_UNLOCK(cfg);
1733         callout_drain(&cfg->jcallout);
1734
1735         for (i = 0; i < cfg->hosts_hashsize; i++) {
1736                 while (!CK_SLIST_EMPTY(&cfg->hosts_hash[i])) {
1737                         host = CK_SLIST_FIRST(&cfg->hosts_hash[i]);
1738                         CK_SLIST_REMOVE_HEAD(&cfg->hosts_hash[i], entries);
1739                         nat64lsn_destroy_host(host);
1740                 }
1741         }
1742
1743         for (i = 0; i < (1 << (32 - cfg->plen4)); i++)
1744                 nat64lsn_destroy_alias(cfg, &cfg->aliases[i]);
1745
1746         CALLOUT_LOCK_DESTROY(cfg);
1747         CFG_LOCK_DESTROY(cfg);
1748         COUNTER_ARRAY_FREE(cfg->base.stats.cnt, NAT64STATS);
1749         free(cfg->hosts_hash, M_NAT64LSN);
1750         free(cfg->aliases, M_NAT64LSN);
1751         free(cfg, M_NAT64LSN);
1752 }
1753