xref: /titanic_50/usr/src/cmd/tsol/tnd/tnd.c (revision f875b4ebb1dd9fdbeb043557cab38ab3bf7f6e01)
1*f875b4ebSrica /*
2*f875b4ebSrica  * CDDL HEADER START
3*f875b4ebSrica  *
4*f875b4ebSrica  * The contents of this file are subject to the terms of the
5*f875b4ebSrica  * Common Development and Distribution License (the "License").
6*f875b4ebSrica  * You may not use this file except in compliance with the License.
7*f875b4ebSrica  *
8*f875b4ebSrica  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*f875b4ebSrica  * or http://www.opensolaris.org/os/licensing.
10*f875b4ebSrica  * See the License for the specific language governing permissions
11*f875b4ebSrica  * and limitations under the License.
12*f875b4ebSrica  *
13*f875b4ebSrica  * When distributing Covered Code, include this CDDL HEADER in each
14*f875b4ebSrica  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*f875b4ebSrica  * If applicable, add the following below this CDDL HEADER, with the
16*f875b4ebSrica  * fields enclosed by brackets "[]" replaced with your own identifying
17*f875b4ebSrica  * information: Portions Copyright [yyyy] [name of copyright owner]
18*f875b4ebSrica  *
19*f875b4ebSrica  * CDDL HEADER END
20*f875b4ebSrica  */
21*f875b4ebSrica 
22*f875b4ebSrica /*
23*f875b4ebSrica  *  Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24*f875b4ebSrica  *  Use is subject to license terms.
25*f875b4ebSrica  */
26*f875b4ebSrica 
27*f875b4ebSrica #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*f875b4ebSrica 
29*f875b4ebSrica #include <sys/types.h>
30*f875b4ebSrica #include <time.h>
31*f875b4ebSrica #include <unistd.h>
32*f875b4ebSrica #include <stdio.h>
33*f875b4ebSrica #include <sys/fcntl.h>
34*f875b4ebSrica #include <sys/stat.h>
35*f875b4ebSrica #include <fcntl.h>
36*f875b4ebSrica #include <locale.h>
37*f875b4ebSrica #include <langinfo.h>
38*f875b4ebSrica #include <search.h>
39*f875b4ebSrica #include <tsol/label.h>
40*f875b4ebSrica #include <errno.h>
41*f875b4ebSrica #include <sys/tsol/tndb.h>
42*f875b4ebSrica #include <sys/socket.h>
43*f875b4ebSrica #include <netinet/in.h>
44*f875b4ebSrica #include <arpa/inet.h>
45*f875b4ebSrica #include <netdb.h>
46*f875b4ebSrica #include <signal.h>
47*f875b4ebSrica #include <sys/signal.h>
48*f875b4ebSrica #include <string.h>
49*f875b4ebSrica #include <stdlib.h>
50*f875b4ebSrica #include <unistd.h>
51*f875b4ebSrica #include <stdarg.h>
52*f875b4ebSrica #include <syslog.h>
53*f875b4ebSrica #include <ctype.h>
54*f875b4ebSrica #include <pwd.h>
55*f875b4ebSrica #include <grp.h>
56*f875b4ebSrica #include <door.h>
57*f875b4ebSrica #include <synch.h>
58*f875b4ebSrica #include <sys/tsol/tsyscall.h>
59*f875b4ebSrica #include <nss_dbdefs.h>
60*f875b4ebSrica #include <libtsnet.h>
61*f875b4ebSrica #include <zone.h>
62*f875b4ebSrica 
63*f875b4ebSrica #include "tnd.h"
64*f875b4ebSrica 
65*f875b4ebSrica static FILE *tnlog_open(char *);
66*f875b4ebSrica static void usage();
67*f875b4ebSrica static void parse_opts(int, char **);
68*f875b4ebSrica static int check_debugl(int);
69*f875b4ebSrica static void load_tp();
70*f875b4ebSrica static void load_tp_entry();
71*f875b4ebSrica static void tnd_serve();
72*f875b4ebSrica static void detachfromtty();
73*f875b4ebSrica static void terminate();
74*f875b4ebSrica static void noop();
75*f875b4ebSrica static char *gettime();
76*f875b4ebSrica static int isnumber(char *);
77*f875b4ebSrica static void poll_now();
78*f875b4ebSrica static int nss_get_tp();
79*f875b4ebSrica static int nss_get_rh();
80*f875b4ebSrica static void timer();
81*f875b4ebSrica static void load_rh_marked();
82*f875b4ebSrica static int rhtable_search_and_update(struct tsol_rhent *ent, int duplflag);
83*f875b4ebSrica static int is_better_match(in_addr_t newaddr, int indx, tnrh_tlb_t *tlbt);
84*f875b4ebSrica static int walk_cache_table(in_addr_t newaddr, char *name,
85*f875b4ebSrica     int indx, tnd_tnrhdb_t *src);
86*f875b4ebSrica static tnrh_tlb_t *lookup_cache_table(in_addr_t addr);
87*f875b4ebSrica static int update_cache_table(tsol_rhent_t *ent, tnd_tnrhdb_t *src);
88*f875b4ebSrica static void update_rh_entry(int op, struct tsol_rhent *rhentp);
89*f875b4ebSrica static int handle_unvisited_nodes();
90*f875b4ebSrica static in_addr_t rh_index_to_mask(uint_t masklen);
91*f875b4ebSrica static tnrh_tlb_ipv6_t *lookup_cache_table_v6(in6_addr_t addr);
92*f875b4ebSrica static in6_addr_t *rh_index_to_mask_v6(uint_t masklen, in6_addr_t *bitmask);
93*f875b4ebSrica static void load_rh_marked_v6();
94*f875b4ebSrica static int
95*f875b4ebSrica     rhtable_search_and_update_v6(struct tsol_rhent *ent, int duplflag);
96*f875b4ebSrica static int walk_cache_table_v6(in6_addr_t newaddr, char *name,
97*f875b4ebSrica     int indx, tnd_tnrhdb_t *src);
98*f875b4ebSrica static int update_cache_table_v6(tsol_rhent_t *ent, tnd_tnrhdb_t *src);
99*f875b4ebSrica static int handle_unvisited_nodes_v6();
100*f875b4ebSrica 
101*f875b4ebSrica #ifdef DEBUG
102*f875b4ebSrica static void print_entry(tsol_rhent_t *ent, int af);
103*f875b4ebSrica static void print_tlbt(tnrh_tlb_t *tlbt);
104*f875b4ebSrica static void rhtable_print();
105*f875b4ebSrica static void cachetable_print();
106*f875b4ebSrica static void rhtable_walk(void (*action)());
107*f875b4ebSrica static void cachetable_print_v6();
108*f875b4ebSrica static void rhtable_print_v6();
109*f875b4ebSrica static void rhtable_walk_v6(void (*action)());
110*f875b4ebSrica #endif /* DEBUG */
111*f875b4ebSrica 
112*f875b4ebSrica /*
113*f875b4ebSrica  * The following constants and structures and the functions
114*f875b4ebSrica  * that operate on them are similar to the ip_ire.c and ip6_ire.c
115*f875b4ebSrica  * code in the kernel.
116*f875b4ebSrica  */
117*f875b4ebSrica #define	TNRH_TABLE_HASH_SIZE 256
118*f875b4ebSrica #define	IP_ABITS 32
119*f875b4ebSrica #define	IP_MASK_TABLE_SIZE (IP_ABITS + 1)
120*f875b4ebSrica #define	RH_HOST_MASK (in_addr_t)0xffffffffU
121*f875b4ebSrica 
122*f875b4ebSrica #define	IPV6_ABITS 128
123*f875b4ebSrica #define	IPV6_MASK_TABLE_SIZE (IPV6_ABITS + 1)
124*f875b4ebSrica #define	s6_addr8 _S6_un._S6_u8
125*f875b4ebSrica #define	s6_addr32 _S6_un._S6_u32
126*f875b4ebSrica 
127*f875b4ebSrica /*
128*f875b4ebSrica  * Exclusive-or the 6 bytes that are likely to contain the MAC
129*f875b4ebSrica  * address. Assumes table_size does not exceed 256.
130*f875b4ebSrica  * Assumes EUI-64 format for good hashing.
131*f875b4ebSrica  */
132*f875b4ebSrica #define	TNRH_ADDR_HASH_V6(addr)				\
133*f875b4ebSrica 	(((addr).s6_addr8[8] ^ (addr).s6_addr8[9] ^	\
134*f875b4ebSrica 	(addr).s6_addr8[10] ^ (addr).s6_addr8[13] ^	\
135*f875b4ebSrica 	(addr).s6_addr8[14] ^ (addr).s6_addr8[15]) % TNRH_TABLE_HASH_SIZE)
136*f875b4ebSrica 
137*f875b4ebSrica #define	TNRH_ADDR_MASK_HASH_V6(addr, mask)	\
138*f875b4ebSrica 	((((addr).s6_addr8[8] & (mask).s6_addr8[8]) ^	\
139*f875b4ebSrica 	((addr).s6_addr8[9] & (mask).s6_addr8[9]) ^	\
140*f875b4ebSrica 	((addr).s6_addr8[10] & (mask).s6_addr8[10]) ^	\
141*f875b4ebSrica 	((addr).s6_addr8[13] & (mask).s6_addr8[13]) ^	\
142*f875b4ebSrica 	((addr).s6_addr8[14] & (mask).s6_addr8[14]) ^	\
143*f875b4ebSrica 	((addr).s6_addr8[15] & (mask).s6_addr8[15])) % TNRH_TABLE_HASH_SIZE)
144*f875b4ebSrica 
145*f875b4ebSrica /* Mask comparison: is IPv6 addr a, and'ed with mask m, equal to addr b? */
146*f875b4ebSrica #define	V6_MASK_EQ(a, m, b)	\
147*f875b4ebSrica 	((((a).s6_addr32[0] & (m).s6_addr32[0]) == (b).s6_addr32[0]) && \
148*f875b4ebSrica 	(((a).s6_addr32[1] & (m).s6_addr32[1]) == (b).s6_addr32[1]) &&  \
149*f875b4ebSrica 	(((a).s6_addr32[2] & (m).s6_addr32[2]) == (b).s6_addr32[2]) &&  \
150*f875b4ebSrica 	(((a).s6_addr32[3] & (m).s6_addr32[3]) == (b).s6_addr32[3]))
151*f875b4ebSrica 
152*f875b4ebSrica 
153*f875b4ebSrica const in6_addr_t ipv6_all_zeros = { 0, 0, 0, 0 };
154*f875b4ebSrica 
155*f875b4ebSrica /*
156*f875b4ebSrica  * This is a table of hash tables to keep
157*f875b4ebSrica  * all the name service entries. We don't have
158*f875b4ebSrica  * a separate hash bucket structure, instead mantain
159*f875b4ebSrica  * a pointer to the hash chain.
160*f875b4ebSrica  */
161*f875b4ebSrica tnd_tnrhdb_t **tnrh_entire_table[IP_MASK_TABLE_SIZE];
162*f875b4ebSrica tnd_tnrhdb_t **tnrh_entire_table_v6[IPV6_MASK_TABLE_SIZE];
163*f875b4ebSrica 
164*f875b4ebSrica /* reader/writer lock for tnrh_entire_table */
165*f875b4ebSrica rwlock_t entire_rwlp;
166*f875b4ebSrica rwlock_t entire_rwlp_v6;
167*f875b4ebSrica 
168*f875b4ebSrica 
169*f875b4ebSrica /*
170*f875b4ebSrica  * This is a hash table which keeps fully resolved
171*f875b4ebSrica  * tnrhdb entries <IP address, Host type>. We don't have
172*f875b4ebSrica  * a separate hash bucket structure, instead
173*f875b4ebSrica  * mantain a pointer to the hash chain.
174*f875b4ebSrica  */
175*f875b4ebSrica tnrh_tlb_t *tnrh_cache_table[TNRH_TABLE_HASH_SIZE];
176*f875b4ebSrica tnrh_tlb_ipv6_t *tnrh_cache_table_v6[TNRH_TABLE_HASH_SIZE];
177*f875b4ebSrica 
178*f875b4ebSrica /* reader/writer lock for tnrh_cache_table */
179*f875b4ebSrica rwlock_t cache_rwlp;
180*f875b4ebSrica rwlock_t cache_rwlp_v6;
181*f875b4ebSrica 
182*f875b4ebSrica FILE	 *logf;
183*f875b4ebSrica int	 debugl = 0;
184*f875b4ebSrica int	 poll_interval = TND_DEF_POLL_TIME;
185*f875b4ebSrica int	 delay_poll_flag = 0;
186*f875b4ebSrica 
187*f875b4ebSrica void	*tp_tree;
188*f875b4ebSrica 
189*f875b4ebSrica #define	_SZ_TIME_BUF 100
190*f875b4ebSrica char time_buf[_SZ_TIME_BUF];
191*f875b4ebSrica 
192*f875b4ebSrica #define	cprint(s, param) { \
193*f875b4ebSrica 		register FILE *consl; \
194*f875b4ebSrica \
195*f875b4ebSrica 		if ((consl = fopen("/dev/msglog", "w")) != NULL) { \
196*f875b4ebSrica 		    setbuf(consl, NULL); \
197*f875b4ebSrica 		    (void) fprintf(consl, "tnd: "); \
198*f875b4ebSrica 		    (void) fprintf(consl, s, param); \
199*f875b4ebSrica 		    (void) fclose(consl); \
200*f875b4ebSrica 			} \
201*f875b4ebSrica 	    }
202*f875b4ebSrica 
203*f875b4ebSrica #define	RHENT_BUF_SIZE 300
204*f875b4ebSrica #define	TPENT_BUF_SIZE 2000
205*f875b4ebSrica 
206*f875b4ebSrica /* 128 privs * (24 bytes + 1 deliminator)= 3200 bytes + 1200 cushion */
207*f875b4ebSrica #define	STRING_PRIVS_SIZE 4800
208*f875b4ebSrica #define	ID_ENT_SIZE 500
209*f875b4ebSrica 
210*f875b4ebSrica main(int argc, char **argv)
211*f875b4ebSrica {
212*f875b4ebSrica 
213*f875b4ebSrica 
214*f875b4ebSrica 	const ucred_t	*uc = NULL;
215*f875b4ebSrica 	const priv_set_t	*pset;
216*f875b4ebSrica 	struct sigaction act;
217*f875b4ebSrica 
218*f875b4ebSrica 	/* set the locale for only the messages system (all else is clean) */
219*f875b4ebSrica 	(void) setlocale(LC_ALL, "");
220*f875b4ebSrica #ifndef TEXT_DOMAIN			/* Should be defined by cc -D */
221*f875b4ebSrica #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it weren't */
222*f875b4ebSrica #endif
223*f875b4ebSrica 	(void) textdomain(TEXT_DOMAIN);
224*f875b4ebSrica 
225*f875b4ebSrica 	if (getzoneid() != GLOBAL_ZONEID) {
226*f875b4ebSrica 		syslog(LOG_ERR,	"can not run tnd from a local zone");
227*f875b4ebSrica 		exit(-1);
228*f875b4ebSrica 	}
229*f875b4ebSrica 
230*f875b4ebSrica 
231*f875b4ebSrica 	if (((uc = ucred_get(getpid())) == NULL) ||
232*f875b4ebSrica 	    ((pset = ucred_getprivset(uc, PRIV_EFFECTIVE)) == NULL)) {
233*f875b4ebSrica 		syslog(LOG_ERR,	"don't have privilege set");
234*f875b4ebSrica 		exit(-1);
235*f875b4ebSrica 	}
236*f875b4ebSrica 
237*f875b4ebSrica 	if (!priv_ismember(pset, PRIV_SYS_NET_CONFIG)) {
238*f875b4ebSrica 		syslog(LOG_ERR,	"don't have privilege to run tnd");
239*f875b4ebSrica 		exit(-1);
240*f875b4ebSrica 	}
241*f875b4ebSrica 
242*f875b4ebSrica 
243*f875b4ebSrica 	/* parse command line options */
244*f875b4ebSrica 	(void) parse_opts(argc, argv);
245*f875b4ebSrica 
246*f875b4ebSrica 	/*
247*f875b4ebSrica 	 * Initialize reader/writer locks. To be
248*f875b4ebSrica 	 * used within this process only.
249*f875b4ebSrica 	 */
250*f875b4ebSrica 	if ((rwlock_init(&entire_rwlp, USYNC_THREAD, 0) != 0) ||
251*f875b4ebSrica 	    (rwlock_init(&entire_rwlp_v6, USYNC_THREAD, 0) != 0) ||
252*f875b4ebSrica 	    (rwlock_init(&cache_rwlp, USYNC_THREAD, 0) != 0) ||
253*f875b4ebSrica 	    (rwlock_init(&cache_rwlp_v6, USYNC_THREAD, 0) != 0)) {
254*f875b4ebSrica 		syslog(LOG_ERR, "cannot initialize lock");
255*f875b4ebSrica 		exit(-1);
256*f875b4ebSrica 	}
257*f875b4ebSrica 
258*f875b4ebSrica 	/* catch the usual termination signals for graceful exit */
259*f875b4ebSrica 	(void) sigset(SIGINT, terminate);
260*f875b4ebSrica 	(void) sigset(SIGTERM, terminate);
261*f875b4ebSrica 	(void) sigset(SIGQUIT, terminate);
262*f875b4ebSrica 	(void) sigset(SIGUSR1, noop);
263*f875b4ebSrica 
264*f875b4ebSrica 	act.sa_handler = timer;
265*f875b4ebSrica 	act.sa_flags = SA_RESTART;
266*f875b4ebSrica 	(void *) sigemptyset(&act.sa_mask);
267*f875b4ebSrica 	(void *) sigaddset(&act.sa_mask, SIGALRM);
268*f875b4ebSrica 	(void *) sigaddset(&act.sa_mask, SIGHUP);
269*f875b4ebSrica 	(void *) sigaction(SIGALRM, &act, NULL);
270*f875b4ebSrica 	(void *) sigaction(SIGHUP, &act, NULL);
271*f875b4ebSrica 
272*f875b4ebSrica 	if (debugl == MAX_TND_DEBUG) {
273*f875b4ebSrica 		(void) fprintf(logf, "%s : ", gettime());
274*f875b4ebSrica 		(void) fprintf(logf, gettext("tnd started. pid= %d\n"),
275*f875b4ebSrica 		    getpid());
276*f875b4ebSrica 		(void) fprintf(logf, "%s : ", gettime());
277*f875b4ebSrica 		(void) fprintf(logf,
278*f875b4ebSrica 		    gettext("max level debugging! not forking\n"));
279*f875b4ebSrica 		(void) fflush(logf);
280*f875b4ebSrica 	} else {
281*f875b4ebSrica 		detachfromtty();
282*f875b4ebSrica 	}
283*f875b4ebSrica 
284*f875b4ebSrica 	if (!delay_poll_flag) {
285*f875b4ebSrica 		(void) sigprocmask(SIG_BLOCK, &act.sa_mask, NULL);
286*f875b4ebSrica 		timer();
287*f875b4ebSrica 		(void) sigprocmask(SIG_UNBLOCK, &act.sa_mask, NULL);
288*f875b4ebSrica 	}
289*f875b4ebSrica 
290*f875b4ebSrica 	if (debugl != MAX_TND_DEBUG) {
291*f875b4ebSrica 		(void) sigsend(P_PID, getppid(), SIGUSR1);
292*f875b4ebSrica 	}
293*f875b4ebSrica 
294*f875b4ebSrica 	(void) tnd_serve();
295*f875b4ebSrica 
296*f875b4ebSrica 	/* NOT REACHED */
297*f875b4ebSrica 	return (0);
298*f875b4ebSrica }
299*f875b4ebSrica 
300*f875b4ebSrica 
301*f875b4ebSrica /*
302*f875b4ebSrica  * Compare addresses after masking off unneeded bits.
303*f875b4ebSrica  * We do this to handle addresses where prefix_len is
304*f875b4ebSrica  * less than the bit length.
305*f875b4ebSrica  */
306*f875b4ebSrica static int
307*f875b4ebSrica rhaddr_compar_mask(struct sockaddr_in *tp1, struct tnd_tnrhdb_c *tp2, int i)
308*f875b4ebSrica {
309*f875b4ebSrica 	struct sockaddr_in *saddrp;
310*f875b4ebSrica 	in_addr_t tmpmask = rh_index_to_mask(i);
311*f875b4ebSrica 
312*f875b4ebSrica 	saddrp = (struct sockaddr_in *)(&tp2->rh_ent.rh_address.ip_addr_v4);
313*f875b4ebSrica 
314*f875b4ebSrica #ifdef DEBUG
315*f875b4ebSrica 	(void) fprintf(logf, gettext("rhaddr_compar_mask mask = 0x%4x, \
316*f875b4ebSrica 	    tp1 = 0x%4x, tp2 = 0x%4x\n"), tmpmask, (tp1->sin_addr),
317*f875b4ebSrica 	    (saddrp->sin_addr.s_addr & tmpmask));
318*f875b4ebSrica 	(void) fprintf(logf, gettext("rhaddr_compar_mask return = %d\n"),
319*f875b4ebSrica 	    (tp1->sin_addr.s_addr == (saddrp->sin_addr.s_addr & tmpmask)));
320*f875b4ebSrica #endif
321*f875b4ebSrica 	return (tp1->sin_addr.s_addr == (saddrp->sin_addr.s_addr & tmpmask));
322*f875b4ebSrica }
323*f875b4ebSrica 
324*f875b4ebSrica 
325*f875b4ebSrica /*
326*f875b4ebSrica  * we use this where exact match is needed.
327*f875b4ebSrica  */
328*f875b4ebSrica static int
329*f875b4ebSrica rhaddr_compar(struct sockaddr_in *tp1, struct tnd_tnrhdb_c *tp2)
330*f875b4ebSrica {
331*f875b4ebSrica 	struct sockaddr_in *saddrp;
332*f875b4ebSrica 
333*f875b4ebSrica 	saddrp = (struct sockaddr_in *)(&tp2->rh_ent.rh_address.ip_addr_v4);
334*f875b4ebSrica 
335*f875b4ebSrica #ifdef DEBUG
336*f875b4ebSrica 	(void) fprintf(logf, gettext("\t tp1 saddrp IP : %s %s\n"),
337*f875b4ebSrica 	    inet_ntoa(tp1->sin_addr), inet_ntoa(saddrp->sin_addr));
338*f875b4ebSrica #endif
339*f875b4ebSrica 
340*f875b4ebSrica 	return (tp1->sin_addr.s_addr == saddrp->sin_addr.s_addr);
341*f875b4ebSrica }
342*f875b4ebSrica 
343*f875b4ebSrica /*
344*f875b4ebSrica  * Compare v6 addresses after masking off unneeded bits.
345*f875b4ebSrica  * We do this to handle addresses where prefix_len is
346*f875b4ebSrica  * less than the bit length.
347*f875b4ebSrica  */
348*f875b4ebSrica static int
349*f875b4ebSrica rhaddr_compar_mask_v6(struct sockaddr_in6 *tp1, struct tnd_tnrhdb_c *tp2, int i)
350*f875b4ebSrica {
351*f875b4ebSrica 	struct sockaddr_in6 *saddrp;
352*f875b4ebSrica 	in6_addr_t tmpmask;
353*f875b4ebSrica 
354*f875b4ebSrica 	(void) rh_index_to_mask_v6(i, &tmpmask);
355*f875b4ebSrica 	saddrp = (struct sockaddr_in6 *)(&tp2->rh_ent.rh_address.ip_addr_v6);
356*f875b4ebSrica 	return (V6_MASK_EQ(tp1->sin6_addr, tmpmask, saddrp->sin6_addr));
357*f875b4ebSrica }
358*f875b4ebSrica 
359*f875b4ebSrica /*
360*f875b4ebSrica  * we use this where v6 exact match is needed.
361*f875b4ebSrica  */
362*f875b4ebSrica static int
363*f875b4ebSrica rhaddr_compar_v6(struct sockaddr_in6 *tp1, struct tnd_tnrhdb_c *tp2)
364*f875b4ebSrica {
365*f875b4ebSrica 	struct sockaddr_in6 *saddrp;
366*f875b4ebSrica 
367*f875b4ebSrica 	saddrp = (struct sockaddr_in6 *)(&tp2->rh_ent.rh_address.ip_addr_v6);
368*f875b4ebSrica 	return (IN6_ARE_ADDR_EQUAL(&tp1->sin6_addr, &saddrp->sin6_addr));
369*f875b4ebSrica }
370*f875b4ebSrica 
371*f875b4ebSrica static int
372*f875b4ebSrica get_hashvalue(in_addr_t addr)
373*f875b4ebSrica {
374*f875b4ebSrica 	unsigned char *bp;
375*f875b4ebSrica 
376*f875b4ebSrica 	bp = (unsigned char *) &addr;
377*f875b4ebSrica 	return ((bp[0] ^ bp[1] ^ bp[2] ^ bp[3]) % TNRH_TABLE_HASH_SIZE);
378*f875b4ebSrica }
379*f875b4ebSrica 
380*f875b4ebSrica /*
381*f875b4ebSrica  * Convert length for a mask to the mask.
382*f875b4ebSrica  */
383*f875b4ebSrica static in_addr_t
384*f875b4ebSrica rh_index_to_mask(uint_t masklen)
385*f875b4ebSrica {
386*f875b4ebSrica 	if (masklen == 0)
387*f875b4ebSrica 		return (0);
388*f875b4ebSrica 	return (htonl(RH_HOST_MASK << (IP_ABITS - masklen)));
389*f875b4ebSrica }
390*f875b4ebSrica 
391*f875b4ebSrica /*
392*f875b4ebSrica  * Convert length for a mask to the mask.
393*f875b4ebSrica  * Returns the argument bitmask.
394*f875b4ebSrica  */
395*f875b4ebSrica static in6_addr_t *
396*f875b4ebSrica rh_index_to_mask_v6(uint_t masklen, in6_addr_t *bitmask)
397*f875b4ebSrica {
398*f875b4ebSrica 	uint32_t *ptr;
399*f875b4ebSrica 
400*f875b4ebSrica 	*bitmask = ipv6_all_zeros;
401*f875b4ebSrica 
402*f875b4ebSrica 	ptr = (uint32_t *)bitmask;
403*f875b4ebSrica 	while (masklen > 32) {
404*f875b4ebSrica 		*ptr++ = 0xffffffffU;
405*f875b4ebSrica 		masklen -= 32;
406*f875b4ebSrica 	}
407*f875b4ebSrica 	*ptr = htonl(0xffffffffU << (32 - masklen));
408*f875b4ebSrica 	return (bitmask);
409*f875b4ebSrica }
410*f875b4ebSrica 
411*f875b4ebSrica 
412*f875b4ebSrica static void
413*f875b4ebSrica parse_opts(argc, argv)
414*f875b4ebSrica 	int argc;
415*f875b4ebSrica 	char **argv;
416*f875b4ebSrica {
417*f875b4ebSrica 	char *logfile = TNDLOG;
418*f875b4ebSrica 	extern char *optarg;
419*f875b4ebSrica 	int c;
420*f875b4ebSrica 
421*f875b4ebSrica 	while ((c = getopt(argc, argv, "d:f:p:n")) != EOF)
422*f875b4ebSrica 	    switch (c) {
423*f875b4ebSrica 	    case 'd':
424*f875b4ebSrica 		if (isnumber(optarg)) {
425*f875b4ebSrica 		    debugl = atoi(optarg);
426*f875b4ebSrica 		    if (check_debugl(debugl) == -1)
427*f875b4ebSrica 		    debugl = 1; /* default to 1 */
428*f875b4ebSrica 		} else {
429*f875b4ebSrica 		    usage();
430*f875b4ebSrica 		    exit(1);
431*f875b4ebSrica 		}
432*f875b4ebSrica 		break;
433*f875b4ebSrica 	    case 'f':
434*f875b4ebSrica 		logfile = optarg;
435*f875b4ebSrica 		break;
436*f875b4ebSrica 	    case 'p':
437*f875b4ebSrica 		if (isnumber(optarg)) {
438*f875b4ebSrica 		    poll_interval = atoi(optarg);
439*f875b4ebSrica 		    if (poll_interval == 0)
440*f875b4ebSrica 			usage();
441*f875b4ebSrica 		} else {
442*f875b4ebSrica 		    usage();
443*f875b4ebSrica 		}
444*f875b4ebSrica 		break;
445*f875b4ebSrica 	    case 'n':
446*f875b4ebSrica 		delay_poll_flag = 1;
447*f875b4ebSrica 		break;
448*f875b4ebSrica 	    case '?':
449*f875b4ebSrica 		usage();
450*f875b4ebSrica 	    }
451*f875b4ebSrica 
452*f875b4ebSrica 	logf = tnlog_open(logfile);
453*f875b4ebSrica }
454*f875b4ebSrica 
455*f875b4ebSrica static int
456*f875b4ebSrica check_debugl(debug_level)
457*f875b4ebSrica 	int debug_level;
458*f875b4ebSrica {
459*f875b4ebSrica 	if (debug_level > MAX_TND_DEBUG) {
460*f875b4ebSrica 	    if ((debugl > 0) && (logf != NULL)) {
461*f875b4ebSrica 		(void) fprintf(logf, "%s : ", gettime());
462*f875b4ebSrica 		(void) fprintf(logf,
463*f875b4ebSrica 		    gettext("invalid debug level: %d, not changed!\n"),
464*f875b4ebSrica 			debug_level);
465*f875b4ebSrica 		(void) fflush(logf);
466*f875b4ebSrica 	    }
467*f875b4ebSrica 	    cprint("invalid debug level: %d, not changed!\n",
468*f875b4ebSrica 		debug_level);
469*f875b4ebSrica 	    return (-1);
470*f875b4ebSrica 	}
471*f875b4ebSrica 	return (0);
472*f875b4ebSrica }
473*f875b4ebSrica 
474*f875b4ebSrica static FILE *
475*f875b4ebSrica tnlog_open(logfile)
476*f875b4ebSrica 	char *logfile;
477*f875b4ebSrica {
478*f875b4ebSrica 	FILE *fp;
479*f875b4ebSrica 
480*f875b4ebSrica 	if ((fp = fopen(logfile, "a")) == NULL) {
481*f875b4ebSrica 		syslog(LOG_ERR, "unable to open logfile %s",
482*f875b4ebSrica 			logfile);
483*f875b4ebSrica 		exit(-1);
484*f875b4ebSrica 	}
485*f875b4ebSrica 	(void) fprintf(fp, "%s : ", gettime());
486*f875b4ebSrica 	(void) fprintf(fp, gettext("tnd starting\n"));
487*f875b4ebSrica 
488*f875b4ebSrica 	return (fp);
489*f875b4ebSrica }
490*f875b4ebSrica 
491*f875b4ebSrica static void
492*f875b4ebSrica detachfromtty()
493*f875b4ebSrica {
494*f875b4ebSrica 	pid_t tnd_pid;
495*f875b4ebSrica 
496*f875b4ebSrica 	(void) close(0);
497*f875b4ebSrica 	(void) close(1);
498*f875b4ebSrica 	(void) close(2);
499*f875b4ebSrica 	switch (tnd_pid = fork()) {
500*f875b4ebSrica 	case (pid_t)-1:
501*f875b4ebSrica 		if (debugl && (logf != NULL)) {
502*f875b4ebSrica 			(void) fprintf(logf, "%s : ", gettime());
503*f875b4ebSrica 			(void) fprintf(logf,
504*f875b4ebSrica 			    gettext("fork() failed: %s\n"), strerror(errno));
505*f875b4ebSrica 			(void) fflush(logf);
506*f875b4ebSrica 		}
507*f875b4ebSrica 		cprint("fork() failed: %s\n", strerror(errno));
508*f875b4ebSrica 		break;
509*f875b4ebSrica 	case 0:
510*f875b4ebSrica 		break;
511*f875b4ebSrica 	default:
512*f875b4ebSrica 		if (debugl && (logf != NULL)) {
513*f875b4ebSrica 			(void) fprintf(logf, "%s : ", gettime());
514*f875b4ebSrica 			(void) fprintf(logf,
515*f875b4ebSrica 			    gettext("tnd started. pid= %d\n"), tnd_pid);
516*f875b4ebSrica 			(void) fflush(logf);
517*f875b4ebSrica 		}
518*f875b4ebSrica 		/*
519*f875b4ebSrica 		 * Suspend parent till child signals it. We catch the signal
520*f875b4ebSrica 		 * in order to return correct exit value.
521*f875b4ebSrica 		 */
522*f875b4ebSrica 
523*f875b4ebSrica 		(void) pause();
524*f875b4ebSrica 		exit(0);
525*f875b4ebSrica 	}
526*f875b4ebSrica 	(void) setsid();
527*f875b4ebSrica 	(void) open("/dev/null", O_RDWR, 0);
528*f875b4ebSrica 	(void) dup(0);
529*f875b4ebSrica 	(void) dup(0);
530*f875b4ebSrica }
531*f875b4ebSrica 
532*f875b4ebSrica static void
533*f875b4ebSrica usage()
534*f875b4ebSrica {
535*f875b4ebSrica 	(void) fprintf(stderr, gettext(
536*f875b4ebSrica 	    "Usage:\n\ttnd [-d debug-level][-f debug-file]"
537*f875b4ebSrica 	    "[-p poll-interval]\n"));
538*f875b4ebSrica 
539*f875b4ebSrica 	exit(1);
540*f875b4ebSrica }
541*f875b4ebSrica 
542*f875b4ebSrica static int
543*f875b4ebSrica isnumber(s)
544*f875b4ebSrica char *s;
545*f875b4ebSrica {
546*f875b4ebSrica 	register c;
547*f875b4ebSrica 
548*f875b4ebSrica 	/* LINTED */
549*f875b4ebSrica 	while (c = *s++)
550*f875b4ebSrica 		if (!isdigit(c))
551*f875b4ebSrica 			return (0);
552*f875b4ebSrica 	return (1);
553*f875b4ebSrica }
554*f875b4ebSrica 
555*f875b4ebSrica 
556*f875b4ebSrica /*
557*f875b4ebSrica  * match any entry in any tree
558*f875b4ebSrica  *	used in tree removal
559*f875b4ebSrica  */
560*f875b4ebSrica /* ARGSUSED */
561*f875b4ebSrica static int
562*f875b4ebSrica any_compar(const void *v1, const void *v2)
563*f875b4ebSrica {
564*f875b4ebSrica 	return (0);
565*f875b4ebSrica }
566*f875b4ebSrica 
567*f875b4ebSrica static int
568*f875b4ebSrica tp_compar(const void *v1, const void *v2)
569*f875b4ebSrica {
570*f875b4ebSrica 	struct tnd_tnrhtp_c	*tp1 = (struct tnd_tnrhtp_c *)v1;
571*f875b4ebSrica 	struct tnd_tnrhtp_c	*tp2 = (struct tnd_tnrhtp_c *)v2;
572*f875b4ebSrica 	return (strcmp(tp1->tp_ent.name, tp2->tp_ent.name));
573*f875b4ebSrica }
574*f875b4ebSrica 
575*f875b4ebSrica /*
576*f875b4ebSrica  * Build tree of tp entries, tossing duplicates
577*f875b4ebSrica  */
578*f875b4ebSrica static int
579*f875b4ebSrica nss_get_tp()
580*f875b4ebSrica {
581*f875b4ebSrica 	tsol_tpent_t tp; /* to store result */
582*f875b4ebSrica 	tsol_tpent_t *tpp;
583*f875b4ebSrica 	struct tnd_tnrhtp_c *new, **old;
584*f875b4ebSrica 	int count = 0;
585*f875b4ebSrica 
586*f875b4ebSrica 	tpp = &tp;
587*f875b4ebSrica 
588*f875b4ebSrica 	tsol_settpent(1);
589*f875b4ebSrica 
590*f875b4ebSrica 	while ((tpp = (tsol_tpent_t *)tsol_gettpent()) != NULL) {
591*f875b4ebSrica 		if ((new = (struct tnd_tnrhtp_c *)
592*f875b4ebSrica 		    calloc(1, sizeof (struct tnd_tnrhtp_c))) == NULL)
593*f875b4ebSrica 			continue;
594*f875b4ebSrica 		(void) memcpy(&new->tp_ent, tpp, sizeof (tp));
595*f875b4ebSrica 		old = (struct tnd_tnrhtp_c **)tsearch(new, &tp_tree, tp_compar);
596*f875b4ebSrica 		if (*old != new)
597*f875b4ebSrica 			free(new);
598*f875b4ebSrica 		else
599*f875b4ebSrica 			count++;
600*f875b4ebSrica 	}
601*f875b4ebSrica 	tsol_endtpent();
602*f875b4ebSrica 
603*f875b4ebSrica 	return (count);
604*f875b4ebSrica }
605*f875b4ebSrica 
606*f875b4ebSrica /* load tp ents into kernel */
607*f875b4ebSrica static void
608*f875b4ebSrica load_tp()
609*f875b4ebSrica {
610*f875b4ebSrica 	twalk(tp_tree, load_tp_entry);
611*f875b4ebSrica }
612*f875b4ebSrica 
613*f875b4ebSrica 
614*f875b4ebSrica static void
615*f875b4ebSrica /* LINTED */
616*f875b4ebSrica load_tp_entry(struct tnd_tnrhtp_c **tppp, VISIT visit, int level)
617*f875b4ebSrica {
618*f875b4ebSrica 	struct tnd_tnrhtp_c *tpp;
619*f875b4ebSrica 
620*f875b4ebSrica 	if (!(visit == postorder || visit == leaf))
621*f875b4ebSrica 		return;
622*f875b4ebSrica 
623*f875b4ebSrica 	tpp = *tppp;
624*f875b4ebSrica 	if (tnrhtp(TNDB_LOAD, &tpp->tp_ent)) {
625*f875b4ebSrica 		if (debugl && (logf != NULL)) {
626*f875b4ebSrica 			(void) fprintf(logf, "%s : ", gettime());
627*f875b4ebSrica 			(void) fprintf(logf, gettext("tnrhtp() failed 0: %s\n"),
628*f875b4ebSrica 			    strerror(errno));
629*f875b4ebSrica 			(void) fprintf(logf,
630*f875b4ebSrica 			    gettext("load of remote-host template "
631*f875b4ebSrica 			    "%s into kernel cache failed\n"),
632*f875b4ebSrica 			    tpp->tp_ent.name);
633*f875b4ebSrica 			(void) fflush(logf);
634*f875b4ebSrica 		}
635*f875b4ebSrica 		cprint("tnrhtp() failed here 1: %s\n", strerror(errno));
636*f875b4ebSrica 	}
637*f875b4ebSrica }
638*f875b4ebSrica 
639*f875b4ebSrica static void
640*f875b4ebSrica tp_flush_cache()
641*f875b4ebSrica {
642*f875b4ebSrica 	struct tnd_tnrhtp_c	dummy;
643*f875b4ebSrica 	struct tnd_tnrhtp_c	*tp;
644*f875b4ebSrica 
645*f875b4ebSrica 	while (tp = tfind(&dummy, tp_tree, any_compar)) {
646*f875b4ebSrica 		(void) tdelete(tp, &tp_tree, tp_compar);
647*f875b4ebSrica 		free(tp);
648*f875b4ebSrica 	}
649*f875b4ebSrica }
650*f875b4ebSrica 
651*f875b4ebSrica /*
652*f875b4ebSrica  * Build/update the table of rh entries from the
653*f875b4ebSrica  * name service sources, files, ldap etc.
654*f875b4ebSrica  */
655*f875b4ebSrica static int
656*f875b4ebSrica nss_get_rh()
657*f875b4ebSrica {
658*f875b4ebSrica 	int found_entry = 0;
659*f875b4ebSrica 	int count = 0;
660*f875b4ebSrica 	int newflag = 0;
661*f875b4ebSrica 	struct tsol_rhent rh; /* to store result */
662*f875b4ebSrica 	struct tsol_rhent *rhp;
663*f875b4ebSrica 	tsol_tpent_t tp;
664*f875b4ebSrica 	sa_family_t af;
665*f875b4ebSrica 	int v6cnt = 0;
666*f875b4ebSrica 
667*f875b4ebSrica 	rhp = &rh;
668*f875b4ebSrica 
669*f875b4ebSrica 	tsol_setrhent(1);
670*f875b4ebSrica 	while ((rhp = (struct tsol_rhent *)
671*f875b4ebSrica 	    tsol_getrhent()) != NULL) {
672*f875b4ebSrica 		/*
673*f875b4ebSrica 		 * Check if this is a known template name
674*f875b4ebSrica 		 * Entries with missing template in kernel will be logged
675*f875b4ebSrica 		 * and not added to cache.
676*f875b4ebSrica 		 */
677*f875b4ebSrica 
678*f875b4ebSrica 		(void) fprintf(logf, gettext("getrhent template name: %s\n"),
679*f875b4ebSrica 		    rhp->rh_template);
680*f875b4ebSrica 
681*f875b4ebSrica 		(void) strncpy(tp.name, rhp->rh_template, TNTNAMSIZ - 1);
682*f875b4ebSrica 		if (tnrhtp(TNDB_GET, &tp) != 0) {
683*f875b4ebSrica 			if (debugl && (logf != NULL))
684*f875b4ebSrica 				(void) fprintf(logf,
685*f875b4ebSrica 				    gettext("Unknown template name: %s\n"),
686*f875b4ebSrica 				    rhp->rh_template);
687*f875b4ebSrica 			cprint(gettext("Unknown template name: %s\n"),
688*f875b4ebSrica 			    rhp->rh_template);
689*f875b4ebSrica 			continue;
690*f875b4ebSrica 		}
691*f875b4ebSrica 		found_entry++;		/* found a valid tnrhdb entry */
692*f875b4ebSrica 		af = rhp->rh_address.ta_family;
693*f875b4ebSrica 
694*f875b4ebSrica 		if (af == AF_INET) {
695*f875b4ebSrica #ifdef DEBUG
696*f875b4ebSrica 			(void) fprintf(logf, gettext("nss_get_rh() v4\n"));
697*f875b4ebSrica #endif
698*f875b4ebSrica 			(void) rw_wrlock(&entire_rwlp);
699*f875b4ebSrica 			(void) rw_wrlock(&cache_rwlp);
700*f875b4ebSrica 
701*f875b4ebSrica 			/*
702*f875b4ebSrica 			 * Both cache table and entire table can be modified
703*f875b4ebSrica 			 * by this function. So, get both locks.
704*f875b4ebSrica 			 */
705*f875b4ebSrica 			newflag = rhtable_search_and_update(rhp, 1);
706*f875b4ebSrica 
707*f875b4ebSrica 			(void) rw_unlock(&cache_rwlp);
708*f875b4ebSrica 			(void) rw_unlock(&entire_rwlp);
709*f875b4ebSrica 		} else if (af == AF_INET6) {
710*f875b4ebSrica #ifdef DEBUG
711*f875b4ebSrica 			(void) fprintf(logf, gettext("nss_get_rh() v6\n"));
712*f875b4ebSrica #endif
713*f875b4ebSrica 			v6cnt++;
714*f875b4ebSrica 			(void) rw_wrlock(&entire_rwlp_v6);
715*f875b4ebSrica 			(void) rw_wrlock(&cache_rwlp_v6);
716*f875b4ebSrica 
717*f875b4ebSrica 			/*
718*f875b4ebSrica 			 * Both cache table and entire table can be modified
719*f875b4ebSrica 			 * by this function. So, get both locks.
720*f875b4ebSrica 			 */
721*f875b4ebSrica 			newflag = rhtable_search_and_update_v6(rhp, 1);
722*f875b4ebSrica 
723*f875b4ebSrica 			(void) rw_unlock(&cache_rwlp_v6);
724*f875b4ebSrica 			(void) rw_unlock(&entire_rwlp_v6);
725*f875b4ebSrica 		}
726*f875b4ebSrica 		if (newflag)
727*f875b4ebSrica 			count++;
728*f875b4ebSrica 	}
729*f875b4ebSrica 	tsol_endrhent();
730*f875b4ebSrica 
731*f875b4ebSrica 	/*
732*f875b4ebSrica 	 * If the first tsol_getrhent() failed, we bail out and
733*f875b4ebSrica 	 * try again at the next poll interval, just in case the
734*f875b4ebSrica 	 * name service was not reachable the first time.
735*f875b4ebSrica 	 */
736*f875b4ebSrica 	if (!found_entry) {
737*f875b4ebSrica #ifdef	DEBUG
738*f875b4ebSrica 		if (logf != NULL)
739*f875b4ebSrica 			(void) fprintf(logf,
740*f875b4ebSrica 			    gettext("Unable to contact ldap server?\n"));
741*f875b4ebSrica #endif
742*f875b4ebSrica 		return (count);
743*f875b4ebSrica 	}
744*f875b4ebSrica 
745*f875b4ebSrica 	(void) rw_wrlock(&entire_rwlp);
746*f875b4ebSrica 	(void) rw_wrlock(&cache_rwlp);
747*f875b4ebSrica 	/*
748*f875b4ebSrica 	 * Handle deletions in the name service entries
749*f875b4ebSrica 	 * Both cache table and entire table can be modified
750*f875b4ebSrica 	 * by this function. So, get both locks.
751*f875b4ebSrica 	 */
752*f875b4ebSrica 	count += handle_unvisited_nodes();
753*f875b4ebSrica 
754*f875b4ebSrica 	(void) rw_unlock(&cache_rwlp);
755*f875b4ebSrica 	(void) rw_unlock(&entire_rwlp);
756*f875b4ebSrica 
757*f875b4ebSrica 	if (v6cnt > 0) {
758*f875b4ebSrica 		(void) rw_wrlock(&entire_rwlp_v6);
759*f875b4ebSrica 		(void) rw_wrlock(&cache_rwlp_v6);
760*f875b4ebSrica 		/*
761*f875b4ebSrica 		 * Handle deletions in the name service entries
762*f875b4ebSrica 		 * Both cache table and entire table can be modified
763*f875b4ebSrica 		 * by this function. So, get both locks.
764*f875b4ebSrica 		 */
765*f875b4ebSrica 		count += handle_unvisited_nodes_v6();
766*f875b4ebSrica 
767*f875b4ebSrica 		(void) rw_unlock(&cache_rwlp_v6);
768*f875b4ebSrica 		(void) rw_unlock(&entire_rwlp_v6);
769*f875b4ebSrica 	}
770*f875b4ebSrica 
771*f875b4ebSrica 	return (count);
772*f875b4ebSrica }
773*f875b4ebSrica 
774*f875b4ebSrica /*
775*f875b4ebSrica  * Check if any deletions in  the name service tables
776*f875b4ebSrica  * affect the cache entries. We need to do this
777*f875b4ebSrica  * in order to not flush the entrie kernel tnrhdb
778*f875b4ebSrica  * cache every time we poll the name services.
779*f875b4ebSrica  */
780*f875b4ebSrica static int
781*f875b4ebSrica handle_unvisited_nodes()
782*f875b4ebSrica {
783*f875b4ebSrica 	int i, j, cnt = 0;
784*f875b4ebSrica 	tnrh_tlb_t *tlbt;
785*f875b4ebSrica 	tnd_tnrhdb_t *rhent, *prev;
786*f875b4ebSrica 
787*f875b4ebSrica 	for (i = 0; i < TNRH_TABLE_HASH_SIZE; i++)
788*f875b4ebSrica 		if ((tlbt = tnrh_cache_table[i]) != NULL)
789*f875b4ebSrica 			do {
790*f875b4ebSrica 				if (tlbt->src->visited == 0) {
791*f875b4ebSrica 					/*
792*f875b4ebSrica 					 * Mark for deletion of both our cache
793*f875b4ebSrica 					 * entry and the kernel cache entry.
794*f875b4ebSrica 					 */
795*f875b4ebSrica 					tlbt->reload = TNDB_DELETE;
796*f875b4ebSrica 					cnt++;
797*f875b4ebSrica 				}
798*f875b4ebSrica 
799*f875b4ebSrica 				tlbt = tlbt->next;
800*f875b4ebSrica 			} while (tlbt != NULL);
801*f875b4ebSrica 
802*f875b4ebSrica 	/*
803*f875b4ebSrica 	 * Remove any unvisited nodes. This can
804*f875b4ebSrica 	 * happen if they are not in use by any cache entry. Then,
805*f875b4ebSrica 	 * mark all nodes in entire_table, un-visited, for next iteration.
806*f875b4ebSrica 	 */
807*f875b4ebSrica 
808*f875b4ebSrica 	for (i = 0; i <= IP_ABITS; i++) {
809*f875b4ebSrica 		if (tnrh_entire_table[i] == NULL)
810*f875b4ebSrica 			continue;
811*f875b4ebSrica 
812*f875b4ebSrica 		for (j = 0; j < TNRH_TABLE_HASH_SIZE; j++) {
813*f875b4ebSrica 			prev = rhent = tnrh_entire_table[i][j];
814*f875b4ebSrica 
815*f875b4ebSrica 			while (rhent != NULL) {
816*f875b4ebSrica 				if (rhent->visited == 0) {
817*f875b4ebSrica 					/*
818*f875b4ebSrica 					 * Check if start node
819*f875b4ebSrica 					 */
820*f875b4ebSrica 					if (rhent == tnrh_entire_table[i][j]) {
821*f875b4ebSrica 						prev = tnrh_entire_table[i][j] =
822*f875b4ebSrica 						    rhent->rh_next;
823*f875b4ebSrica 					} else {
824*f875b4ebSrica 						/* bypass the deleted node */
825*f875b4ebSrica 						prev->rh_next = rhent->rh_next;
826*f875b4ebSrica 						prev = prev->rh_next;
827*f875b4ebSrica 					}
828*f875b4ebSrica 
829*f875b4ebSrica 					free(rhent);
830*f875b4ebSrica 
831*f875b4ebSrica 					if (prev == NULL)
832*f875b4ebSrica 						break;
833*f875b4ebSrica 					else {
834*f875b4ebSrica 						rhent = prev;
835*f875b4ebSrica 						continue;
836*f875b4ebSrica 					}
837*f875b4ebSrica 				} else
838*f875b4ebSrica 					rhent->visited = 0;
839*f875b4ebSrica 
840*f875b4ebSrica 				prev = rhent;
841*f875b4ebSrica 				rhent = rhent->rh_next;
842*f875b4ebSrica 			}
843*f875b4ebSrica 		}
844*f875b4ebSrica 	}
845*f875b4ebSrica 
846*f875b4ebSrica 	return (cnt);
847*f875b4ebSrica }
848*f875b4ebSrica 
849*f875b4ebSrica /*
850*f875b4ebSrica  * Check if any deletions in  the name service tables
851*f875b4ebSrica  * affect the cache entries. We need to do this
852*f875b4ebSrica  * in order to not flush the entrie kernel tnrhdb
853*f875b4ebSrica  * cache every time we poll the name services.
854*f875b4ebSrica  */
855*f875b4ebSrica static int
856*f875b4ebSrica handle_unvisited_nodes_v6()
857*f875b4ebSrica {
858*f875b4ebSrica 	int i, j, cnt = 0;
859*f875b4ebSrica 	tnrh_tlb_ipv6_t *tlbt;
860*f875b4ebSrica 	tnd_tnrhdb_t *rhent, *prev;
861*f875b4ebSrica 
862*f875b4ebSrica 	for (i = 0; i < TNRH_TABLE_HASH_SIZE; i++)
863*f875b4ebSrica 	if ((tlbt = tnrh_cache_table_v6[i]) != NULL)
864*f875b4ebSrica 	do {
865*f875b4ebSrica 		if (tlbt->src->visited == 0) {
866*f875b4ebSrica 			/*
867*f875b4ebSrica 			 * Mark for deletion of both our cache entry
868*f875b4ebSrica 			 * and the kernel cache entry.
869*f875b4ebSrica 			 */
870*f875b4ebSrica 			tlbt->reload = TNDB_DELETE;
871*f875b4ebSrica 			cnt++;
872*f875b4ebSrica 		}
873*f875b4ebSrica 
874*f875b4ebSrica 		tlbt = tlbt->next;
875*f875b4ebSrica 	} while (tlbt != NULL);
876*f875b4ebSrica 
877*f875b4ebSrica 	/*
878*f875b4ebSrica 	 * Remove any unvisited nodes. This can
879*f875b4ebSrica 	 * happen if they are not in use by any cache entry. Then,
880*f875b4ebSrica 	 * mark all nodes in entire_table, un-visited, for next iteration.
881*f875b4ebSrica 	 */
882*f875b4ebSrica 
883*f875b4ebSrica 	for (i = 0; i <= IPV6_ABITS; i++) {
884*f875b4ebSrica 	if (tnrh_entire_table_v6[i] == NULL)
885*f875b4ebSrica 		continue;
886*f875b4ebSrica 
887*f875b4ebSrica 	for (j = 0; j < TNRH_TABLE_HASH_SIZE; j++) {
888*f875b4ebSrica 		prev = rhent = tnrh_entire_table_v6[i][j];
889*f875b4ebSrica 
890*f875b4ebSrica 		while (rhent != NULL) {
891*f875b4ebSrica 		if (rhent->visited == 0) {	/* delete the node */
892*f875b4ebSrica 			/* Check if start node */
893*f875b4ebSrica 			if (rhent == tnrh_entire_table_v6[i][j]) {
894*f875b4ebSrica 				prev = tnrh_entire_table_v6[i][j] =
895*f875b4ebSrica 				    rhent->rh_next;
896*f875b4ebSrica 			} else {
897*f875b4ebSrica 				/* bypass the deleted node */
898*f875b4ebSrica 				prev->rh_next = rhent->rh_next;
899*f875b4ebSrica 				prev = prev->rh_next;
900*f875b4ebSrica 			}
901*f875b4ebSrica 
902*f875b4ebSrica 			free(rhent);
903*f875b4ebSrica 			if (prev == NULL)
904*f875b4ebSrica 				break;
905*f875b4ebSrica 			else {
906*f875b4ebSrica 				rhent = prev;
907*f875b4ebSrica 				continue;
908*f875b4ebSrica 			}
909*f875b4ebSrica 		} else
910*f875b4ebSrica 			rhent->visited = 0;
911*f875b4ebSrica 
912*f875b4ebSrica 		prev = rhent;
913*f875b4ebSrica 		rhent = rhent->rh_next;
914*f875b4ebSrica 		}
915*f875b4ebSrica 	}
916*f875b4ebSrica 	}
917*f875b4ebSrica 
918*f875b4ebSrica 	return (cnt);
919*f875b4ebSrica }
920*f875b4ebSrica 
921*f875b4ebSrica 
922*f875b4ebSrica /*
923*f875b4ebSrica  * Search the hash chain for the address. If not found,
924*f875b4ebSrica  * add the entry to the hash table. If necessary,
925*f875b4ebSrica  * construct the hash table.
926*f875b4ebSrica  * If the rh entry is in table, we may update its template name
927*f875b4ebSrica  */
928*f875b4ebSrica static int
929*f875b4ebSrica rhtable_search_and_update(struct tsol_rhent *ent, int duplflag)
930*f875b4ebSrica {
931*f875b4ebSrica 	struct sockaddr_in *saddrp;
932*f875b4ebSrica 	unsigned char hash;
933*f875b4ebSrica 	tnd_tnrhdb_t *rhent;
934*f875b4ebSrica 	int i;
935*f875b4ebSrica 	int rflag = 1;
936*f875b4ebSrica 
937*f875b4ebSrica 	struct tnd_tnrhdb_c *new;
938*f875b4ebSrica 
939*f875b4ebSrica 	saddrp = (struct sockaddr_in *)&ent->rh_address.ip_addr_v4;
940*f875b4ebSrica 	hash = (unsigned char) get_hashvalue(saddrp->sin_addr.s_addr);
941*f875b4ebSrica 	i = ent->rh_prefix;
942*f875b4ebSrica 
943*f875b4ebSrica #ifdef DEBUG
944*f875b4ebSrica 	(void) fprintf(logf, gettext("\trhtable_search_and_update IP address:\
945*f875b4ebSrica 		%s\n"), inet_ntoa(saddrp->sin_addr));
946*f875b4ebSrica #endif
947*f875b4ebSrica 
948*f875b4ebSrica 	if (tnrh_entire_table[i] == NULL) {
949*f875b4ebSrica 		if ((tnrh_entire_table[i] = (tnd_tnrhdb_t **)calloc(
950*f875b4ebSrica 		    TNRH_TABLE_HASH_SIZE, sizeof (tnd_tnrhdb_t *))) == NULL) {
951*f875b4ebSrica 			return (0);
952*f875b4ebSrica 		}
953*f875b4ebSrica 	}
954*f875b4ebSrica 
955*f875b4ebSrica 	rhent = tnrh_entire_table[i][hash];
956*f875b4ebSrica #ifdef DEBUG
957*f875b4ebSrica 	(void) fprintf(logf, gettext("\tsearch_and_update i = %d hash = %d\n"),
958*f875b4ebSrica 	    i, hash);
959*f875b4ebSrica 	if (rhent != NULL) {
960*f875b4ebSrica 		(void) fprintf(logf, gettext("\trhent visited  = %d\n"),
961*f875b4ebSrica 		    rhent->visited);
962*f875b4ebSrica 		print_entry(&rhent->rh_ent, AF_INET);
963*f875b4ebSrica 	} else {
964*f875b4ebSrica 		(void) fprintf(logf, gettext("\tsearch_and_update null\n"));
965*f875b4ebSrica 	}
966*f875b4ebSrica #endif
967*f875b4ebSrica 	while (rhent != NULL) {
968*f875b4ebSrica 		if (rhaddr_compar(saddrp, rhent) == 1) {
969*f875b4ebSrica 			/* Check if this is a duplicate entry */
970*f875b4ebSrica 			if ((rhent->visited == 1) && duplflag)
971*f875b4ebSrica 				return (0);
972*f875b4ebSrica 
973*f875b4ebSrica 			if (duplflag)
974*f875b4ebSrica 				rhent->visited = 1;
975*f875b4ebSrica 
976*f875b4ebSrica 			if (strcmp(ent->rh_template,
977*f875b4ebSrica 			    rhent->rh_ent.rh_template) != 0) {
978*f875b4ebSrica 				/*
979*f875b4ebSrica 				 * Template is changed in the name service.
980*f875b4ebSrica 				 * Use the new template.
981*f875b4ebSrica 				 */
982*f875b4ebSrica 				(void) strcpy(rhent->rh_ent.rh_template,
983*f875b4ebSrica 				    ent->rh_template);
984*f875b4ebSrica 				/*
985*f875b4ebSrica 				 * Check if this modified entry
986*f875b4ebSrica 				 * affects the cache table.
987*f875b4ebSrica 				 */
988*f875b4ebSrica 				rflag = update_cache_table(ent, rhent);
989*f875b4ebSrica 				return (rflag);
990*f875b4ebSrica 			} else
991*f875b4ebSrica 				return (0);
992*f875b4ebSrica 		}
993*f875b4ebSrica 		rhent = rhent->rh_next;
994*f875b4ebSrica 	}
995*f875b4ebSrica 
996*f875b4ebSrica 	/* Not found. Add the entry */
997*f875b4ebSrica 	new = (struct tnd_tnrhdb_c *)calloc(1,
998*f875b4ebSrica 	    sizeof (struct tnd_tnrhdb_c));
999*f875b4ebSrica 	if (new == NULL)
1000*f875b4ebSrica 		return (0);
1001*f875b4ebSrica 	(void) memcpy(&new->rh_ent, ent, sizeof (struct tsol_rhent));
1002*f875b4ebSrica 	if (duplflag)
1003*f875b4ebSrica 		new->visited = 1;	/* Mark all new nodes visited */
1004*f875b4ebSrica 
1005*f875b4ebSrica 	/* linked list. Insert in the beginning */
1006*f875b4ebSrica 	new->rh_next = tnrh_entire_table[i][hash];
1007*f875b4ebSrica 	tnrh_entire_table[i][hash] = new;
1008*f875b4ebSrica #ifdef DEBUG
1009*f875b4ebSrica 	(void) fprintf(logf, gettext("rhtable added i = %d, hash = %d\n"),
1010*f875b4ebSrica 	    i, hash);
1011*f875b4ebSrica #endif
1012*f875b4ebSrica 
1013*f875b4ebSrica 	/* Check if the new entry affects the cache table */
1014*f875b4ebSrica 	rflag = update_cache_table(ent, new);
1015*f875b4ebSrica 
1016*f875b4ebSrica #ifdef DEBUG
1017*f875b4ebSrica 	(void) fprintf(logf, gettext("search_and_update rflag=%d\n"), rflag);
1018*f875b4ebSrica #endif
1019*f875b4ebSrica 	return (rflag);
1020*f875b4ebSrica }
1021*f875b4ebSrica 
1022*f875b4ebSrica /*
1023*f875b4ebSrica  * Search the hash chain for the address. If not found,
1024*f875b4ebSrica  * add the entry to the hash table. If necessary,
1025*f875b4ebSrica  * construct the hash table.
1026*f875b4ebSrica  */
1027*f875b4ebSrica static int
1028*f875b4ebSrica rhtable_search_and_update_v6(struct tsol_rhent *ent, int duplflag)
1029*f875b4ebSrica {
1030*f875b4ebSrica 	struct sockaddr_in6 *saddrp;
1031*f875b4ebSrica 	unsigned char hash;
1032*f875b4ebSrica 	tnd_tnrhdb_t *rhent;
1033*f875b4ebSrica 	int i;
1034*f875b4ebSrica 	int rflag = 1;
1035*f875b4ebSrica 
1036*f875b4ebSrica 	struct tnd_tnrhdb_c *new;
1037*f875b4ebSrica 	in6_addr_t tmpmask6;
1038*f875b4ebSrica 
1039*f875b4ebSrica 	saddrp = (struct sockaddr_in6 *)&ent->rh_address.ip_addr_v6;
1040*f875b4ebSrica 	i = ent->rh_prefix;
1041*f875b4ebSrica 	(void) rh_index_to_mask_v6(i, &tmpmask6);
1042*f875b4ebSrica 	hash = (unsigned char) TNRH_ADDR_MASK_HASH_V6(saddrp->sin6_addr,
1043*f875b4ebSrica 	    tmpmask6);
1044*f875b4ebSrica 
1045*f875b4ebSrica 	if (tnrh_entire_table_v6[i] == NULL) {
1046*f875b4ebSrica 		if ((tnrh_entire_table_v6[i] = (tnd_tnrhdb_t **)calloc(
1047*f875b4ebSrica 		    TNRH_TABLE_HASH_SIZE, sizeof (tnd_tnrhdb_t *))) == NULL) {
1048*f875b4ebSrica 			return (0);
1049*f875b4ebSrica 		}
1050*f875b4ebSrica 	}
1051*f875b4ebSrica 
1052*f875b4ebSrica 	rhent = tnrh_entire_table_v6[i][hash];
1053*f875b4ebSrica 	while (rhent != NULL) {
1054*f875b4ebSrica 		if (rhaddr_compar_v6(saddrp, rhent) == 1) {
1055*f875b4ebSrica 			/* Check if this is a duplicate entry */
1056*f875b4ebSrica 			if ((rhent->visited == 1) && duplflag)
1057*f875b4ebSrica 				return (0);
1058*f875b4ebSrica 
1059*f875b4ebSrica 			if (duplflag)
1060*f875b4ebSrica 				rhent->visited = 1;
1061*f875b4ebSrica 
1062*f875b4ebSrica 			if (strcmp(ent->rh_template,
1063*f875b4ebSrica 			    rhent->rh_ent.rh_template) != 0) {
1064*f875b4ebSrica 				/*
1065*f875b4ebSrica 				 * Template is changed in the name service.
1066*f875b4ebSrica 				 * Use the new template.
1067*f875b4ebSrica 				 */
1068*f875b4ebSrica 				(void) strcpy(rhent->rh_ent.rh_template,
1069*f875b4ebSrica 				    ent->rh_template);
1070*f875b4ebSrica 				/*
1071*f875b4ebSrica 				 * Check if this modified entry
1072*f875b4ebSrica 				 * affects the cache table.
1073*f875b4ebSrica 				 */
1074*f875b4ebSrica 				rflag = update_cache_table_v6(ent, rhent);
1075*f875b4ebSrica 				return (rflag);
1076*f875b4ebSrica 			} else
1077*f875b4ebSrica 				return (0);
1078*f875b4ebSrica 		}
1079*f875b4ebSrica 		rhent = rhent->rh_next;
1080*f875b4ebSrica 	}
1081*f875b4ebSrica 
1082*f875b4ebSrica 	/* Not found. Add the entry */
1083*f875b4ebSrica 	new = (struct tnd_tnrhdb_c *)calloc(1, sizeof (struct tnd_tnrhdb_c));
1084*f875b4ebSrica 	if (new == NULL)
1085*f875b4ebSrica 		return (0);
1086*f875b4ebSrica 	(void) memcpy(&new->rh_ent, ent, sizeof (struct tsol_rhent));
1087*f875b4ebSrica 	if (duplflag)
1088*f875b4ebSrica 		new->visited = 1;	/* Mark all new nodes visited */
1089*f875b4ebSrica 
1090*f875b4ebSrica 	/* linked list. Insert in the beginning */
1091*f875b4ebSrica 	new->rh_next = tnrh_entire_table_v6[i][hash];
1092*f875b4ebSrica 	tnrh_entire_table_v6[i][hash] = new;
1093*f875b4ebSrica 
1094*f875b4ebSrica 	/* Check if the new entry affects the cache table */
1095*f875b4ebSrica 	rflag = update_cache_table_v6(ent, new);
1096*f875b4ebSrica 
1097*f875b4ebSrica 	return (rflag);
1098*f875b4ebSrica }
1099*f875b4ebSrica 
1100*f875b4ebSrica /*
1101*f875b4ebSrica  * The array element i points to the hash table.
1102*f875b4ebSrica  * Search the hash chain for the address.
1103*f875b4ebSrica  */
1104*f875b4ebSrica static struct tnd_tnrhdb_c *
1105*f875b4ebSrica rhtable_lookup(struct sockaddr_in *saddrp, int i)
1106*f875b4ebSrica {
1107*f875b4ebSrica 	unsigned char hash;
1108*f875b4ebSrica 	tnd_tnrhdb_t *rhent;
1109*f875b4ebSrica 
1110*f875b4ebSrica 	if (tnrh_entire_table[i] == NULL)
1111*f875b4ebSrica 		return (NULL);
1112*f875b4ebSrica 
1113*f875b4ebSrica 	hash = (unsigned char) get_hashvalue(saddrp->sin_addr.s_addr);
1114*f875b4ebSrica 	rhent = tnrh_entire_table[i][hash];
1115*f875b4ebSrica 
1116*f875b4ebSrica #ifdef DEBUG
1117*f875b4ebSrica 	(void) fprintf(logf, gettext("rhtable_lookup i = %d, hash = %d\n"),
1118*f875b4ebSrica 	    i, hash);
1119*f875b4ebSrica #endif
1120*f875b4ebSrica 
1121*f875b4ebSrica 	while (rhent != NULL) {
1122*f875b4ebSrica #ifdef DEBUG
1123*f875b4ebSrica 	struct sockaddr_in *saddrp2;
1124*f875b4ebSrica 	saddrp2 = (struct sockaddr_in *)(&rhent->rh_ent.rh_address.ip_addr_v4);
1125*f875b4ebSrica 	(void) fprintf(logf, gettext("rhtable_lookup addr = %s, tmpl = %s\n"),
1126*f875b4ebSrica 	    inet_ntoa(saddrp2->sin_addr), rhent->rh_ent.rh_template);
1127*f875b4ebSrica #endif
1128*f875b4ebSrica 		if (rhaddr_compar_mask(saddrp, rhent, i) == 1)
1129*f875b4ebSrica 			return (rhent);
1130*f875b4ebSrica 		rhent = rhent->rh_next;
1131*f875b4ebSrica 	}
1132*f875b4ebSrica 
1133*f875b4ebSrica #ifdef DEBUG
1134*f875b4ebSrica 	(void) fprintf(logf, gettext("\trhtable_lookup failed\n"));
1135*f875b4ebSrica #endif
1136*f875b4ebSrica 
1137*f875b4ebSrica 	/* Not found */
1138*f875b4ebSrica 	return (NULL);
1139*f875b4ebSrica }
1140*f875b4ebSrica 
1141*f875b4ebSrica /*
1142*f875b4ebSrica  * The array element i points to the hash table.
1143*f875b4ebSrica  * Search the hash chain for the address.
1144*f875b4ebSrica  */
1145*f875b4ebSrica static struct tnd_tnrhdb_c *
1146*f875b4ebSrica rhtable_lookup_v6(struct sockaddr_in6 *saddrp, in6_addr_t mask, int i)
1147*f875b4ebSrica {
1148*f875b4ebSrica 	unsigned char hash;
1149*f875b4ebSrica 	tnd_tnrhdb_t *rhent;
1150*f875b4ebSrica 
1151*f875b4ebSrica 	if (tnrh_entire_table_v6[i] == NULL)
1152*f875b4ebSrica 		return (NULL);
1153*f875b4ebSrica 
1154*f875b4ebSrica 	hash = (unsigned char) TNRH_ADDR_MASK_HASH_V6(saddrp->sin6_addr, mask);
1155*f875b4ebSrica 	rhent = tnrh_entire_table_v6[i][hash];
1156*f875b4ebSrica 
1157*f875b4ebSrica 	while (rhent != NULL) {
1158*f875b4ebSrica 		if (rhaddr_compar_mask_v6(saddrp, rhent, i) == 1)
1159*f875b4ebSrica 			return (rhent);
1160*f875b4ebSrica 		rhent = rhent->rh_next;
1161*f875b4ebSrica 	}
1162*f875b4ebSrica 
1163*f875b4ebSrica 	/* Not found */
1164*f875b4ebSrica 	return (NULL);
1165*f875b4ebSrica }
1166*f875b4ebSrica 
1167*f875b4ebSrica void
1168*f875b4ebSrica add_cache_entry(in_addr_t addr, char *name, int indx,
1169*f875b4ebSrica     tnd_tnrhdb_t *src)
1170*f875b4ebSrica {
1171*f875b4ebSrica 	unsigned char hash;
1172*f875b4ebSrica 	tnrh_tlb_t *tlbt;
1173*f875b4ebSrica 
1174*f875b4ebSrica 	hash = (unsigned char) get_hashvalue(addr);
1175*f875b4ebSrica 
1176*f875b4ebSrica 	/* Look if some other thread already added this entry */
1177*f875b4ebSrica 	if (lookup_cache_table(addr) != NULL)
1178*f875b4ebSrica 		return;
1179*f875b4ebSrica #ifdef DEBUG
1180*f875b4ebSrica 	(void) fprintf(logf, gettext("\tenter add_cache_entry\n"));
1181*f875b4ebSrica #endif
1182*f875b4ebSrica 	if ((tlbt = (tnrh_tlb_t *)calloc(1, sizeof (tnrh_tlb_t))) == NULL)
1183*f875b4ebSrica 		return;
1184*f875b4ebSrica 	tlbt->addr = addr;
1185*f875b4ebSrica 	(void) strncpy(tlbt->template_name, name, TNTNAMSIZ-1);
1186*f875b4ebSrica 	tlbt->masklen_used = indx;
1187*f875b4ebSrica 	tlbt->reload = TNDB_LOAD;
1188*f875b4ebSrica 	tlbt->src = src;
1189*f875b4ebSrica 
1190*f875b4ebSrica #ifdef DEBUG
1191*f875b4ebSrica 	(void) fprintf(logf, gettext("adding cache entry\n"));
1192*f875b4ebSrica 	print_tlbt(tlbt);
1193*f875b4ebSrica #endif
1194*f875b4ebSrica 	/* Add to the chain */
1195*f875b4ebSrica 	if (tnrh_cache_table[hash] == NULL) {
1196*f875b4ebSrica 		tnrh_cache_table[hash] = tlbt;
1197*f875b4ebSrica 	} else {
1198*f875b4ebSrica 		/* Add in the beginning */
1199*f875b4ebSrica 		tlbt->next = tnrh_cache_table[hash];
1200*f875b4ebSrica 		tnrh_cache_table[hash] = tlbt;
1201*f875b4ebSrica 	}
1202*f875b4ebSrica }
1203*f875b4ebSrica 
1204*f875b4ebSrica static tnrh_tlb_t *
1205*f875b4ebSrica lookup_cache_table(in_addr_t addr)
1206*f875b4ebSrica {
1207*f875b4ebSrica 	tnrh_tlb_t *tlbt = NULL;
1208*f875b4ebSrica 	unsigned char hash;
1209*f875b4ebSrica 
1210*f875b4ebSrica 	hash = (unsigned char) get_hashvalue(addr);
1211*f875b4ebSrica 	tlbt = tnrh_cache_table[hash];
1212*f875b4ebSrica 	while (tlbt != NULL) {
1213*f875b4ebSrica 		if (addr == tlbt->addr)
1214*f875b4ebSrica 			break;
1215*f875b4ebSrica 		tlbt = tlbt->next;
1216*f875b4ebSrica 	}
1217*f875b4ebSrica 	return (tlbt);
1218*f875b4ebSrica }
1219*f875b4ebSrica 
1220*f875b4ebSrica static void
1221*f875b4ebSrica add_cache_entry_v6(in6_addr_t addr, char *name, int indx,
1222*f875b4ebSrica 				tnd_tnrhdb_t *src)
1223*f875b4ebSrica {
1224*f875b4ebSrica 	unsigned char hash;
1225*f875b4ebSrica 	tnrh_tlb_ipv6_t *tlbt;
1226*f875b4ebSrica 
1227*f875b4ebSrica 	hash = (unsigned char) TNRH_ADDR_HASH_V6(addr);
1228*f875b4ebSrica 
1229*f875b4ebSrica 	/* Look if some other thread already added this entry */
1230*f875b4ebSrica 	if (lookup_cache_table_v6(addr) != NULL)
1231*f875b4ebSrica 		return;
1232*f875b4ebSrica 
1233*f875b4ebSrica 	if ((tlbt = (tnrh_tlb_ipv6_t *)calloc(1,
1234*f875b4ebSrica 	    sizeof (tnrh_tlb_ipv6_t))) == NULL)
1235*f875b4ebSrica 		return;
1236*f875b4ebSrica 	(void) memcpy(&tlbt->addr, &addr, sizeof (in6_addr_t));
1237*f875b4ebSrica 	(void) strncpy(tlbt->template_name, name, TNTNAMSIZ-1);
1238*f875b4ebSrica 	tlbt->masklen_used = indx;
1239*f875b4ebSrica 	tlbt->reload = TNDB_LOAD;
1240*f875b4ebSrica 	tlbt->src = src;
1241*f875b4ebSrica 
1242*f875b4ebSrica 	/* Add to the chain */
1243*f875b4ebSrica 	if (tnrh_cache_table_v6[hash] == NULL) {
1244*f875b4ebSrica 		tnrh_cache_table_v6[hash] = tlbt;
1245*f875b4ebSrica 	} else {
1246*f875b4ebSrica 		/* Add in the beginning */
1247*f875b4ebSrica 		tlbt->next = tnrh_cache_table_v6[hash];
1248*f875b4ebSrica 		tnrh_cache_table_v6[hash] = tlbt;
1249*f875b4ebSrica 	}
1250*f875b4ebSrica }
1251*f875b4ebSrica 
1252*f875b4ebSrica static tnrh_tlb_ipv6_t *
1253*f875b4ebSrica lookup_cache_table_v6(in6_addr_t addr)
1254*f875b4ebSrica {
1255*f875b4ebSrica 	tnrh_tlb_ipv6_t *tlbt = NULL;
1256*f875b4ebSrica 	unsigned char hash;
1257*f875b4ebSrica 
1258*f875b4ebSrica 	hash = (unsigned char) TNRH_ADDR_HASH_V6(addr);
1259*f875b4ebSrica 	tlbt = tnrh_cache_table_v6[hash];
1260*f875b4ebSrica 	while (tlbt != NULL) {
1261*f875b4ebSrica 		if (IN6_ARE_ADDR_EQUAL(&addr, &tlbt->addr))
1262*f875b4ebSrica 			break;
1263*f875b4ebSrica 		tlbt = tlbt->next;
1264*f875b4ebSrica 	}
1265*f875b4ebSrica 	return (tlbt);
1266*f875b4ebSrica }
1267*f875b4ebSrica 
1268*f875b4ebSrica 
1269*f875b4ebSrica /*
1270*f875b4ebSrica  * Walk the cache table and check if this IP address/address prefix
1271*f875b4ebSrica  * will be a better match for an existing entry in the cache.
1272*f875b4ebSrica  * will add cache if not already exists
1273*f875b4ebSrica  */
1274*f875b4ebSrica static int
1275*f875b4ebSrica update_cache_table(tsol_rhent_t *ent, tnd_tnrhdb_t *src)
1276*f875b4ebSrica {
1277*f875b4ebSrica 	int i;
1278*f875b4ebSrica 	char result[TNTNAMSIZ];
1279*f875b4ebSrica 	in_addr_t tmpmask;
1280*f875b4ebSrica 	in_addr_t addr;
1281*f875b4ebSrica 	struct sockaddr_in *saddrp;
1282*f875b4ebSrica 	tnrh_tlb_t *tlbt;
1283*f875b4ebSrica 	struct tnd_tnrhdb_c	*rhp;
1284*f875b4ebSrica 	int rflag = 0;
1285*f875b4ebSrica 
1286*f875b4ebSrica 	saddrp = (struct sockaddr_in *)&ent->rh_address.ip_addr_v4;
1287*f875b4ebSrica 	addr = saddrp->sin_addr.s_addr;
1288*f875b4ebSrica 
1289*f875b4ebSrica 	(void) rw_rdlock(&cache_rwlp);
1290*f875b4ebSrica 	tlbt = lookup_cache_table(addr);
1291*f875b4ebSrica 	(void) rw_unlock(&cache_rwlp);
1292*f875b4ebSrica 
1293*f875b4ebSrica 	if (tlbt == NULL) {
1294*f875b4ebSrica 		(void) rw_rdlock(&entire_rwlp);
1295*f875b4ebSrica 		for (i = (IP_MASK_TABLE_SIZE - 1); i >= 0; i--) {
1296*f875b4ebSrica #ifdef DEBUG
1297*f875b4ebSrica 			(void) fprintf(logf, "update_cache_table i = %d\n", i);
1298*f875b4ebSrica #endif
1299*f875b4ebSrica 			if (tnrh_entire_table[i] == NULL)
1300*f875b4ebSrica 				continue;
1301*f875b4ebSrica 
1302*f875b4ebSrica 			tmpmask = rh_index_to_mask(i);
1303*f875b4ebSrica 			saddrp->sin_addr.s_addr &= tmpmask;
1304*f875b4ebSrica #ifdef DEBUG
1305*f875b4ebSrica 			(void) fprintf(logf,
1306*f875b4ebSrica 			    "update_cache_table found i = %d\n", i);
1307*f875b4ebSrica 			(void) fprintf(logf, "\ti = %d, tmpmask = 0x%4x\n",
1308*f875b4ebSrica 			    i, tmpmask);
1309*f875b4ebSrica #endif
1310*f875b4ebSrica 			rhp = (struct tnd_tnrhdb_c *)rhtable_lookup(saddrp, i);
1311*f875b4ebSrica 			if (rhp != NULL) {
1312*f875b4ebSrica 				(void) strcpy(result, rhp->rh_ent.rh_template);
1313*f875b4ebSrica 				/* Add this result to the cache also */
1314*f875b4ebSrica 				(void) rw_wrlock(&cache_rwlp);
1315*f875b4ebSrica 				add_cache_entry(addr, result, i, rhp);
1316*f875b4ebSrica 				rflag++;
1317*f875b4ebSrica 				(void) rw_unlock(&cache_rwlp);
1318*f875b4ebSrica 				break;
1319*f875b4ebSrica 			} else {
1320*f875b4ebSrica #ifdef DEBUG
1321*f875b4ebSrica 				(void) fprintf(logf,
1322*f875b4ebSrica 				    "rhtable_lookup return null !!");
1323*f875b4ebSrica #endif
1324*f875b4ebSrica 			}
1325*f875b4ebSrica 		}
1326*f875b4ebSrica 		(void) rw_unlock(&entire_rwlp);
1327*f875b4ebSrica 	}
1328*f875b4ebSrica 
1329*f875b4ebSrica 	rflag += walk_cache_table(addr, ent->rh_template, ent->rh_prefix, src);
1330*f875b4ebSrica 	return (rflag);
1331*f875b4ebSrica }
1332*f875b4ebSrica 
1333*f875b4ebSrica /*
1334*f875b4ebSrica  * Walk the cache table and check if this IP address/address prefix
1335*f875b4ebSrica  * will be a better match for an existing entry in the cache.
1336*f875b4ebSrica  */
1337*f875b4ebSrica static int
1338*f875b4ebSrica update_cache_table_v6(tsol_rhent_t *ent, tnd_tnrhdb_t *src)
1339*f875b4ebSrica {
1340*f875b4ebSrica 	int i;
1341*f875b4ebSrica 	char result[TNTNAMSIZ];
1342*f875b4ebSrica 	in6_addr_t addr;
1343*f875b4ebSrica 	struct sockaddr_in6 *saddrp;
1344*f875b4ebSrica 	tnrh_tlb_ipv6_t *tlbt;
1345*f875b4ebSrica 	struct tnd_tnrhdb_c	*rhp;
1346*f875b4ebSrica 	in6_addr_t tmpmask6;
1347*f875b4ebSrica 	int rflag = 0;
1348*f875b4ebSrica 
1349*f875b4ebSrica 	saddrp = (struct sockaddr_in6 *)&ent->rh_address.ip_addr_v6;
1350*f875b4ebSrica 	(void) memcpy(&addr, &saddrp->sin6_addr, sizeof (in6_addr_t));
1351*f875b4ebSrica 
1352*f875b4ebSrica 	/* Look in the cache first */
1353*f875b4ebSrica 	(void) rw_rdlock(&cache_rwlp);
1354*f875b4ebSrica 	tlbt = lookup_cache_table_v6(addr);
1355*f875b4ebSrica 	(void) rw_unlock(&cache_rwlp);
1356*f875b4ebSrica 
1357*f875b4ebSrica 
1358*f875b4ebSrica 	if (tlbt == NULL) {
1359*f875b4ebSrica 		(void) rw_rdlock(&entire_rwlp_v6);
1360*f875b4ebSrica 		for (i = (IPV6_MASK_TABLE_SIZE - 1); i >= 0; i--) {
1361*f875b4ebSrica 			if (tnrh_entire_table_v6[i] == NULL)
1362*f875b4ebSrica 				continue;
1363*f875b4ebSrica 			(void) rh_index_to_mask_v6(i, &tmpmask6);
1364*f875b4ebSrica 			rhp = (struct tnd_tnrhdb_c *)
1365*f875b4ebSrica 			    rhtable_lookup_v6(saddrp, tmpmask6, i);
1366*f875b4ebSrica 			if (rhp != NULL) {
1367*f875b4ebSrica 				(void) strcpy(result, rhp->rh_ent.rh_template);
1368*f875b4ebSrica 				/* Add this result to the cache also */
1369*f875b4ebSrica 				(void) rw_wrlock(&cache_rwlp_v6);
1370*f875b4ebSrica 				add_cache_entry_v6(addr, result, i, rhp);
1371*f875b4ebSrica 				rflag++;
1372*f875b4ebSrica 				(void) rw_unlock(&cache_rwlp_v6);
1373*f875b4ebSrica 				break;
1374*f875b4ebSrica 			}
1375*f875b4ebSrica 		}
1376*f875b4ebSrica 		(void) rw_unlock(&entire_rwlp_v6);
1377*f875b4ebSrica 	}
1378*f875b4ebSrica 
1379*f875b4ebSrica 	rflag += walk_cache_table_v6(addr, ent->rh_template,
1380*f875b4ebSrica 	    ent->rh_prefix, src);
1381*f875b4ebSrica 	return (rflag);
1382*f875b4ebSrica }
1383*f875b4ebSrica 
1384*f875b4ebSrica 
1385*f875b4ebSrica /*
1386*f875b4ebSrica  * Check if this prefix addr will be a better match
1387*f875b4ebSrica  * for an existing entry.
1388*f875b4ebSrica  */
1389*f875b4ebSrica static int
1390*f875b4ebSrica is_better_match(in_addr_t newaddr, int indx, tnrh_tlb_t *tlbt)
1391*f875b4ebSrica {
1392*f875b4ebSrica 	if (tlbt->masklen_used <= indx) {
1393*f875b4ebSrica 		in_addr_t tmpmask = rh_index_to_mask(indx);
1394*f875b4ebSrica 
1395*f875b4ebSrica 		if ((newaddr) == (tlbt->addr & tmpmask))
1396*f875b4ebSrica 			return (1);
1397*f875b4ebSrica 	}
1398*f875b4ebSrica 
1399*f875b4ebSrica 	return (0);
1400*f875b4ebSrica }
1401*f875b4ebSrica 
1402*f875b4ebSrica /*
1403*f875b4ebSrica  * Walk the cache table and update entries if needed.
1404*f875b4ebSrica  * Mark entries for reload to kernel, if somehow their
1405*f875b4ebSrica  * template changed.
1406*f875b4ebSrica  * why is_better_match() is called???
1407*f875b4ebSrica  */
1408*f875b4ebSrica static int
1409*f875b4ebSrica walk_cache_table(in_addr_t newaddr, char *name, int indx, tnd_tnrhdb_t *src)
1410*f875b4ebSrica {
1411*f875b4ebSrica 	int i;
1412*f875b4ebSrica 	tnrh_tlb_t *tlbt;
1413*f875b4ebSrica 	int rflag = 0;
1414*f875b4ebSrica 
1415*f875b4ebSrica 	for (i = 0; i < TNRH_TABLE_HASH_SIZE; i++) {
1416*f875b4ebSrica 		tlbt = tnrh_cache_table[i];
1417*f875b4ebSrica 
1418*f875b4ebSrica 		while (tlbt != NULL) {
1419*f875b4ebSrica 			if (is_better_match(newaddr, indx, tlbt)) {
1420*f875b4ebSrica 				tlbt->masklen_used = indx;
1421*f875b4ebSrica 				tlbt->src = src;
1422*f875b4ebSrica 				/*
1423*f875b4ebSrica 				 * Reload to the kernel only if the
1424*f875b4ebSrica 				 * host type changed. There is no need
1425*f875b4ebSrica 				 * to load, if only the mask used has changed,
1426*f875b4ebSrica 				 * since the kernel does not need that
1427*f875b4ebSrica 				 * information.
1428*f875b4ebSrica 				 */
1429*f875b4ebSrica 				if (strcmp(name, tlbt->template_name) != 0) {
1430*f875b4ebSrica 					(void) strncpy(tlbt->template_name,
1431*f875b4ebSrica 					    name, TNTNAMSIZ-1);
1432*f875b4ebSrica 					tlbt->reload = TNDB_LOAD;
1433*f875b4ebSrica 					rflag ++;
1434*f875b4ebSrica 				}
1435*f875b4ebSrica 			}
1436*f875b4ebSrica 
1437*f875b4ebSrica 			tlbt = tlbt->next;
1438*f875b4ebSrica 		}
1439*f875b4ebSrica 	}
1440*f875b4ebSrica #ifdef DEBUG
1441*f875b4ebSrica 	(void) fprintf(logf, gettext("walk_cache_table rflag=%d\n"), rflag);
1442*f875b4ebSrica #endif
1443*f875b4ebSrica 	return (rflag);
1444*f875b4ebSrica }
1445*f875b4ebSrica 
1446*f875b4ebSrica /*
1447*f875b4ebSrica  * Check if this prefix addr will be a better match
1448*f875b4ebSrica  * for an existing entry.
1449*f875b4ebSrica  */
1450*f875b4ebSrica static int
1451*f875b4ebSrica is_better_match_v6(in6_addr_t newaddr, int indx, tnrh_tlb_ipv6_t *tlbt)
1452*f875b4ebSrica {
1453*f875b4ebSrica 	in6_addr_t tmpmask;
1454*f875b4ebSrica 
1455*f875b4ebSrica 	if (tlbt->masklen_used <= indx) {
1456*f875b4ebSrica 		(void) rh_index_to_mask_v6(indx, &tmpmask);
1457*f875b4ebSrica 
1458*f875b4ebSrica 		if (V6_MASK_EQ(newaddr, tmpmask, tlbt->addr))
1459*f875b4ebSrica 			return (1);
1460*f875b4ebSrica 	}
1461*f875b4ebSrica 
1462*f875b4ebSrica 	return (0);
1463*f875b4ebSrica }
1464*f875b4ebSrica 
1465*f875b4ebSrica 
1466*f875b4ebSrica /*
1467*f875b4ebSrica  * Walk the cache table and update entries if needed.
1468*f875b4ebSrica  * Mark entries for reload to kernel, if somehow their
1469*f875b4ebSrica  * template changed.
1470*f875b4ebSrica  */
1471*f875b4ebSrica static int
1472*f875b4ebSrica walk_cache_table_v6(in6_addr_t newaddr, char *name, int indx, tnd_tnrhdb_t *src)
1473*f875b4ebSrica {
1474*f875b4ebSrica 	int i;
1475*f875b4ebSrica 	tnrh_tlb_ipv6_t *tlbt;
1476*f875b4ebSrica 	int rflag = 0;
1477*f875b4ebSrica 
1478*f875b4ebSrica 	for (i = 0; i < TNRH_TABLE_HASH_SIZE; i++) {
1479*f875b4ebSrica 		tlbt = tnrh_cache_table_v6[i];
1480*f875b4ebSrica 
1481*f875b4ebSrica 		while (tlbt != NULL) {
1482*f875b4ebSrica 			if (is_better_match_v6(newaddr, indx, tlbt)) {
1483*f875b4ebSrica 				tlbt->masklen_used = indx;
1484*f875b4ebSrica 				tlbt->src = src;
1485*f875b4ebSrica 				/*
1486*f875b4ebSrica 				 * Reload to the kernel only if the
1487*f875b4ebSrica 				 * host type changed. There is no need
1488*f875b4ebSrica 				 * to load, if only the mask used has changed,
1489*f875b4ebSrica 				 * since the kernel does not need that
1490*f875b4ebSrica 				 * information.
1491*f875b4ebSrica 				 */
1492*f875b4ebSrica 				if (strcmp(name, tlbt->template_name) != 0) {
1493*f875b4ebSrica 					(void) strncpy(tlbt->template_name,
1494*f875b4ebSrica 					    name, TNTNAMSIZ-1);
1495*f875b4ebSrica 					tlbt->reload = TNDB_LOAD;
1496*f875b4ebSrica 					rflag ++;
1497*f875b4ebSrica 				}
1498*f875b4ebSrica 			}
1499*f875b4ebSrica 
1500*f875b4ebSrica 			tlbt = tlbt->next;
1501*f875b4ebSrica 		}
1502*f875b4ebSrica 	}
1503*f875b4ebSrica 
1504*f875b4ebSrica 	return (rflag);
1505*f875b4ebSrica }
1506*f875b4ebSrica 
1507*f875b4ebSrica /*
1508*f875b4ebSrica  * load/delete marked rh ents into kernel
1509*f875b4ebSrica  * depending on the reload flag by invoking tnrh().
1510*f875b4ebSrica  * It will mark other entries as TNDB_NOOP
1511*f875b4ebSrica  */
1512*f875b4ebSrica static void
1513*f875b4ebSrica load_rh_marked()
1514*f875b4ebSrica {
1515*f875b4ebSrica 	int i;
1516*f875b4ebSrica 	tnrh_tlb_t *tlbt, *prev;
1517*f875b4ebSrica 	struct tsol_rhent rhentp;
1518*f875b4ebSrica 
1519*f875b4ebSrica 	(void) memset((char *)&rhentp, '\0', sizeof (rhentp));
1520*f875b4ebSrica 
1521*f875b4ebSrica 	for (i = 0; i < TNRH_TABLE_HASH_SIZE; i++) {
1522*f875b4ebSrica 
1523*f875b4ebSrica 		prev = tlbt = tnrh_cache_table[i];
1524*f875b4ebSrica 
1525*f875b4ebSrica 		while (tlbt != NULL) {
1526*f875b4ebSrica 			if ((tlbt->reload == TNDB_LOAD) ||
1527*f875b4ebSrica 			    (tlbt->reload == TNDB_DELETE)) {
1528*f875b4ebSrica 			/*
1529*f875b4ebSrica 			 * We have to call tnrh() with tsol_rhent argument.
1530*f875b4ebSrica 			 * Construct such a struct from the tlbt struct we have.
1531*f875b4ebSrica 			 */
1532*f875b4ebSrica 				rhentp.rh_address.ip_addr_v4.sin_addr.s_addr =
1533*f875b4ebSrica 				    tlbt->addr;
1534*f875b4ebSrica 				rhentp.rh_address.ip_addr_v4.sin_family =
1535*f875b4ebSrica 				    AF_INET;
1536*f875b4ebSrica 				rhentp.rh_prefix = tlbt->masklen_used;
1537*f875b4ebSrica 				(void) strcpy(rhentp.rh_template,
1538*f875b4ebSrica 				    tlbt->template_name);
1539*f875b4ebSrica 
1540*f875b4ebSrica #ifdef DEBUG
1541*f875b4ebSrica 				(void) fprintf(logf, "load op =%d\n",
1542*f875b4ebSrica 				    tlbt->reload);
1543*f875b4ebSrica 				print_tlbt(tlbt);
1544*f875b4ebSrica #endif
1545*f875b4ebSrica 				update_rh_entry(tlbt->reload, &rhentp);
1546*f875b4ebSrica 
1547*f875b4ebSrica 				if (tlbt->reload == TNDB_DELETE) {
1548*f875b4ebSrica 					if (tlbt == tnrh_cache_table[i]) {
1549*f875b4ebSrica 						tnrh_cache_table[i] =
1550*f875b4ebSrica 						    tlbt->next;
1551*f875b4ebSrica 						prev = tnrh_cache_table[i];
1552*f875b4ebSrica 					} else {
1553*f875b4ebSrica 						prev->next = tlbt->next;
1554*f875b4ebSrica 						prev = prev->next;
1555*f875b4ebSrica 					}
1556*f875b4ebSrica 
1557*f875b4ebSrica 					free(tlbt);
1558*f875b4ebSrica 					if (prev == NULL)
1559*f875b4ebSrica 						break;
1560*f875b4ebSrica 					else {
1561*f875b4ebSrica 						tlbt = prev;
1562*f875b4ebSrica 						continue;
1563*f875b4ebSrica 					}
1564*f875b4ebSrica 				}
1565*f875b4ebSrica 				tlbt->reload = TNDB_NOOP;
1566*f875b4ebSrica 			}
1567*f875b4ebSrica 
1568*f875b4ebSrica 			prev = tlbt;
1569*f875b4ebSrica 			tlbt = tlbt->next;
1570*f875b4ebSrica 		}
1571*f875b4ebSrica 	}
1572*f875b4ebSrica 
1573*f875b4ebSrica }
1574*f875b4ebSrica 
1575*f875b4ebSrica /* load marked rh ents into kernel */
1576*f875b4ebSrica static void
1577*f875b4ebSrica load_rh_marked_v6()
1578*f875b4ebSrica {
1579*f875b4ebSrica 	int i;
1580*f875b4ebSrica 	tnrh_tlb_ipv6_t *tlbt, *prev;
1581*f875b4ebSrica 	struct tsol_rhent rhentp;
1582*f875b4ebSrica 
1583*f875b4ebSrica 	(void) memset((char *)&rhentp, '\0', sizeof (rhentp));
1584*f875b4ebSrica 
1585*f875b4ebSrica 	for (i = 0; i < TNRH_TABLE_HASH_SIZE; i++) {
1586*f875b4ebSrica 		prev = tlbt = tnrh_cache_table_v6[i];
1587*f875b4ebSrica 
1588*f875b4ebSrica 		while (tlbt != NULL) {
1589*f875b4ebSrica 		if ((tlbt->reload == TNDB_LOAD) ||
1590*f875b4ebSrica 		    (tlbt->reload == TNDB_DELETE)) {
1591*f875b4ebSrica 			/*
1592*f875b4ebSrica 			 * We have to call tnrh() with tsol_rhent argument.
1593*f875b4ebSrica 			 * Construct such a struct from the tlbt struct we have.
1594*f875b4ebSrica 			 */
1595*f875b4ebSrica 			(void) memcpy(&rhentp.rh_address.ip_addr_v6.sin6_addr,
1596*f875b4ebSrica 			    &tlbt->addr, sizeof (in6_addr_t));
1597*f875b4ebSrica 			rhentp.rh_address.ip_addr_v6.sin6_family = AF_INET6;
1598*f875b4ebSrica 			rhentp.rh_prefix = tlbt->masklen_used;
1599*f875b4ebSrica 			(void) strcpy(rhentp.rh_template, tlbt->template_name);
1600*f875b4ebSrica 
1601*f875b4ebSrica 			update_rh_entry(tlbt->reload, &rhentp);
1602*f875b4ebSrica 
1603*f875b4ebSrica 			if (tlbt->reload == TNDB_DELETE) {
1604*f875b4ebSrica 				if (tlbt == tnrh_cache_table_v6[i]) {
1605*f875b4ebSrica 					tnrh_cache_table_v6[i] =
1606*f875b4ebSrica 					    tlbt->next;
1607*f875b4ebSrica 					prev = tnrh_cache_table_v6[i];
1608*f875b4ebSrica 				} else {
1609*f875b4ebSrica 					prev->next = tlbt->next;
1610*f875b4ebSrica 					prev = prev->next;
1611*f875b4ebSrica 				}
1612*f875b4ebSrica 
1613*f875b4ebSrica 				free(tlbt);
1614*f875b4ebSrica 				if (prev == NULL)
1615*f875b4ebSrica 					break;
1616*f875b4ebSrica 				else {
1617*f875b4ebSrica 					tlbt = prev;
1618*f875b4ebSrica 					continue;
1619*f875b4ebSrica 				}
1620*f875b4ebSrica 			}
1621*f875b4ebSrica 			tlbt->reload = TNDB_NOOP;
1622*f875b4ebSrica 		}
1623*f875b4ebSrica 
1624*f875b4ebSrica 		prev = tlbt;
1625*f875b4ebSrica 		tlbt = tlbt->next;
1626*f875b4ebSrica 	}
1627*f875b4ebSrica 	}
1628*f875b4ebSrica 
1629*f875b4ebSrica }
1630*f875b4ebSrica 
1631*f875b4ebSrica /*
1632*f875b4ebSrica  * Does the real load/delete for the entry depending on op code.
1633*f875b4ebSrica  */
1634*f875b4ebSrica 
1635*f875b4ebSrica static void
1636*f875b4ebSrica update_rh_entry(int op, struct tsol_rhent *rhentp)
1637*f875b4ebSrica {
1638*f875b4ebSrica #ifdef DEBUG
1639*f875b4ebSrica 	(void) fprintf(logf, gettext("\t###update_rh_entry op = %d\n"), op);
1640*f875b4ebSrica 	print_entry(rhentp, AF_INET);
1641*f875b4ebSrica #endif
1642*f875b4ebSrica 	if (tnrh(op, rhentp) != 0) {
1643*f875b4ebSrica 		if (debugl && (logf != NULL)) {
1644*f875b4ebSrica 			(void) fprintf(logf, "%s : ", gettime());
1645*f875b4ebSrica 			(void) fprintf(logf, gettext("tnrh() failed: %s\n"),
1646*f875b4ebSrica 			    strerror(errno));
1647*f875b4ebSrica 			if (op == TNDB_LOAD)
1648*f875b4ebSrica 			(void) fprintf(logf,
1649*f875b4ebSrica 			    gettext("load of remote host database "
1650*f875b4ebSrica 			    "%s into kernel cache failed\n"),
1651*f875b4ebSrica 			    rhentp->rh_template);
1652*f875b4ebSrica 			if (op == TNDB_DELETE)
1653*f875b4ebSrica 			(void) fprintf(logf,
1654*f875b4ebSrica 			    gettext("delete of remote host database "
1655*f875b4ebSrica 			    "%s from kernel cache failed\n"),
1656*f875b4ebSrica 			    rhentp->rh_template);
1657*f875b4ebSrica 			(void) fflush(logf);
1658*f875b4ebSrica 		}
1659*f875b4ebSrica 		cprint("tnrh() failed..: %s\n", strerror(errno));
1660*f875b4ebSrica 	}
1661*f875b4ebSrica }
1662*f875b4ebSrica 
1663*f875b4ebSrica static void
1664*f875b4ebSrica timer()
1665*f875b4ebSrica {
1666*f875b4ebSrica 	poll_now();
1667*f875b4ebSrica 	(void) alarm(poll_interval);
1668*f875b4ebSrica }
1669*f875b4ebSrica 
1670*f875b4ebSrica #define	max(a, b)	((a) > (b) ? (a) : (b))
1671*f875b4ebSrica 
1672*f875b4ebSrica static void
1673*f875b4ebSrica poll_now()
1674*f875b4ebSrica {
1675*f875b4ebSrica 
1676*f875b4ebSrica 	(void) fprintf(logf, "enter poll_now at %s \n", gettime());
1677*f875b4ebSrica 	(void) fflush(logf);
1678*f875b4ebSrica 
1679*f875b4ebSrica 	if (nss_get_tp() > 0) {
1680*f875b4ebSrica 		load_tp();
1681*f875b4ebSrica 		tp_flush_cache();
1682*f875b4ebSrica 	}
1683*f875b4ebSrica 
1684*f875b4ebSrica #ifdef DEBUG
1685*f875b4ebSrica 	(void) fprintf(logf, "now search for tnrhdb update %s \n", gettime());
1686*f875b4ebSrica #endif
1687*f875b4ebSrica 
1688*f875b4ebSrica 	if (nss_get_rh() > 0) {
1689*f875b4ebSrica 		if (logf != NULL) {
1690*f875b4ebSrica 			(void) fprintf(logf, "tnrhdb needs update %s \n",
1691*f875b4ebSrica 			    gettime());
1692*f875b4ebSrica 		}
1693*f875b4ebSrica 
1694*f875b4ebSrica 		(void) rw_wrlock(&cache_rwlp);
1695*f875b4ebSrica 		/* This function will cleanup cache table */
1696*f875b4ebSrica 		load_rh_marked();
1697*f875b4ebSrica 		(void) rw_unlock(&cache_rwlp);
1698*f875b4ebSrica 
1699*f875b4ebSrica 		(void) rw_wrlock(&cache_rwlp_v6);
1700*f875b4ebSrica 		/* This function will cleanup cache table */
1701*f875b4ebSrica 		load_rh_marked_v6();
1702*f875b4ebSrica 		(void) rw_unlock(&cache_rwlp_v6);
1703*f875b4ebSrica 	}
1704*f875b4ebSrica 
1705*f875b4ebSrica #ifdef DEBUG
1706*f875b4ebSrica 	if (logf != NULL) {
1707*f875b4ebSrica 		cachetable_print();
1708*f875b4ebSrica 		cachetable_print_v6();
1709*f875b4ebSrica 
1710*f875b4ebSrica 		(void) fprintf(logf, "rh table begin\n");
1711*f875b4ebSrica 		rhtable_print();
1712*f875b4ebSrica 		rhtable_print_v6();
1713*f875b4ebSrica 		(void) fprintf(logf, "rh table end \n");
1714*f875b4ebSrica 		(void) fprintf(logf, "-------------------------\n\n");
1715*f875b4ebSrica 		(void) fflush(logf);
1716*f875b4ebSrica 	}
1717*f875b4ebSrica #endif
1718*f875b4ebSrica }
1719*f875b4ebSrica 
1720*f875b4ebSrica static void
1721*f875b4ebSrica tnd_serve()
1722*f875b4ebSrica {
1723*f875b4ebSrica 	for (;;) {
1724*f875b4ebSrica 		(void) pause();
1725*f875b4ebSrica 	}
1726*f875b4ebSrica }
1727*f875b4ebSrica 
1728*f875b4ebSrica static void
1729*f875b4ebSrica terminate()
1730*f875b4ebSrica {
1731*f875b4ebSrica 	if (debugl && (logf != NULL)) {
1732*f875b4ebSrica 		(void) fprintf(logf, "%s : ", gettime());
1733*f875b4ebSrica 		(void) fprintf(logf, gettext("tnd terminating on signal.\n"));
1734*f875b4ebSrica 		(void) fflush(logf);
1735*f875b4ebSrica 	}
1736*f875b4ebSrica 	exit(1);
1737*f875b4ebSrica }
1738*f875b4ebSrica 
1739*f875b4ebSrica static void
1740*f875b4ebSrica noop()
1741*f875b4ebSrica {
1742*f875b4ebSrica }
1743*f875b4ebSrica 
1744*f875b4ebSrica static char *
1745*f875b4ebSrica gettime()
1746*f875b4ebSrica {
1747*f875b4ebSrica 	time_t now;
1748*f875b4ebSrica 	struct tm *tp, tm;
1749*f875b4ebSrica 	char *fmt;
1750*f875b4ebSrica 
1751*f875b4ebSrica 	(void) time(&now);
1752*f875b4ebSrica 	tp = localtime(&now);
1753*f875b4ebSrica 	(void) memcpy(&tm, tp, sizeof (struct tm));
1754*f875b4ebSrica 	fmt = nl_langinfo(_DATE_FMT);
1755*f875b4ebSrica 
1756*f875b4ebSrica 	(void) strftime(time_buf, _SZ_TIME_BUF, fmt, &tm);
1757*f875b4ebSrica 
1758*f875b4ebSrica 	return (time_buf);
1759*f875b4ebSrica }
1760*f875b4ebSrica /*
1761*f875b4ebSrica  * debugging routines
1762*f875b4ebSrica  */
1763*f875b4ebSrica 
1764*f875b4ebSrica 
1765*f875b4ebSrica #ifdef DEBUG
1766*f875b4ebSrica static void
1767*f875b4ebSrica print_cache_entry(tnrh_tlb_t *tlbt)
1768*f875b4ebSrica {
1769*f875b4ebSrica 	struct in_addr addr;
1770*f875b4ebSrica 
1771*f875b4ebSrica 	addr.s_addr = tlbt->addr;
1772*f875b4ebSrica 	(void) fprintf(logf, "\tIP address: %s", inet_ntoa(addr));
1773*f875b4ebSrica 	(void) fprintf(logf, "\tTemplate name: %s", tlbt->template_name);
1774*f875b4ebSrica 	(void) fprintf(logf, "\tMask length used: %d\n", tlbt->masklen_used);
1775*f875b4ebSrica }
1776*f875b4ebSrica 
1777*f875b4ebSrica static void
1778*f875b4ebSrica print_cache_entry_v6(tnrh_tlb_ipv6_t *tlbt)
1779*f875b4ebSrica {
1780*f875b4ebSrica 	char abuf[INET6_ADDRSTRLEN];
1781*f875b4ebSrica 
1782*f875b4ebSrica 	(void) fprintf(logf, "\tIP address: %s",
1783*f875b4ebSrica 	    inet_ntop(AF_INET6, &tlbt->addr, abuf, sizeof (abuf)));
1784*f875b4ebSrica 	(void) fprintf(logf, "\tTemplate name: %s", tlbt->template_name);
1785*f875b4ebSrica 	(void) fprintf(logf, "\tMask length used: %d\n", tlbt->masklen_used);
1786*f875b4ebSrica }
1787*f875b4ebSrica 
1788*f875b4ebSrica static void
1789*f875b4ebSrica cachetable_print()
1790*f875b4ebSrica {
1791*f875b4ebSrica 	int i;
1792*f875b4ebSrica 	tnrh_tlb_t *tlbt;
1793*f875b4ebSrica 
1794*f875b4ebSrica 	(void) fprintf(logf, "-------------------------\n");
1795*f875b4ebSrica 	(void) fprintf(logf, "Cache table begin\n");
1796*f875b4ebSrica 
1797*f875b4ebSrica 	for (i = 0; i < TNRH_TABLE_HASH_SIZE; i++) {
1798*f875b4ebSrica 		if ((tlbt = tnrh_cache_table[i]) != NULL)
1799*f875b4ebSrica 			print_cache_entry(tlbt);
1800*f875b4ebSrica 	}
1801*f875b4ebSrica 
1802*f875b4ebSrica 	(void) fprintf(logf, "Cache table end \n");
1803*f875b4ebSrica 	(void) fprintf(logf, "-------------------------\n\n");
1804*f875b4ebSrica }
1805*f875b4ebSrica 
1806*f875b4ebSrica static void
1807*f875b4ebSrica cachetable_print_v6()
1808*f875b4ebSrica {
1809*f875b4ebSrica 	int i;
1810*f875b4ebSrica 	tnrh_tlb_ipv6_t *tlbt;
1811*f875b4ebSrica 
1812*f875b4ebSrica 	(void) fprintf(logf, "-------------------------\n");
1813*f875b4ebSrica 	(void) fprintf(logf, "Cache table begin\n");
1814*f875b4ebSrica 
1815*f875b4ebSrica 	for (i = 0; i < TNRH_TABLE_HASH_SIZE; i++) {
1816*f875b4ebSrica 		if ((tlbt = tnrh_cache_table_v6[i]) != NULL)
1817*f875b4ebSrica 			print_cache_entry_v6(tlbt);
1818*f875b4ebSrica 	}
1819*f875b4ebSrica 
1820*f875b4ebSrica 	(void) fprintf(logf, "Cache table end \n");
1821*f875b4ebSrica 	(void) fprintf(logf, "-------------------------\n\n");
1822*f875b4ebSrica }
1823*f875b4ebSrica 
1824*f875b4ebSrica 
1825*f875b4ebSrica static void
1826*f875b4ebSrica print_entry(tsol_rhent_t *ent, int af)
1827*f875b4ebSrica {
1828*f875b4ebSrica 	struct sockaddr_in *saddrp;
1829*f875b4ebSrica 	struct sockaddr_in6 *saddrp6;
1830*f875b4ebSrica 	char abuf[INET6_ADDRSTRLEN];
1831*f875b4ebSrica 
1832*f875b4ebSrica 	if (af == AF_INET) {
1833*f875b4ebSrica 		saddrp = (struct sockaddr_in *)&ent->rh_address.ip_addr_v4;
1834*f875b4ebSrica 		(void) fprintf(logf, gettext("\tIP address: %s"),
1835*f875b4ebSrica 		    inet_ntoa(saddrp->sin_addr));
1836*f875b4ebSrica 	} else if (af == AF_INET6) {
1837*f875b4ebSrica 		saddrp6 = (struct sockaddr_in6 *)&ent->rh_address.ip_addr_v6;
1838*f875b4ebSrica 		(void) fprintf(logf, gettext("\tIP address: %s"),
1839*f875b4ebSrica 		    inet_ntop(AF_INET6, &saddrp6->sin6_addr, abuf,
1840*f875b4ebSrica 		    sizeof (abuf)));
1841*f875b4ebSrica 	}
1842*f875b4ebSrica 
1843*f875b4ebSrica 	(void) fprintf(logf,
1844*f875b4ebSrica 	    gettext("\tTemplate name: %s"), ent->rh_template);
1845*f875b4ebSrica 	(void) fprintf(logf, gettext("\tprefix_len: %d\n"), ent->rh_prefix);
1846*f875b4ebSrica 	(void) fflush(logf);
1847*f875b4ebSrica }
1848*f875b4ebSrica 
1849*f875b4ebSrica static void
1850*f875b4ebSrica print_tlbt(tnrh_tlb_t *tlbt)
1851*f875b4ebSrica {
1852*f875b4ebSrica 	(void) fprintf(logf, "tlbt addr = 0x%4x name = %s \
1853*f875b4ebSrica 	    mask = %u, reload = %d\n", tlbt->addr, tlbt->template_name,
1854*f875b4ebSrica 	    tlbt->masklen_used, tlbt->reload);
1855*f875b4ebSrica }
1856*f875b4ebSrica 
1857*f875b4ebSrica static void
1858*f875b4ebSrica rhtable_print()
1859*f875b4ebSrica {
1860*f875b4ebSrica 	rhtable_walk(print_entry);
1861*f875b4ebSrica 	(void) fprintf(logf, "-----------------------------\n\n");
1862*f875b4ebSrica }
1863*f875b4ebSrica 
1864*f875b4ebSrica static void
1865*f875b4ebSrica rhtable_print_v6()
1866*f875b4ebSrica {
1867*f875b4ebSrica 	rhtable_walk_v6(print_entry);
1868*f875b4ebSrica 	(void) fprintf(logf, "-----------------------------\n\n");
1869*f875b4ebSrica }
1870*f875b4ebSrica 
1871*f875b4ebSrica /*
1872*f875b4ebSrica  * Walk through all the entries in tnrh_entire_table[][]
1873*f875b4ebSrica  * and execute the function passing the entry as argument.
1874*f875b4ebSrica  */
1875*f875b4ebSrica static void
1876*f875b4ebSrica rhtable_walk(void (*action)())
1877*f875b4ebSrica {
1878*f875b4ebSrica 	int i, j;
1879*f875b4ebSrica 	tnd_tnrhdb_t *rhent;
1880*f875b4ebSrica 
1881*f875b4ebSrica 	for (i = 0; i <= IP_ABITS; i++) {
1882*f875b4ebSrica 		if (tnrh_entire_table[i] == NULL)
1883*f875b4ebSrica 			continue;
1884*f875b4ebSrica 
1885*f875b4ebSrica 		for (j = 0; j < TNRH_TABLE_HASH_SIZE; j++) {
1886*f875b4ebSrica 			rhent = tnrh_entire_table[i][j];
1887*f875b4ebSrica 
1888*f875b4ebSrica 			while (rhent != NULL) {
1889*f875b4ebSrica 				action(&rhent->rh_ent, AF_INET);
1890*f875b4ebSrica 				rhent = rhent->rh_next;
1891*f875b4ebSrica 			}
1892*f875b4ebSrica 		}
1893*f875b4ebSrica 	}
1894*f875b4ebSrica }
1895*f875b4ebSrica 
1896*f875b4ebSrica /*
1897*f875b4ebSrica  * Walk through all the entries in tnrh_entire_table_v6[][]
1898*f875b4ebSrica  * and execute the function passing the entry as argument.
1899*f875b4ebSrica  */
1900*f875b4ebSrica static void
1901*f875b4ebSrica rhtable_walk_v6(void (*action)())
1902*f875b4ebSrica {
1903*f875b4ebSrica 	int i, j;
1904*f875b4ebSrica 	tnd_tnrhdb_t *rhent;
1905*f875b4ebSrica 
1906*f875b4ebSrica 	for (i = 0; i <= IPV6_ABITS; i++) {
1907*f875b4ebSrica 		if (tnrh_entire_table_v6[i] == NULL)
1908*f875b4ebSrica 			continue;
1909*f875b4ebSrica 
1910*f875b4ebSrica 		for (j = 0; j < TNRH_TABLE_HASH_SIZE; j++) {
1911*f875b4ebSrica 			rhent = tnrh_entire_table_v6[i][j];
1912*f875b4ebSrica 
1913*f875b4ebSrica 			while (rhent != NULL) {
1914*f875b4ebSrica 				action(&rhent->rh_ent, AF_INET6);
1915*f875b4ebSrica 				rhent = rhent->rh_next;
1916*f875b4ebSrica 			}
1917*f875b4ebSrica 		}
1918*f875b4ebSrica 	}
1919*f875b4ebSrica }
1920*f875b4ebSrica #endif /* DEBUG */
1921