1255332Scy/* $FreeBSD$ */
2255332Scy
3255332Scy/*
4255332Scy * Copyright (C) 2012 by Darren Reed.
5255332Scy * (C)opyright 1997 by Marc Boucher.
6255332Scy *
7255332Scy * See the IPFILTER.LICENCE file for details on licencing.
8255332Scy *
9255332Scy */
10255332Scy
11255332Scy/* TODO: (MARCXXX)
12255332Scy	- ipl_init failure -> open ENODEV or whatever
13255332Scy	- prevent multiple LKM loads
14255332Scy	- surround access to ifnet structures by IFNET_LOCK()/IFNET_UNLOCK() ?
15255332Scy	- m != m1 problem
16255332Scy*/
17255332Scy
18255332Scy#include <sys/types.h>
19255332Scy#include <sys/conf.h>
20255332Scy#ifdef IPFILTER_LKM
21255332Scy#include <sys/mload.h>
22255332Scy#endif
23255332Scy#include <sys/systm.h>
24255332Scy#include <sys/errno.h>
25255332Scy#include <net/if.h>
26255332Scy#include <net/route.h>
27255332Scy#include <netinet/in.h>
28255332Scy#ifdef IFF_DRVRLOCK /* IRIX6 */
29255332Scy#include <sys/hashing.h>
30255332Scy#include <netinet/in_var.h>
31255332Scy#endif
32255332Scy#include <sys/mbuf.h>
33255332Scy#include <netinet/in_systm.h>
34255332Scy#include <netinet/ip.h>
35255332Scy#include <netinet/ip_var.h>
36255332Scy#include <netinet/tcp.h>
37255332Scy#include <netinet/udp.h>
38255332Scy#include <netinet/tcpip.h>
39255332Scy#include <netinet/ip_icmp.h>
40255332Scy#include <netinet/ipfilter.h>
41255332Scy#include "ipl.h"
42255332Scy#include "ip_compat.h"
43255332Scy#include "ip_fil.h"
44255332Scy#include "ip_nat.h"
45255332Scy
46255332Scy#ifndef	MBUF_IS_CLUSTER
47255332Scy# define	MBUF_IS_CLUSTER(m)	((m)->m_flags & MCL_CLUSTER)
48255332Scy#endif
49255332Scy#undef	IPFDEBUG	/* #define IPFDEBUG 9 */
50255332Scy
51255332Scy#ifdef IPFILTER_LKM
52255332Scyu_int	ipldevflag = D_MP;
53255332Scychar	*iplmversion = M_VERSION;
54255332Scy#else
55255332Scyu_int	ipfilterdevflag = D_MP;
56255332Scychar	*ipfiltermversion = M_VERSION;
57255332Scy#endif
58255332Scy
59255332Scyipfmutex_t	ipl_mutex, ipfi_mutex, ipf_rw, ipf_stinsert, ipf_auth_mx;
60255332Scyipfmutex_t	ipf_nat_new, ipf_natio, ipf_timeoutlock;
61255332Scyipfrwlock_t	ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth;
62255332Scyipfrwlock_t	ipf_global, ipf_mutex, ipf_ipidfrag, ipf_frcache, ipf_tokens;
63255332Scy
64255332Scyint     (*ipf_checkp) __P((struct ip *, int, void *, int, mb_t **));
65255332Scy
66255332Scy#ifdef IPFILTER_LKM
67255332Scystatic int *ipff_addr = 0;
68255332Scystatic int ipff_value;
69255332Scystatic __psunsigned_t *ipfk_addr = 0;
70255332Scystatic __psunsigned_t ipfk_code[4];
71255332Scy#endif
72255332Scystatic void nifattach();
73255332Scystatic void nifdetach();
74255332Scy
75255332Scytypedef	struct	nif	{
76255332Scy	struct	nif	*nf_next;
77255332Scy	struct ifnet	*nf_ifp;
78255332Scy#if (IRIX < 60500)
79255332Scy	int     (*nf_output)(struct ifnet *, struct mbuf *, struct sockaddr *);
80255332Scy#else
81255332Scy	int     (*nf_output)(struct ifnet *, struct mbuf *, struct sockaddr *,
82255332Scy			     struct rtentry *);
83255332Scy#endif
84255332Scy	char	nf_name[LIFNAMSIZ];
85255332Scy	int	nf_unit;
86255332Scy} nif_t;
87255332Scy
88255332Scystatic nif_t *nif_head = 0;
89255332Scystatic int nif_interfaces = 0;
90255332Scyextern int in_interfaces;
91255332Scy#if IRIX >= 60500
92255332Scytoid_t	ipf_timer_id;
93255332Scy#endif
94255332Scy
95255332Scyextern ipnat_t *nat_list;
96255332Scy
97255332Scy#ifdef IPFDEBUG
98255332Scystatic void ipf_dumppacket(m)
99255332Scy	struct mbuf *m;
100255332Scy{
101255332Scy	u_char *s;
102255332Scy	char *t, line[80];
103255332Scy	int len, off, i;
104255332Scy
105255332Scy	off = 0;
106255332Scy
107255332Scy	while (m != NULL) {
108255332Scy		len = M_LEN(m);
109255332Scy		s = mtod(m, u_char *);
110255332Scy		printf("mbuf 0x%lx len %d flags %x type %d\n",
111255332Scy			m, len, m->m_flags, m->m_type);
112255332Scy		printf("dat 0x%lx off 0x%lx/%d s 0x%lx next 0x%lx\n",
113255332Scy			m->m_dat, m->m_off, m->m_off, s, m->m_next);
114255332Scy		while (len > 0) {
115255332Scy			t = line;
116255332Scy			for (i = 0; (i < 16) && (len > 0); len--, i++)
117255332Scy				sprintf(t, " %02x", *s++), t += strlen(t);
118255332Scy			*s = '\0';
119255332Scy			printf("mbuf:%x:%s\n", off, line);
120255332Scy			off += 16;
121255332Scy		}
122255332Scy		m = m->m_next;
123255332Scy	}
124255332Scy}
125255332Scy#endif
126255332Scy
127255332Scy
128255332Scystatic int
129255332Scy#if IRIX < 60500
130255332Scyipl_if_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst)
131255332Scy#else
132255332Scyipl_if_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
133255332Scy	      struct rtentry *rt)
134255332Scy#endif
135255332Scy{
136255332Scy#if (IPFDEBUG >= 0)
137255332Scy	static unsigned int cnt = 0;
138255332Scy#endif
139255332Scy	nif_t *nif;
140255332Scy
141255332Scy	MUTEX_ENTER(&ipfi_mutex); /* sets interrupt priority level to splhi */
142255332Scy	for (nif = nif_head; nif; nif = nif->nf_next)
143255332Scy		if (nif->nf_ifp == ifp)
144255332Scy			break;
145255332Scy	MUTEX_EXIT(&ipfi_mutex);
146255332Scy
147255332Scy	if (nif == NULL) {
148255332Scy		printf("IP Filter: ipl_if_output intf %x NOT FOUND\n", ifp);
149255332Scy		return ENETDOWN;
150255332Scy	}
151255332Scy
152255332Scy#if (IPFDEBUG >= 7)
153255332Scy	if ((++cnt % 200) == 0)
154255332Scy		printf("IP Filter: ipl_if_output(ifp=0x%lx, m=0x%lx, dst=0x%lx), m_type=%d m_flags=0x%lx m_off=0x%lx\n", ifp, m, dst, m->m_type, (u_long)m->m_flags, m->m_off);
155255332Scy#endif
156255332Scy
157255332Scy	if (ipf_checkp) {
158255332Scy		struct mbuf *m1 = m;
159255332Scy		struct ip *ip;
160255332Scy		int hlen;
161255332Scy
162255332Scy		switch(m->m_type)
163255332Scy		{
164255332Scy		case MT_HEADER:
165255332Scy			if (m->m_len == 0) {
166255332Scy				if (m->m_next == NULL)
167255332Scy					break;
168255332Scy				m = m->m_next;
169255332Scy			}
170255332Scy			/* FALLTHROUGH */
171255332Scy		case MT_DATA:
172255332Scy			if (!MBUF_IS_CLUSTER(m) &&
173255332Scy			    ((m->m_off < MMINOFF) || (m->m_off > MMAXOFF))) {
174255332Scy#if (IPFDEBUG >= 4)
175255332Scy				printf("IP Filter: ipl_if_output: bad m_off m_type=%d m_flags=0x%lx m_off=0x%lx\n", m->m_type, (u_long)m->m_flags, m->m_off);
176255332Scy#endif
177255332Scy				break;
178255332Scy			}
179255332Scy			if (m->m_len < sizeof(char)) {
180255332Scy#if (IPFDEBUG >= 3)
181255332Scy				printf("IP Filter: ipl_if_output: mbuf block too small (m_len=%d) for IP vers+hlen, m_type=%d m_flags=0x%lx\n", m->m_len, m->m_type, (u_long)m->m_flags);
182255332Scy#endif
183255332Scy				break;
184255332Scy			}
185255332Scy			ip = mtod(m, struct ip *);
186255332Scy			if (ip->ip_v != IPVERSION) {
187255332Scy#if (IPFDEBUG >= 2)
188255332Scy				ipf_dumppacket(m);
189255332Scy				printf("IP Filter: ipl_if_output: bad ip_v m_type=%d m_flags=0x%lx m_off=0x%lx\n", m->m_type, (u_long)m->m_flags, m->m_off);
190255332Scy#endif
191255332Scy				break;
192255332Scy			}
193255332Scy
194255332Scy			hlen = ip->ip_hl << 2;
195255332Scy			if ((*ipf_checkp)(ip, hlen, ifp, 1, &m1) || (m1 == NULL))
196255332Scy				return EHOSTUNREACH;
197255332Scy
198255332Scy			m = m1;
199255332Scy			break;
200255332Scy
201255332Scy		default:
202255332Scy#if (IPFDEBUG >= 2)
203255332Scy			printf("IP Filter: ipl_if_output: bad m_type=%d m_flags=0x%lxm_off=0x%lx\n", m->m_type, (u_long)m->m_flags, m->m_off);
204255332Scy#endif
205255332Scy			break;
206255332Scy		}
207255332Scy	}
208255332Scy#if (IRIX < 60500)
209255332Scy	return (*nif->nf_output)(ifp, m, dst);
210255332Scy#else
211255332Scy	return (*nif->nf_output)(ifp, m, dst, rt);
212255332Scy#endif
213255332Scy}
214255332Scy
215255332Scyint
216255332Scy
217255332Scy
218255332Scy#if !defined(IPFILTER_LKM) && (IRIX >= 60500)
219255332Scyipfilter_kernel(struct ifnet *rcvif, struct mbuf *m)
220255332Scy#else
221255332Scyipl_kernel(struct ifnet *rcvif, struct mbuf *m)
222255332Scy#endif
223255332Scy{
224255332Scy#if (IPFDEBUG >= 7)
225255332Scy	static unsigned int cnt = 0;
226255332Scy
227255332Scy	if ((++cnt % 200) == 0)
228255332Scy		printf("IP Filter: ipl_kernel(rcvif=0x%lx, m=0x%lx\n",
229255332Scy			rcvif, m);
230255332Scy#endif
231255332Scy
232255332Scy	if (ipf_running <= 0)
233255332Scy		return IPF_ACCEPTIT;
234255332Scy
235255332Scy	/*
236255332Scy	 * Check if we want to allow this packet to be processed.
237255332Scy	 * Consider it to be bad if not.
238255332Scy	 */
239255332Scy	if (ipf_checkp) {
240255332Scy		struct mbuf *m1 = m;
241255332Scy		struct ip *ip;
242255332Scy		int hlen;
243255332Scy
244255332Scy		if ((m->m_type != MT_DATA) && (m->m_type != MT_HEADER)) {
245255332Scy#if (IPFDEBUG >= 4)
246255332Scy			printf("IP Filter: ipl_kernel: bad m_type=%d m_flags=0x%lx m_off=0x%lx\n", m->m_type, (u_long)m->m_flags, m->m_off);
247255332Scy#endif
248255332Scy			return IPF_ACCEPTIT;
249255332Scy		}
250255332Scy
251255332Scy		if (!MBUF_IS_CLUSTER(m) &&
252255332Scy		    ((m->m_off < MMINOFF) || (m->m_off > MMAXOFF))) {
253255332Scy#if (IPFDEBUG >= 4)
254255332Scy			printf("IP Filter: ipl_kernel: bad m_off m_type=%d m_flags=0x%lx m_off=0x%lx\n", m->m_type, (u_long)m->m_flags, m->m_off);
255255332Scy#endif
256255332Scy			return IPF_ACCEPTIT;
257255332Scy		}
258255332Scy
259255332Scy		if (m->m_len < sizeof(char)) {
260255332Scy#if (IPFDEBUG >= 1)
261255332Scy			printf("IP Filter: ipl_kernel: mbuf block too small (m_len=%d) for IP vers+hlen, m_type=%d m_flags=0x%lx\n", m->m_len, m->m_type, (u_long)m->m_flags);
262255332Scy#endif
263255332Scy			return IPF_ACCEPTIT;
264255332Scy		}
265255332Scy
266255332Scy		ip = mtod(m, struct ip *);
267255332Scy		if (ip->ip_v != IPVERSION) {
268255332Scy#if (IPFDEBUG >= 4)
269255332Scy			printf("IP Filter: ipl_kernel: bad ip_v\n");
270255332Scy#endif
271255332Scy			m_freem(m);
272255332Scy			return IPF_DROPIT;
273255332Scy		}
274255332Scy
275255332Scy		ip->ip_len = htons(ip->ip_len);
276255332Scy		ip->ip_off = htons(ip->ip_off);
277255332Scy		hlen = ip->ip_hl << 2;
278255332Scy		if ((*ipf_checkp)(ip, hlen, rcvif, 0, &m1) || !m1)
279255332Scy			return IPF_DROPIT;
280255332Scy		ip = mtod(m1, struct ip *);
281255332Scy		ip->ip_len = ntohs(ip->ip_len);
282255332Scy		ip->ip_off = ntohs(ip->ip_off);
283255332Scy
284255332Scy#if (IPFDEBUG >= 2)
285255332Scy		if (m != m1)
286255332Scy			printf("IP Filter: ipl_kernel: m != m1\n");
287255332Scy#endif
288255332Scy	}
289255332Scy
290255332Scy	return IPF_ACCEPTIT;
291255332Scy}
292255332Scy
293255332Scyint
294255332Scyipl_ipfilter_attach(void)
295255332Scy{
296255332Scy#if defined(IPFILTER_LKM)
297255332Scy	__psunsigned_t *addr_ff, *addr_fk;
298255332Scy
299255332Scy	st_findaddr("ipfilterflag", &addr_ff);
300255332Scy# if (IPFDEBUG >= 1)
301255332Scy	printf("IP Filter: st_findaddr ipfilterflag=0x%lx\n", addr_ff);
302255332Scy# endif
303255332Scy	if (!addr_ff)
304255332Scy		return ESRCH;
305255332Scy
306255332Scy	st_findaddr("ipfilter_kernel", &addr_fk);
307255332Scy# if (IPFDEBUG >= 1)
308255332Scy	printf("IP Filter: st_findaddr ipfilter_kernel=0x%lx\n", addr_fk);
309255332Scy# endif
310255332Scy	if (!addr_fk)
311255332Scy		return ESRCH;
312255332Scy
313255332Scy	MUTEX_ENTER(&ipfi_mutex); /* sets interrupt priority level to splhi */
314255332Scy
315255332Scy	ipff_addr = (int *)addr_ff;
316255332Scy
317255332Scy	ipff_value = *ipff_addr;
318255332Scy	*ipff_addr = 0;
319255332Scy
320255332Scy
321255332Scy	ipfk_addr = addr_fk;
322255332Scy
323255332Scy	bcopy(ipfk_addr, ipfk_code, sizeof(ipfk_code));
324255332Scy
325255332Scy	/* write a "li t4, ipl_kernel" instruction */
326255332Scy	ipfk_addr[0] = 0x3c0c0000 |
327255332Scy		       (((__psunsigned_t)ipl_kernel >> 16) & 0xffff);
328255332Scy	ipfk_addr[1] = 0x358c0000 |
329255332Scy		       ((__psunsigned_t)ipl_kernel & 0xffff);
330255332Scy	/* write a "jr t4" instruction" */
331255332Scy	ipfk_addr[2] = 0x01800008;
332255332Scy
333255332Scy	/* write a "nop" instruction */
334255332Scy	ipfk_addr[3] = 0;
335255332Scy
336255332Scy	icache_inval(ipfk_addr, sizeof(ipfk_code));
337255332Scy
338255332Scy	*ipff_addr = 1; /* enable ipfilter_kernel */
339255332Scy
340255332Scy	MUTEX_EXIT(&ipfi_mutex);
341255332Scy#else
342255332Scy	extern int ipfilterflag;
343255332Scy
344255332Scy	ipfilterflag = 1;
345255332Scy#endif
346255332Scy	nif_interfaces = 0;
347255332Scy	nifattach();
348255332Scy
349255332Scy	return 0;
350255332Scy}
351255332Scy
352255332Scy
353255332Scy/*
354255332Scy * attach the packet filter to each non-loopback interface that is running
355255332Scy */
356255332Scystatic void
357255332Scynifattach()
358255332Scy{
359255332Scy	nif_t *nif, *qf2;
360255332Scy	struct ifnet *ifp;
361255332Scy	struct frentry *f;
362255332Scy	ipnat_t *np;
363255332Scy
364255332Scy	MUTEX_ENTER(&ipfi_mutex); /* sets interrupt priority level to splhi */
365255332Scy
366255332Scy	for (ifp = ifnet; ifp; ifp = ifp->if_next) {
367255332Scy		if ((!(ifp->if_flags & IFF_RUNNING)) ||
368255332Scy			(ifp->if_flags & IFF_LOOPBACK))
369255332Scy			continue;
370255332Scy
371255332Scy		/*
372255332Scy		 * Look for entry already setup for this device
373255332Scy		 */
374255332Scy		for (nif = nif_head; nif; nif = nif->nf_next)
375255332Scy			if (nif->nf_ifp == ifp)
376255332Scy				break;
377255332Scy		if (nif)
378255332Scy			continue;
379255332Scy
380255332Scy		if (ifp->if_output == ipl_if_output) {
381255332Scy			printf("IP Filter: ERROR INTF 0x%lx STILL ATTACHED\n",
382255332Scy				ifp);
383255332Scy			continue;
384255332Scy		}
385255332Scy#if (IPFDEBUG >= 2)
386255332Scy		printf("IP Filter: nifattach nif %x opt %x\n",
387255332Scy		       ifp, ifp->if_output);
388255332Scy#endif
389255332Scy		KMALLOC(nif, nif_t *);
390255332Scy		if (!nif) {
391255332Scy			printf("IP Filter: malloc(%d) for nif_t failed\n",
392255332Scy			       sizeof(nif_t));
393255332Scy			continue;
394255332Scy		}
395255332Scy
396255332Scy		nif->nf_ifp = ifp;
397255332Scy		(void) strncpy(nif->nf_name, ifp->if_name,
398255332Scy			       sizeof(nif->nf_name));
399255332Scy		nif->nf_name[sizeof(nif->nf_name) - 1] = '\0';
400255332Scy		nif->nf_unit = ifp->if_unit;
401255332Scy
402255332Scy		nif->nf_next = nif_head;
403255332Scy		nif_head = nif;
404255332Scy
405255332Scy		/*
406255332Scy		 * Activate any rules directly associated with this interface
407255332Scy		 */
408255332Scy		WRITE_ENTER(&ipf_mutex);
409255332Scy		for (f = ipf_rules[0][0]; f; f = f->fr_next) {
410255332Scy			if ((f->fr_ifa == (struct ifnet *)-1)) {
411255332Scy				if (f->fr_ifname[0] &&
412255332Scy				    (GETIFP(f->fr_ifname, 4) == ifp))
413255332Scy					f->fr_ifa = ifp;
414255332Scy			}
415255332Scy		}
416255332Scy		for (f = ipf_rules[1][0]; f; f = f->fr_next) {
417255332Scy			if ((f->fr_ifa == (struct ifnet *)-1)) {
418255332Scy				if (f->fr_ifname[0] &&
419255332Scy				    (GETIFP(f->fr_ifname, 4) == ifp))
420255332Scy					f->fr_ifa = ifp;
421255332Scy			}
422255332Scy		}
423255332Scy		RWLOCK_EXIT(&ipf_mutex);
424255332Scy		WRITE_ENTER(&ipf_nat);
425255332Scy		for (np = nat_list; np; np = np->in_next) {
426255332Scy			if ((np->in_ifps[0] == (void *)-1)) {
427255332Scy				if (np->in_ifnames[0][0] &&
428255332Scy				    (GETIFP(np->in_ifnames[0], 4) == ifp))
429255332Scy					np->in_ifps[0] = (void *)ifp;
430255332Scy			}
431255332Scy			if ((np->in_ifps[1] == (void *)-1)) {
432255332Scy				if (np->in_ifnames[1][0] &&
433255332Scy				    (GETIFP(np->in_ifnames[1], 4) == ifp))
434255332Scy					np->in_ifps[1] = (void *)ifp;
435255332Scy			}
436255332Scy		}
437255332Scy		RWLOCK_EXIT(&ipf_nat);
438255332Scy
439255332Scy		nif->nf_output = ifp->if_output;
440255332Scy		ifp->if_output = ipl_if_output;
441255332Scy
442255332Scy#if (IPFDEBUG >= 2)
443255332Scy		printf("IP Filter: nifattach: ifp(%lx)->if_output FROM %lx TO %lx\n",
444255332Scy			ifp, nif->nf_output, ifp->if_output);
445255332Scy#endif
446255332Scy
447255332Scy		printf("IP Filter: attach to [%s,%d]\n",
448255332Scy			nif->nf_name, ifp->if_unit);
449255332Scy	}
450255332Scy	if (!nif_head)
451255332Scy		printf("IP Filter: not attached to any interfaces\n");
452255332Scy
453255332Scy	nif_interfaces = in_interfaces;
454255332Scy
455255332Scy	MUTEX_EXIT(&ipfi_mutex);
456255332Scy
457255332Scy	return;
458255332Scy}
459255332Scy
460255332Scy
461255332Scy/*
462255332Scy * unhook the IP filter from all defined interfaces with IP addresses
463255332Scy */
464255332Scystatic void
465255332Scynifdetach()
466255332Scy{
467255332Scy	nif_t *nif, *qf2, **qp;
468255332Scy	struct ifnet *ifp;
469255332Scy
470255332Scy	MUTEX_ENTER(&ipfi_mutex); /* sets interrupt priority level to splhi */
471255332Scy	/*
472255332Scy	 * Make two passes, first get rid of all the unknown devices, next
473255332Scy	 * unlink known devices.
474255332Scy	 */
475255332Scy	for (qp = &nif_head; (nif = *qp); ) {
476255332Scy		for (ifp = ifnet; ifp; ifp = ifp->if_next)
477255332Scy			if (nif->nf_ifp == ifp)
478255332Scy				break;
479255332Scy		if (ifp) {
480255332Scy			qp = &nif->nf_next;
481255332Scy			continue;
482255332Scy		}
483255332Scy		printf("IP Filter: removing [%s]\n", nif->nf_name);
484255332Scy		*qp = nif->nf_next;
485255332Scy		KFREE(nif);
486255332Scy	}
487255332Scy
488255332Scy	while ((nif = nif_head)) {
489255332Scy		nif_head = nif->nf_next;
490255332Scy		for (ifp = ifnet; ifp; ifp = ifp->if_next)
491255332Scy			if (nif->nf_ifp == ifp)
492255332Scy				break;
493255332Scy		if (ifp) {
494255332Scy			printf("IP Filter: detaching [%s,%d]\n",
495255332Scy				nif->nf_name, ifp->if_unit);
496255332Scy
497255332Scy#if (IPFDEBUG >= 4)
498255332Scy			printf("IP Filter: nifdetach: ifp(%lx)->if_output FROM %lx TO %lx\n",
499255332Scy				ifp, ifp->if_output, nif->nf_output);
500255332Scy#endif
501255332Scy			ifp->if_output = nif->nf_output;
502255332Scy		}
503255332Scy		KFREE(nif);
504255332Scy	}
505255332Scy	MUTEX_EXIT(&ipfi_mutex);
506255332Scy
507255332Scy	return;
508255332Scy}
509255332Scy
510255332Scy
511255332Scyvoid
512255332Scyipl_ipfilter_detach(void)
513255332Scy{
514255332Scy#ifdef IPFILTER_LKM
515255332Scy	nifdetach();
516255332Scy	MUTEX_ENTER(&ipfi_mutex); /* sets interrupt priority level to splhi */
517255332Scy
518255332Scy	if (ipff_addr) {
519255332Scy		*ipff_addr = 0;
520255332Scy
521255332Scy		if (ipfk_addr) {
522255332Scy			bcopy(ipfk_code, ipfk_addr, sizeof(ipfk_code));
523255332Scy			icache_inval(ipfk_addr - 16, sizeof(ipfk_code)+32);
524255332Scy		}
525255332Scy
526255332Scy		*ipff_addr = ipff_value;
527255332Scy	}
528255332Scy
529255332Scy	MUTEX_EXIT(&ipfi_mutex);
530255332Scy#else
531255332Scy	extern int ipfilterflag;
532255332Scy
533255332Scy	nifdetach();
534255332Scy
535255332Scy	ipfilterflag = 0;
536255332Scy#endif
537255332Scy}
538255332Scy
539255332Scy
540255332Scy/* this function is called from ipf_slowtimer at 500ms intervals to
541255332Scy   keep our interface list in sync */
542255332Scyvoid
543255332Scyipl_ipfilter_intfsync(void)
544255332Scy{
545255332Scy	MUTEX_ENTER(&ipfi_mutex);
546255332Scy	if (nif_interfaces != in_interfaces) {
547255332Scy		/* if the number of interfaces has changed, resync */
548255332Scy		MUTEX_EXIT(&ipfi_mutex);
549255332Scy		ipf_sync(&ipfmain, NULL);
550255332Scy	} else
551255332Scy		MUTEX_EXIT(&ipfi_mutex);
552255332Scy}
553255332Scy
554255332Scy#ifdef IPFILTER_LKM
555255332Scy/* this routine should be treated as an interrupt routine and should
556255332Scy   not call any routines that would cause it to sleep, such as: biowait(),
557255332Scy   sleep(), psema() or delay().
558255332Scy*/
559255332Scyint
560255332Scyiplunload(void)
561255332Scy{
562255332Scy	int error = 0;
563255332Scy
564255332Scy	if (ipf_refcnt)
565255332Scy		return EBUSY;
566255332Scy
567255332Scy	WRITE_ENTER(&ipf_global);
568255332Scy	error = ipl_detach();
569255332Scy	if (error != 0) {
570255332Scy		RWLOCK_EXIT(&ipf_global);
571255332Scy		return error;
572255332Scy	}
573255332Scy	ipf_running = -2;
574255332Scy
575255332Scy#if (IRIX < 60500)
576255332Scy	LOCK_DEALLOC(ipl_mutex.l);
577255332Scy	LOCK_DEALLOC(ipf_rw.l);
578255332Scy	LOCK_DEALLOC(ipf_auth.l);
579255332Scy	LOCK_DEALLOC(ipf_natfrag.l);
580255332Scy	LOCK_DEALLOC(ipf_ipidfrag.l);
581255332Scy	LOCK_DEALLOC(ipf_tokens.l);
582255332Scy	LOCK_DEALLOC(ipf_stinsert.l);
583255332Scy	LOCK_DEALLOC(ipf_nat_new.l);
584255332Scy	LOCK_DEALLOC(ipf_natio.l);
585255332Scy	LOCK_DEALLOC(ipf_nat.l);
586255332Scy	LOCK_DEALLOC(ipf_state.l);
587255332Scy	LOCK_DEALLOC(ipf_frag.l);
588255332Scy	LOCK_DEALLOC(ipf_auth_mx.l);
589255332Scy	LOCK_DEALLOC(ipf_mutex.l);
590255332Scy	LOCK_DEALLOC(ipf_frcache.l);
591255332Scy	LOCK_DEALLOC(ipfi_mutex.l);
592255332Scy	RWLOCK_EXIT(&ipf_global);
593255332Scy	LOCK_DEALLOC(ipf_global.l);
594255332Scy#else
595255332Scy	MUTEX_DESTROY(&ipf_rw);
596255332Scy	MUTEX_DESTROY(&ipfi_mutex);
597255332Scy	MUTEX_DESTROY(&ipf_timeoutlock);
598255332Scy	RW_DESTROY(&ipf_mutex);
599255332Scy	RW_DESTROY(&ipf_frcache);
600255332Scy	RW_DESTROY(&ipf_tokens);
601255332Scy	RWLOCK_EXIT(&ipf_global);
602255332Scy	delay(hz);
603255332Scy	RW_DESTROY(&ipf_global);
604255332Scy#endif
605255332Scy
606255332Scy	printf("%s unloaded\n", ipfilter_version);
607255332Scy
608255332Scy	delay(hz);
609255332Scy
610255332Scy	return 0;
611255332Scy}
612255332Scy#endif
613255332Scy
614255332Scyvoid
615255332Scyipfilterinit(void)
616255332Scy{
617255332Scy#ifdef IPFILTER_LKM
618255332Scy	int error;
619255332Scy#endif
620255332Scy
621255332Scy#if (IRIX < 60500)
622255332Scy	ipfi_mutex.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
623255332Scyipf_mutex.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
624255332Scyipf_frcache.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
625255332Scyipf_timeoutlock.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
626255332Scy	ipf_global.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
627255332Scy	ipf_frag.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
628255332Scy	ipf_state.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
629255332Scy	ipf_nat.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
630255332Scy	ipf_stinsert.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
631255332Scy	ipf_natfrag.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
632255332Scy	ipf_ipidfrag.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
633255332Scy	ipf_tokens.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
634255332Scy	ipf_auth.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
635255332Scy	ipf_rw.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
636255332Scy	ipl_mutex.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP);
637255332Scy
638255332Scy	if (!ipfi_mutex.l || !ipf_mutex.l || !ipf_timeoutlock.l ||
639255332Scy	    !ipf_frag.l || !ipf_state.l || !ipf_nat.l || !ipf_natfrag.l ||
640255332Scy	    !ipf_auth.l || !ipf_rw.l || !ipf_ipidfrag.l || !ipl_mutex.l ||
641255332Scy	    !ipf_stinsert.l || !ipf_auth_mx.l || !ipf_frcache.l ||
642255332Scy	    !ipf_tokens.l)
643255332Scy		panic("IP Filter: LOCK_ALLOC failed");
644255332Scy#else
645255332Scy	MUTEX_INIT(&ipf_rw, "ipf rw mutex");
646255332Scy	MUTEX_INIT(&ipf_timeoutlock, "ipf timeout mutex");
647255332Scy	RWLOCK_INIT(&ipf_global, "ipf filter load/unload mutex");
648255332Scy	RWLOCK_INIT(&ipf_mutex, "ipf filter rwlock");
649255332Scy	RWLOCK_INIT(&ipf_frcache, "ipf cache rwlock");
650255332Scy#endif
651255332Scy
652255332Scy#ifdef IPFILTER_LKM
653255332Scy	error = ipl_attach();
654255332Scy	if (error) {
655255332Scy		iplunload();
656255332Scy	} else {
657255332Scy		char *defpass;
658255332Scy
659255332Scy		if (FR_ISPASS(ipf_pass))
660255332Scy			defpass = "pass";
661255332Scy		else if (FR_ISBLOCK(ipf_pass))
662255332Scy			defpass = "block";
663255332Scy		else
664255332Scy			defpass = "no-match -> block";
665255332Scy
666255332Scy		printf("%s initialized.  Default = %s all, Logging = %s%s\n",
667255332Scy			ipfilter_version, defpass,
668255332Scy# ifdef  IPFILTER_LOG
669255332Scy			"enabled",
670255332Scy# else
671255332Scy			"disabled",
672255332Scy# endif
673255332Scy# ifdef IPFILTER_COMPILED
674255332Scy		" (COMPILED)"
675255332Scy# else
676255332Scy		""
677255332Scy# endif
678255332Scy		);
679255332Scy	}
680255332Scy#endif
681255332Scy
682255332Scy	return;
683255332Scy}
684