1145519Sdarrenr/*	$FreeBSD$	*/
2145510Sdarrenr
3145510Sdarrenr/*
4255332Scy * Copyright (C) 2012 by Darren Reed.
5145510Sdarrenr *
6145510Sdarrenr * See the IPFILTER.LICENCE file for details on licencing.
7145510Sdarrenr *
8255332Scy * $Id$
9145510Sdarrenr */
10145510Sdarrenr
11145510Sdarrenr#include <fcntl.h>
12145510Sdarrenr#include <sys/ioctl.h>
13145510Sdarrenr#include "ipf.h"
14145510Sdarrenr#include "netinet/ip_lookup.h"
15145510Sdarrenr#include "netinet/ip_htable.h"
16145510Sdarrenr
17145510Sdarrenr
18255332Scyint
19255332Scyload_hash(iphp, list, iocfunc)
20255332Scy	iphtable_t *iphp;
21255332Scy	iphtent_t *list;
22255332Scy	ioctlfunc_t iocfunc;
23145510Sdarrenr{
24145510Sdarrenr	iplookupop_t op;
25145510Sdarrenr	iphtable_t iph;
26145510Sdarrenr	iphtent_t *a;
27145510Sdarrenr	size_t size;
28145510Sdarrenr	int n;
29145510Sdarrenr
30255332Scy	if (pool_open() == -1)
31145510Sdarrenr		return -1;
32145510Sdarrenr
33145510Sdarrenr	for (n = 0, a = list; a != NULL; a = a->ipe_next)
34145510Sdarrenr		n++;
35145510Sdarrenr
36255332Scy	bzero((char *)&iph, sizeof(iph));
37145510Sdarrenr	op.iplo_arg = 0;
38145510Sdarrenr	op.iplo_type = IPLT_HASH;
39145510Sdarrenr	op.iplo_unit = iphp->iph_unit;
40145510Sdarrenr	strncpy(op.iplo_name, iphp->iph_name, sizeof(op.iplo_name));
41145510Sdarrenr	if (*op.iplo_name == '\0')
42145510Sdarrenr		op.iplo_arg = IPHASH_ANON;
43145510Sdarrenr	op.iplo_size = sizeof(iph);
44145510Sdarrenr	op.iplo_struct = &iph;
45255332Scy	iph = *iphp;
46145510Sdarrenr	if (n <= 0)
47145510Sdarrenr		n = 1;
48145510Sdarrenr	if (iphp->iph_size == 0)
49145510Sdarrenr		size = n * 2 - 1;
50145510Sdarrenr	else
51145510Sdarrenr		size = iphp->iph_size;
52145510Sdarrenr	if ((list == NULL) && (size == 1)) {
53145510Sdarrenr		fprintf(stderr,
54145510Sdarrenr			"WARNING: empty hash table %s, recommend setting %s\n",
55145510Sdarrenr			iphp->iph_name, "size to match expected use");
56145510Sdarrenr	}
57145510Sdarrenr	iph.iph_size = size;
58145510Sdarrenr	iph.iph_table = NULL;
59170268Sdarrenr	iph.iph_list = NULL;
60145510Sdarrenr	iph.iph_ref = 0;
61145510Sdarrenr
62145510Sdarrenr	if ((opts & OPT_REMOVE) == 0) {
63255332Scy		if (pool_ioctl(iocfunc, SIOCLOOKUPADDTABLE, &op))
64145510Sdarrenr			if ((opts & OPT_DONOTHING) == 0) {
65255332Scy				return ipf_perror_fd(pool_fd(), iocfunc,
66255332Scy					"add lookup hash table");
67145510Sdarrenr			}
68145510Sdarrenr	}
69145510Sdarrenr
70153881Sguido	strncpy(iph.iph_name, op.iplo_name, sizeof(op.iplo_name));
71153881Sguido	strncpy(iphp->iph_name, op.iplo_name, sizeof(op.iplo_name));
72145510Sdarrenr
73145510Sdarrenr	if (opts & OPT_VERBOSE) {
74145510Sdarrenr		iph.iph_table = calloc(size, sizeof(*iph.iph_table));
75145510Sdarrenr		if (iph.iph_table == NULL) {
76145510Sdarrenr			perror("calloc(size, sizeof(*iph.iph_table))");
77145510Sdarrenr			return -1;
78145510Sdarrenr		}
79170268Sdarrenr		iph.iph_list = list;
80255332Scy		printhash(&iph, bcopywrap, iph.iph_name, opts, NULL);
81145510Sdarrenr		free(iph.iph_table);
82145510Sdarrenr
83145510Sdarrenr		for (a = list; a != NULL; a = a->ipe_next) {
84145510Sdarrenr			a->ipe_addr.in4_addr = htonl(a->ipe_addr.in4_addr);
85145510Sdarrenr			a->ipe_mask.in4_addr = htonl(a->ipe_mask.in4_addr);
86145510Sdarrenr		}
87145510Sdarrenr	}
88145510Sdarrenr
89145510Sdarrenr	if (opts & OPT_DEBUG)
90145510Sdarrenr		printf("Hash %s:\n", iph.iph_name);
91145510Sdarrenr
92145510Sdarrenr	for (a = list; a != NULL; a = a->ipe_next)
93255332Scy		load_hashnode(iphp->iph_unit, iph.iph_name, a, 0, iocfunc);
94145510Sdarrenr
95145510Sdarrenr	if ((opts & OPT_REMOVE) != 0) {
96255332Scy		if (pool_ioctl(iocfunc, SIOCLOOKUPDELTABLE, &op))
97145510Sdarrenr			if ((opts & OPT_DONOTHING) == 0) {
98255332Scy				return ipf_perror_fd(pool_fd(), iocfunc,
99255332Scy					"delete lookup hash table");
100145510Sdarrenr			}
101145510Sdarrenr	}
102145510Sdarrenr	return 0;
103145510Sdarrenr}
104