source: rtems-libbsd/freebsd/sys/netpfil/ipfw/nat64/nat64stl_control.c @ 3c967ca

55-freebsd-126-freebsd-12
Last change on this file since 3c967ca was 3c967ca, checked in by Sebastian Huber <sebastian.huber@…>, on 06/08/17 at 11:15:12

Use <sys/lock.h> provided by Newlib

  • Property mode set to 100644
File size: 15.4 KB
Line 
1#include <machine/rtems-bsd-kernel-space.h>
2
3/*-
4 * Copyright (c) 2015-2016 Yandex LLC
5 * Copyright (c) 2015-2016 Andrey V. Elsukov <ae@FreeBSD.org>
6 * Copyright (c) 2015 Alexander V. Chernikov <melifaro@FreeBSD.org>
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD$");
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/counter.h>
37#include <sys/errno.h>
38#include <sys/kernel.h>
39#include <sys/lock.h>
40#include <sys/malloc.h>
41#include <sys/mbuf.h>
42#include <sys/module.h>
43#include <sys/rmlock.h>
44#include <sys/rwlock.h>
45#include <sys/socket.h>
46#include <sys/sockopt.h>
47#include <sys/queue.h>
48#include <sys/syslog.h>
49#include <sys/sysctl.h>
50
51#include <net/if.h>
52#include <net/if_var.h>
53#include <net/pfil.h>
54#include <net/route.h>
55#include <net/vnet.h>
56
57#include <netinet/in.h>
58#include <netinet/ip_var.h>
59#include <netinet/ip_fw.h>
60#include <netinet6/in6_var.h>
61#include <netinet6/ip6_var.h>
62
63#include <netpfil/ipfw/ip_fw_private.h>
64#include <netpfil/ipfw/nat64/ip_fw_nat64.h>
65#include <netpfil/ipfw/nat64/nat64stl.h>
66#include <netinet6/ip_fw_nat64.h>
67
68VNET_DEFINE(uint16_t, nat64stl_eid) = 0;
69
70static struct nat64stl_cfg *nat64stl_alloc_config(const char *name, uint8_t set);
71static void nat64stl_free_config(struct nat64stl_cfg *cfg);
72static struct nat64stl_cfg *nat64stl_find(struct namedobj_instance *ni,
73    const char *name, uint8_t set);
74
75static struct nat64stl_cfg *
76nat64stl_alloc_config(const char *name, uint8_t set)
77{
78        struct nat64stl_cfg *cfg;
79
80        cfg = malloc(sizeof(struct nat64stl_cfg), M_IPFW, M_WAITOK | M_ZERO);
81        COUNTER_ARRAY_ALLOC(cfg->stats.stats, NAT64STATS, M_WAITOK);
82        cfg->no.name = cfg->name;
83        cfg->no.etlv = IPFW_TLV_NAT64STL_NAME;
84        cfg->no.set = set;
85        strlcpy(cfg->name, name, sizeof(cfg->name));
86        return (cfg);
87}
88
89static void
90nat64stl_free_config(struct nat64stl_cfg *cfg)
91{
92
93        COUNTER_ARRAY_FREE(cfg->stats.stats, NAT64STATS);
94        free(cfg, M_IPFW);
95}
96
97static void
98nat64stl_export_config(struct ip_fw_chain *ch, struct nat64stl_cfg *cfg,
99    ipfw_nat64stl_cfg *uc)
100{
101        struct named_object *no;
102
103        uc->prefix6 = cfg->prefix6;
104        uc->plen6 = cfg->plen6;
105        uc->flags = cfg->flags & NAT64STL_FLAGSMASK;
106        uc->set = cfg->no.set;
107        strlcpy(uc->name, cfg->no.name, sizeof(uc->name));
108
109        no = ipfw_objhash_lookup_table_kidx(ch, cfg->map64);
110        ipfw_export_obj_ntlv(no, &uc->ntlv6);
111        no = ipfw_objhash_lookup_table_kidx(ch, cfg->map46);
112        ipfw_export_obj_ntlv(no, &uc->ntlv4);
113}
114
115struct nat64stl_dump_arg {
116        struct ip_fw_chain *ch;
117        struct sockopt_data *sd;
118};
119
120static int
121export_config_cb(struct namedobj_instance *ni, struct named_object *no,
122    void *arg)
123{
124        struct nat64stl_dump_arg *da = (struct nat64stl_dump_arg *)arg;
125        ipfw_nat64stl_cfg *uc;
126
127        uc = (ipfw_nat64stl_cfg *)ipfw_get_sopt_space(da->sd, sizeof(*uc));
128        nat64stl_export_config(da->ch, (struct nat64stl_cfg *)no, uc);
129        return (0);
130}
131
132static struct nat64stl_cfg *
133nat64stl_find(struct namedobj_instance *ni, const char *name, uint8_t set)
134{
135        struct nat64stl_cfg *cfg;
136
137        cfg = (struct nat64stl_cfg *)ipfw_objhash_lookup_name_type(ni, set,
138            IPFW_TLV_NAT64STL_NAME, name);
139
140        return (cfg);
141}
142
143
144static int
145nat64stl_create_internal(struct ip_fw_chain *ch, struct nat64stl_cfg *cfg,
146    ipfw_nat64stl_cfg *i)
147{
148
149        IPFW_UH_WLOCK_ASSERT(ch);
150
151        if (ipfw_objhash_alloc_idx(CHAIN_TO_SRV(ch), &cfg->no.kidx) != 0)
152                return (ENOSPC);
153        cfg->flags |= NAT64STL_KIDX;
154
155        if (ipfw_ref_table(ch, &i->ntlv4, &cfg->map46) != 0)
156                return (EINVAL);
157        cfg->flags |= NAT64STL_46T;
158
159        if (ipfw_ref_table(ch, &i->ntlv6, &cfg->map64) != 0)
160                return (EINVAL);
161        cfg->flags |= NAT64STL_64T;
162
163        ipfw_objhash_add(CHAIN_TO_SRV(ch), &cfg->no);
164
165        return (0);
166}
167
168/*
169 * Creates new nat64 instance.
170 * Data layout (v0)(current):
171 * Request: [ ipfw_obj_lheader ipfw_nat64stl_cfg ]
172 *
173 * Returns 0 on success
174 */
175static int
176nat64stl_create(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
177    struct sockopt_data *sd)
178{
179        ipfw_obj_lheader *olh;
180        ipfw_nat64stl_cfg *uc;
181        struct namedobj_instance *ni;
182        struct nat64stl_cfg *cfg;
183        int error;
184
185        if (sd->valsize != sizeof(*olh) + sizeof(*uc))
186                return (EINVAL);
187
188        olh = (ipfw_obj_lheader *)sd->kbuf;
189        uc = (ipfw_nat64stl_cfg *)(olh + 1);
190
191        if (ipfw_check_object_name_generic(uc->name) != 0)
192                return (EINVAL);
193        if (!IN6_IS_ADDR_WKPFX(&uc->prefix6))
194                return (EINVAL);
195        if (uc->plen6 != 96 || uc->set >= IPFW_MAX_SETS)
196                return (EINVAL);
197
198        /* XXX: check types of tables */
199
200        ni = CHAIN_TO_SRV(ch);
201        error = 0;
202
203        IPFW_UH_RLOCK(ch);
204        if (nat64stl_find(ni, uc->name, uc->set) != NULL) {
205                IPFW_UH_RUNLOCK(ch);
206                return (EEXIST);
207        }
208        IPFW_UH_RUNLOCK(ch);
209
210        cfg = nat64stl_alloc_config(uc->name, uc->set);
211        cfg->prefix6 = uc->prefix6;
212        cfg->plen6 = uc->plen6;
213        cfg->flags = uc->flags & NAT64STL_FLAGSMASK;
214
215        IPFW_UH_WLOCK(ch);
216
217        if (nat64stl_find(ni, uc->name, uc->set) != NULL) {
218                IPFW_UH_WUNLOCK(ch);
219                nat64stl_free_config(cfg);
220                return (EEXIST);
221        }
222        error = nat64stl_create_internal(ch, cfg, uc);
223        if (error == 0) {
224                /* Okay, let's link data */
225                IPFW_WLOCK(ch);
226                SRV_OBJECT(ch, cfg->no.kidx) = cfg;
227                IPFW_WUNLOCK(ch);
228
229                IPFW_UH_WUNLOCK(ch);
230                return (0);
231        }
232
233        if (cfg->flags & NAT64STL_KIDX)
234                ipfw_objhash_free_idx(ni, cfg->no.kidx);
235        if (cfg->flags & NAT64STL_46T)
236                ipfw_unref_table(ch, cfg->map46);
237        if (cfg->flags & NAT64STL_64T)
238                ipfw_unref_table(ch, cfg->map64);
239
240        IPFW_UH_WUNLOCK(ch);
241        nat64stl_free_config(cfg);
242        return (error);
243}
244
245/*
246 * Change existing nat64stl instance configuration.
247 * Data layout (v0)(current):
248 * Request: [ ipfw_obj_header ipfw_nat64stl_cfg ]
249 * Reply: [ ipfw_obj_header ipfw_nat64stl_cfg ]
250 *
251 * Returns 0 on success
252 */
253static int
254nat64stl_config(struct ip_fw_chain *ch, ip_fw3_opheader *op,
255    struct sockopt_data *sd)
256{
257        ipfw_obj_header *oh;
258        ipfw_nat64stl_cfg *uc;
259        struct nat64stl_cfg *cfg;
260        struct namedobj_instance *ni;
261
262        if (sd->valsize != sizeof(*oh) + sizeof(*uc))
263                return (EINVAL);
264
265        oh = (ipfw_obj_header *)ipfw_get_sopt_space(sd,
266            sizeof(*oh) + sizeof(*uc));
267        uc = (ipfw_nat64stl_cfg *)(oh + 1);
268
269        if (ipfw_check_object_name_generic(oh->ntlv.name) != 0 ||
270            oh->ntlv.set >= IPFW_MAX_SETS)
271                return (EINVAL);
272
273        ni = CHAIN_TO_SRV(ch);
274        if (sd->sopt->sopt_dir == SOPT_GET) {
275                IPFW_UH_RLOCK(ch);
276                cfg = nat64stl_find(ni, oh->ntlv.name, oh->ntlv.set);
277                if (cfg == NULL) {
278                        IPFW_UH_RUNLOCK(ch);
279                        return (EEXIST);
280                }
281                nat64stl_export_config(ch, cfg, uc);
282                IPFW_UH_RUNLOCK(ch);
283                return (0);
284        }
285
286        IPFW_UH_WLOCK(ch);
287        cfg = nat64stl_find(ni, oh->ntlv.name, oh->ntlv.set);
288        if (cfg == NULL) {
289                IPFW_UH_WUNLOCK(ch);
290                return (EEXIST);
291        }
292
293        /*
294         * For now allow to change only following values:
295         *  flags.
296         */
297
298        cfg->flags = uc->flags & NAT64STL_FLAGSMASK;
299        IPFW_UH_WUNLOCK(ch);
300        return (0);
301}
302
303static void
304nat64stl_detach_config(struct ip_fw_chain *ch, struct nat64stl_cfg *cfg)
305{
306
307        IPFW_UH_WLOCK_ASSERT(ch);
308
309        ipfw_objhash_del(CHAIN_TO_SRV(ch), &cfg->no);
310        ipfw_objhash_free_idx(CHAIN_TO_SRV(ch), cfg->no.kidx);
311        ipfw_unref_table(ch, cfg->map46);
312        ipfw_unref_table(ch, cfg->map64);
313}
314
315/*
316 * Destroys nat64 instance.
317 * Data layout (v0)(current):
318 * Request: [ ipfw_obj_header ]
319 *
320 * Returns 0 on success
321 */
322static int
323nat64stl_destroy(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
324    struct sockopt_data *sd)
325{
326        ipfw_obj_header *oh;
327        struct nat64stl_cfg *cfg;
328
329        if (sd->valsize != sizeof(*oh))
330                return (EINVAL);
331
332        oh = (ipfw_obj_header *)sd->kbuf;
333        if (ipfw_check_object_name_generic(oh->ntlv.name) != 0)
334                return (EINVAL);
335
336        IPFW_UH_WLOCK(ch);
337        cfg = nat64stl_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set);
338        if (cfg == NULL) {
339                IPFW_UH_WUNLOCK(ch);
340                return (ESRCH);
341        }
342        if (cfg->no.refcnt > 0) {
343                IPFW_UH_WUNLOCK(ch);
344                return (EBUSY);
345        }
346
347        IPFW_WLOCK(ch);
348        SRV_OBJECT(ch, cfg->no.kidx) = NULL;
349        IPFW_WUNLOCK(ch);
350
351        nat64stl_detach_config(ch, cfg);
352        IPFW_UH_WUNLOCK(ch);
353
354        nat64stl_free_config(cfg);
355        return (0);
356}
357
358/*
359 * Lists all nat64stl instances currently available in kernel.
360 * Data layout (v0)(current):
361 * Request: [ ipfw_obj_lheader ]
362 * Reply: [ ipfw_obj_lheader ipfw_nat64stl_cfg x N ]
363 *
364 * Returns 0 on success
365 */
366static int
367nat64stl_list(struct ip_fw_chain *ch, ip_fw3_opheader *op3,
368    struct sockopt_data *sd)
369{
370        ipfw_obj_lheader *olh;
371        struct nat64stl_dump_arg da;
372
373        /* Check minimum header size */
374        if (sd->valsize < sizeof(ipfw_obj_lheader))
375                return (EINVAL);
376
377        olh = (ipfw_obj_lheader *)ipfw_get_sopt_header(sd, sizeof(*olh));
378
379        IPFW_UH_RLOCK(ch);
380        olh->count = ipfw_objhash_count_type(CHAIN_TO_SRV(ch),
381            IPFW_TLV_NAT64STL_NAME);
382        olh->objsize = sizeof(ipfw_nat64stl_cfg);
383        olh->size = sizeof(*olh) + olh->count * olh->objsize;
384
385        if (sd->valsize < olh->size) {
386                IPFW_UH_RUNLOCK(ch);
387                return (ENOMEM);
388        }
389        memset(&da, 0, sizeof(da));
390        da.ch = ch;
391        da.sd = sd;
392        ipfw_objhash_foreach_type(CHAIN_TO_SRV(ch), export_config_cb,
393            &da, IPFW_TLV_NAT64STL_NAME);
394        IPFW_UH_RUNLOCK(ch);
395
396        return (0);
397}
398
399#define __COPY_STAT_FIELD(_cfg, _stats, _field) \
400        (_stats)->_field = NAT64STAT_FETCH(&(_cfg)->stats, _field)
401static void
402export_stats(struct ip_fw_chain *ch, struct nat64stl_cfg *cfg,
403    struct ipfw_nat64stl_stats *stats)
404{
405
406        __COPY_STAT_FIELD(cfg, stats, opcnt64);
407        __COPY_STAT_FIELD(cfg, stats, opcnt46);
408        __COPY_STAT_FIELD(cfg, stats, ofrags);
409        __COPY_STAT_FIELD(cfg, stats, ifrags);
410        __COPY_STAT_FIELD(cfg, stats, oerrors);
411        __COPY_STAT_FIELD(cfg, stats, noroute4);
412        __COPY_STAT_FIELD(cfg, stats, noroute6);
413        __COPY_STAT_FIELD(cfg, stats, noproto);
414        __COPY_STAT_FIELD(cfg, stats, nomem);
415        __COPY_STAT_FIELD(cfg, stats, dropped);
416}
417
418/*
419 * Get nat64stl statistics.
420 * Data layout (v0)(current):
421 * Request: [ ipfw_obj_header ]
422 * Reply: [ ipfw_obj_header ipfw_obj_ctlv [ uint64_t x N ]]
423 *
424 * Returns 0 on success
425 */
426static int
427nat64stl_stats(struct ip_fw_chain *ch, ip_fw3_opheader *op,
428    struct sockopt_data *sd)
429{
430        struct ipfw_nat64stl_stats stats;
431        struct nat64stl_cfg *cfg;
432        ipfw_obj_header *oh;
433        ipfw_obj_ctlv *ctlv;
434        size_t sz;
435
436        sz = sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ctlv) + sizeof(stats);
437        if (sd->valsize % sizeof(uint64_t))
438                return (EINVAL);
439        if (sd->valsize < sz)
440                return (ENOMEM);
441        oh = (ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
442        if (oh == NULL)
443                return (EINVAL);
444        memset(&stats, 0, sizeof(stats));
445
446        IPFW_UH_RLOCK(ch);
447        cfg = nat64stl_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set);
448        if (cfg == NULL) {
449                IPFW_UH_RUNLOCK(ch);
450                return (ESRCH);
451        }
452        export_stats(ch, cfg, &stats);
453        IPFW_UH_RUNLOCK(ch);
454
455        ctlv = (ipfw_obj_ctlv *)(oh + 1);
456        memset(ctlv, 0, sizeof(*ctlv));
457        ctlv->head.type = IPFW_TLV_COUNTERS;
458        ctlv->head.length = sz - sizeof(ipfw_obj_header);
459        ctlv->count = sizeof(stats) / sizeof(uint64_t);
460        ctlv->objsize = sizeof(uint64_t);
461        ctlv->version = IPFW_NAT64_VERSION;
462        memcpy(ctlv + 1, &stats, sizeof(stats));
463        return (0);
464}
465
466/*
467 * Reset nat64stl statistics.
468 * Data layout (v0)(current):
469 * Request: [ ipfw_obj_header ]
470 *
471 * Returns 0 on success
472 */
473static int
474nat64stl_reset_stats(struct ip_fw_chain *ch, ip_fw3_opheader *op,
475    struct sockopt_data *sd)
476{
477        struct nat64stl_cfg *cfg;
478        ipfw_obj_header *oh;
479
480        if (sd->valsize != sizeof(*oh))
481                return (EINVAL);
482        oh = (ipfw_obj_header *)sd->kbuf;
483        if (ipfw_check_object_name_generic(oh->ntlv.name) != 0 ||
484            oh->ntlv.set >= IPFW_MAX_SETS)
485                return (EINVAL);
486
487        IPFW_UH_WLOCK(ch);
488        cfg = nat64stl_find(CHAIN_TO_SRV(ch), oh->ntlv.name, oh->ntlv.set);
489        if (cfg == NULL) {
490                IPFW_UH_WUNLOCK(ch);
491                return (ESRCH);
492        }
493        COUNTER_ARRAY_ZERO(cfg->stats.stats, NAT64STATS);
494        IPFW_UH_WUNLOCK(ch);
495        return (0);
496}
497
498static struct ipfw_sopt_handler scodes[] = {
499
500        { IP_FW_NAT64STL_CREATE, 0,     HDIR_SET,       nat64stl_create },
501        { IP_FW_NAT64STL_DESTROY,0,     HDIR_SET,       nat64stl_destroy },
502        { IP_FW_NAT64STL_CONFIG, 0,     HDIR_BOTH,      nat64stl_config },
503        { IP_FW_NAT64STL_LIST,   0,     HDIR_GET,       nat64stl_list },
504        { IP_FW_NAT64STL_STATS,  0,     HDIR_GET,       nat64stl_stats },
505        { IP_FW_NAT64STL_RESET_STATS,0, HDIR_SET,       nat64stl_reset_stats },
506};
507
508static int
509nat64stl_classify(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
510{
511        ipfw_insn *icmd;
512
513        icmd = cmd - 1;
514        if (icmd->opcode != O_EXTERNAL_ACTION ||
515            icmd->arg1 != V_nat64stl_eid)
516                return (1);
517
518        *puidx = cmd->arg1;
519        *ptype = 0;
520        return (0);
521}
522
523static void
524nat64stl_update_arg1(ipfw_insn *cmd, uint16_t idx)
525{
526
527        cmd->arg1 = idx;
528}
529
530static int
531nat64stl_findbyname(struct ip_fw_chain *ch, struct tid_info *ti,
532    struct named_object **pno)
533{
534        int err;
535
536        err = ipfw_objhash_find_type(CHAIN_TO_SRV(ch), ti,
537            IPFW_TLV_NAT64STL_NAME, pno);
538        return (err);
539}
540
541static struct named_object *
542nat64stl_findbykidx(struct ip_fw_chain *ch, uint16_t idx)
543{
544        struct namedobj_instance *ni;
545        struct named_object *no;
546
547        IPFW_UH_WLOCK_ASSERT(ch);
548        ni = CHAIN_TO_SRV(ch);
549        no = ipfw_objhash_lookup_kidx(ni, idx);
550        KASSERT(no != NULL, ("NAT with index %d not found", idx));
551
552        return (no);
553}
554
555static int
556nat64stl_manage_sets(struct ip_fw_chain *ch, uint16_t set, uint8_t new_set,
557    enum ipfw_sets_cmd cmd)
558{
559
560        return (ipfw_obj_manage_sets(CHAIN_TO_SRV(ch), IPFW_TLV_NAT64STL_NAME,
561            set, new_set, cmd));
562}
563
564static struct opcode_obj_rewrite opcodes[] = {
565        {
566                .opcode = O_EXTERNAL_INSTANCE,
567                .etlv = IPFW_TLV_EACTION /* just show it isn't table */,
568                .classifier = nat64stl_classify,
569                .update = nat64stl_update_arg1,
570                .find_byname = nat64stl_findbyname,
571                .find_bykidx = nat64stl_findbykidx,
572                .manage_sets = nat64stl_manage_sets,
573        },
574};
575
576static int
577destroy_config_cb(struct namedobj_instance *ni, struct named_object *no,
578    void *arg)
579{
580        struct nat64stl_cfg *cfg;
581        struct ip_fw_chain *ch;
582
583        ch = (struct ip_fw_chain *)arg;
584        cfg = (struct nat64stl_cfg *)SRV_OBJECT(ch, no->kidx);
585        SRV_OBJECT(ch, no->kidx) = NULL;
586        nat64stl_detach_config(ch, cfg);
587        nat64stl_free_config(cfg);
588        return (0);
589}
590
591int
592nat64stl_init(struct ip_fw_chain *ch, int first)
593{
594
595        V_nat64stl_eid = ipfw_add_eaction(ch, ipfw_nat64stl, "nat64stl");
596        if (V_nat64stl_eid == 0)
597                return (ENXIO);
598        IPFW_ADD_SOPT_HANDLER(first, scodes);
599        IPFW_ADD_OBJ_REWRITER(first, opcodes);
600        return (0);
601}
602
603void
604nat64stl_uninit(struct ip_fw_chain *ch, int last)
605{
606
607        IPFW_DEL_OBJ_REWRITER(last, opcodes);
608        IPFW_DEL_SOPT_HANDLER(last, scodes);
609        ipfw_del_eaction(ch, V_nat64stl_eid);
610        /*
611         * Since we already have deregistered external action,
612         * our named objects become unaccessible via rules, because
613         * all rules were truncated by ipfw_del_eaction().
614         * So, we can unlink and destroy our named objects without holding
615         * IPFW_WLOCK().
616         */
617        IPFW_UH_WLOCK(ch);
618        ipfw_objhash_foreach_type(CHAIN_TO_SRV(ch), destroy_config_cb, ch,
619            IPFW_TLV_NAT64STL_NAME);
620        V_nat64stl_eid = 0;
621        IPFW_UH_WUNLOCK(ch);
622}
623
Note: See TracBrowser for help on using the repository browser.