2 * Copyright (C) 1993-2001 by Darren Reed.
3 * (C)opyright 1997 by Marc Boucher.
5 * See the IPFILTER.LICENCE file for details on licencing.
9 - ipl_init failure -> open ENODEV or whatever
10 - prevent multiple LKM loads
11 - surround access to ifnet structures by IFNET_LOCK()/IFNET_UNLOCK() ?
15 #include <sys/types.h>
18 #include <sys/mload.h>
20 #include <sys/systm.h>
21 #include <sys/errno.h>
23 #include <net/route.h>
24 #include <netinet/in.h>
25 #ifdef IFF_DRVRLOCK /* IRIX6 */
26 #include <sys/hashing.h>
27 #include <netinet/in_var.h>
30 #include <netinet/in_systm.h>
31 #include <netinet/ip.h>
32 #include <netinet/ip_var.h>
33 #include <netinet/tcp.h>
34 #include <netinet/udp.h>
35 #include <netinet/tcpip.h>
36 #include <netinet/ip_icmp.h>
37 #include <netinet/ipfilter.h>
39 #include "ip_compat.h"
43 /*#define IPFDEBUG 1*/
45 unsigned IPL_EXTERN(devflag
) = D_MP
;
47 char *IPL_EXTERN(mversion
) = M_VERSION
;
50 kmutex_t ipl_mutex
, ipf_mutex
, ipfi_mutex
, ipf_rw
;
51 kmutex_t ipf_frag
, ipf_state
, ipf_nat
, ipf_natfrag
, ipf_auth
;
53 int (*fr_checkp
) __P((struct ip
*, int, void *, int, mb_t
**));
56 static int *ipff_addr
= 0;
57 static int ipff_value
;
58 static __psunsigned_t
*ipfk_addr
= 0;
59 static __psunsigned_t ipfk_code
[4];
66 int (*nf_output
)(struct ifnet
*, struct mbuf
*, struct sockaddr
*);
68 int (*nf_output
)(struct ifnet
*, struct mbuf
*, struct sockaddr
*,
71 char nf_name
[IFNAMSIZ
];
75 static nif_t
*nif_head
= 0;
76 static int nif_interfaces
= 0;
77 extern int in_interfaces
;
79 extern ipnat_t
*nat_list
;
83 ipl_if_output(struct ifnet
*ifp
, struct mbuf
*m
, struct sockaddr
*dst
)
85 ipl_if_output(struct ifnet
*ifp
, struct mbuf
*m
, struct sockaddr
*dst
,
91 MUTEX_ENTER(&ipfi_mutex
); /* sets interrupt priority level to splhi */
92 for (nif
= nif_head
; nif
; nif
= nif
->nf_next
)
93 if (nif
->nf_ifp
== ifp
)
96 MUTEX_EXIT(&ipfi_mutex
);
98 printf("IP Filter: ipl_if_output intf %x NOT FOUND\n", ifp
);
103 static unsigned int cnt
= 0;
104 if ((++cnt
% 200) == 0)
105 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
, (unsigned long)(m
->m_flags
), m
->m_off
);
114 if (m
->m_flags
& M_BCAST
) {
116 printf("IP Filter: ipl_if_output: passing M_BCAST\n");
123 if (!MBUF_IS_CLUSTER(m
) && ((m
->m_off
< MMINOFF
) || (m
->m_off
> MMAXOFF
))) {
124 printf("IP Filter: ipl_if_output: bad m_off m_type=%d m_flags=0x%lx m_off=0x%lx\n", m
->m_type
, (unsigned long)(m
->m_flags
), m
->m_off
);
128 if (m
->m_len
< sizeof(char)) {
129 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
, (unsigned long)(m
->m_flags
));
132 ip
= mtod(m
, struct ip
*);
133 if (ip
->ip_v
!= IPVERSION
) {
135 printf("IP Filter: ipl_if_output: bad ip_v m_type=%d m_flags=0x%lx m_off=0x%lx\n", m
->m_type
, (unsigned long)(m
->m_flags
), m
->m_off
);
140 hlen
= ip
->ip_hl
<< 2;
141 if ((*fr_checkp
)(ip
, hlen
, ifp
, 1, &m1
))
151 printf("IP Filter: ipl_if_output: bad m_type=%d m_flags=0x%lxm_off=0x%lx\n", m
->m_type
, (unsigned long)(m
->m_flags
), m
->m_off
);
157 return (*nif
->nf_output
)(ifp
, m
, dst
);
159 return (*nif
->nf_output
)(ifp
, m
, dst
, rt
);
164 IPL_EXTERN(_kernel
)(struct ifnet
*rcvif
, struct mbuf
*m
)
167 static unsigned int cnt
= 0;
168 if ((++cnt
% 200) == 0)
169 printf("IP Filter: ipl_ipfilter_kernel(rcvif=0x%lx, m=0x%lx\n", rcvif
, m
);
173 * Check if we want to allow this packet to be processed.
174 * Consider it to be bad if not.
181 if ((m
->m_type
!= MT_DATA
) && (m
->m_type
!= MT_HEADER
)) {
182 printf("IP Filter: ipl_ipfilter_kernel: bad m_type=%d m_flags=0x%lx m_off=0x%lx\n", m
->m_type
, (unsigned long)(m
->m_flags
), m
->m_off
);
187 if (!MBUF_IS_CLUSTER(m
) && ((m
->m_off
< MMINOFF
) || (m
->m_off
> MMAXOFF
))) {
188 printf("IP Filter: ipl_ipfilter_kernel: bad m_off m_type=%d m_flags=0x%lx m_off=0x%lx\n", m
->m_type
, (unsigned long)(m
->m_flags
), m
->m_off
);
192 if (m
->m_len
< sizeof(char)) {
193 printf("IP Filter: ipl_ipfilter_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
, (unsigned long)(m
->m_flags
));
196 ip
= mtod(m
, struct ip
*);
197 if (ip
->ip_v
!= IPVERSION
) {
198 printf("IP Filter: ipl_ipfilter_kernel: bad ip_v\n");
203 hlen
= ip
->ip_hl
<< 2;
204 if ((*fr_checkp
)(ip
, hlen
, rcvif
, 0, &m1
) || !m1
)
207 printf("IP Filter: ipl_ipfilter_kernel: m != m1\n");
217 __psunsigned_t
*addr_ff
, *addr_fk
;
219 st_findaddr("ipfilterflag", &addr_ff
);
221 printf("IP Filter: st_findaddr ipfilterflag=0x%lx\n", addr_ff
);
226 st_findaddr("ipfilter_kernel", &addr_fk
);
228 printf("IP Filter: st_findaddr ipfilter_kernel=0x%lx\n", addr_fk
);
233 MUTEX_ENTER(&ipfi_mutex
); /* sets interrupt priority level to splhi */
235 ipff_addr
= (int *)addr_ff
;
237 ipff_value
= *ipff_addr
;
243 bcopy(ipfk_addr
, ipfk_code
,
246 /* write a "li t4, ipl_ipfilter_kernel" instruction */
247 ipfk_addr
[0] = 0x3c0c0000 |
248 (((__psunsigned_t
)IPL_EXTERN(_kernel
) >> 16) & 0xffff);
249 ipfk_addr
[1] = 0x358c0000 |
250 ((__psunsigned_t
)IPL_EXTERN(_kernel
) & 0xffff);
251 /* write a "jr t4" instruction" */
252 ipfk_addr
[2] = 0x01800008;
254 /* write a "nop" instruction */
257 icache_inval(ipfk_addr
, sizeof(ipfk_code
));
259 *ipff_addr
= 1; /* enable ipfilter_kernel */
261 MUTEX_EXIT(&ipfi_mutex
);
263 extern int ipfilterflag
;
272 * attach the packet filter to each non-loopback interface that is running
282 MUTEX_ENTER(&ipfi_mutex
); /* sets interrupt priority level to splhi */
284 for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
) {
285 if ((!(ifp
->if_flags
& IFF_RUNNING
)) ||
286 (ifp
->if_flags
& IFF_LOOPBACK
))
290 * Look for entry already setup for this device
292 for (nif
= nif_head
; nif
; nif
= nif
->nf_next
)
293 if (nif
->nf_ifp
== ifp
)
298 if (ifp
->if_output
== ipl_if_output
) {
299 printf("IP Filter: ERROR INTF 0x%lx STILL ATTACHED\n",
304 printf("IP Filter: nifattach nif %x opt %x\n",
305 ifp
, ifp
->if_output
);
307 KMALLOC(nif
, nif_t
*);
309 printf("IP Filter: malloc(%d) for nif_t failed\n",
315 strncpy(nif
->nf_name
, ifp
->if_name
, sizeof(nif
->nf_name
));
316 nif
->nf_name
[sizeof(nif
->nf_name
) - 1] = '\0';
317 nif
->nf_unit
= ifp
->if_unit
;
319 nif
->nf_next
= nif_head
;
323 * Activate any rules directly associated with this interface
325 MUTEX_ENTER(&ipf_mutex
);
326 for (f
= ipfilter
[0][0]; f
; f
= f
->fr_next
) {
327 if ((f
->fr_ifa
== (struct ifnet
*)-1)) {
328 if (f
->fr_ifname
[0] &&
329 (GETUNIT(f
->fr_ifname
, 4) == ifp
))
333 for (f
= ipfilter
[1][0]; f
; f
= f
->fr_next
) {
334 if ((f
->fr_ifa
== (struct ifnet
*)-1)) {
335 if (f
->fr_ifname
[0] &&
336 (GETUNIT(f
->fr_ifname
, 4) == ifp
))
340 MUTEX_EXIT(&ipf_mutex
);
341 MUTEX_ENTER(&ipf_nat
);
342 for (np
= nat_list
; np
; np
= np
->in_next
) {
343 if ((np
->in_ifp
== (void *)-1)) {
344 if (np
->in_ifname
[0] &&
345 (GETUNIT(np
->in_ifname
, 4) == ifp
))
346 np
->in_ifp
= (void *)ifp
;
349 MUTEX_EXIT(&ipf_nat
);
351 nif
->nf_output
= ifp
->if_output
;
352 ifp
->if_output
= ipl_if_output
;
355 printf("IP Filter: nifattach: ifp(%lx)->if_output FROM %lx TO %lx\n",
356 ifp
, nif
->nf_output
, ifp
->if_output
);
359 printf("IP Filter: attach to [%s,%d]\n",
360 nif
->nf_name
, ifp
->if_unit
);
363 printf("IP Filter: not attached to any interfaces\n");
365 nif_interfaces
= in_interfaces
;
367 MUTEX_EXIT(&ipfi_mutex
);
373 * look for bad consistancies between the list of interfaces the filter knows
374 * about and those which are currently configured.
379 register struct frentry
*f
;
380 register ipnat_t
*np
;
381 register nif_t
*nif
, **qp
;
382 register struct ifnet
*ifp
;
384 MUTEX_ENTER(&ipfi_mutex
); /* sets interrupt priority level to splhi */
385 for (qp
= &nif_head
; (nif
= *qp
); ) {
386 for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
)
387 if ((nif
->nf_ifp
== ifp
) &&
388 (nif
->nf_unit
== ifp
->if_unit
) &&
389 !strcmp(nif
->nf_name
, ifp
->if_name
)) {
396 printf("IP Filter: detaching [%s]\n", nif
->nf_name
);
400 * Disable any rules directly associated with this interface
402 MUTEX_ENTER(&ipf_mutex
);
403 for (f
= ipfilter
[0][0]; f
; f
= f
->fr_next
)
404 if (f
->fr_ifa
== (void *)nif
->nf_ifp
)
405 f
->fr_ifa
= (struct ifnet
*)-1;
406 for (f
= ipfilter
[1][0]; f
; f
= f
->fr_next
)
407 if (f
->fr_ifa
== (void *)nif
->nf_ifp
)
408 f
->fr_ifa
= (struct ifnet
*)-1;
409 MUTEX_EXIT(&ipf_mutex
);
410 MUTEX_ENTER(&ipf_nat
);
411 for (np
= nat_list
; np
; np
= np
->in_next
)
412 if (np
->in_ifp
== (void *)nif
->nf_ifp
)
413 np
->in_ifp
=(struct ifnet
*)-1;
414 MUTEX_EXIT(&ipf_nat
);
419 MUTEX_EXIT(&ipfi_mutex
);
428 * unhook the IP filter from all defined interfaces with IP addresses
436 MUTEX_ENTER(&ipfi_mutex
); /* sets interrupt priority level to splhi */
438 * Make two passes, first get rid of all the unknown devices, next
439 * unlink known devices.
441 for (qp
= &nif_head
; (nif
= *qp
); ) {
442 for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
)
443 if (nif
->nf_ifp
== ifp
)
449 printf("IP Filter: removing [%s]\n", nif
->nf_name
);
454 while ((nif
= nif_head
)) {
455 nif_head
= nif
->nf_next
;
456 for (ifp
= ifnet
; ifp
; ifp
= ifp
->if_next
)
457 if (nif
->nf_ifp
== ifp
)
460 printf("IP Filter: detaching [%s,%d]\n",
461 nif
->nf_name
, ifp
->if_unit
);
464 printf("IP Filter: nifdetach: ifp(%lx)->if_output FROM %lx TO %lx\n",
465 ifp
, ifp
->if_output
, nif
->nf_output
);
467 ifp
->if_output
= nif
->nf_output
;
471 MUTEX_EXIT(&ipfi_mutex
);
481 MUTEX_ENTER(&ipfi_mutex
); /* sets interrupt priority level to splhi */
487 bcopy(ipfk_code
, ipfk_addr
, sizeof(ipfk_code
));
489 *ipff_addr
= ipff_value
;
492 MUTEX_EXIT(&ipfi_mutex
);
494 extern int ipfilterflag
;
500 /* called by ipldetach() */
502 ipfilter_sgi_detach(void)
509 /* called by iplattach() */
511 ipfilter_sgi_attach(void)
517 error
= ipfilterattach();
525 /* this function is called from ipfr_slowtimer at 500ms intervals to
526 keep our interface list in sync */
528 ipfilter_sgi_intfsync(void)
530 MUTEX_ENTER(&ipfi_mutex
);
531 if (nif_interfaces
!= in_interfaces
) {
532 /* if the number of interfaces has changed, resync */
533 MUTEX_EXIT(&ipfi_mutex
);
536 MUTEX_EXIT(&ipfi_mutex
);
540 /* this routine should be treated as an interrupt routine and should
541 not call any routines that would cause it to sleep, such as: biowait(),
542 sleep(), psema() or delay().
545 IPL_EXTERN(unload
)(void)
551 LOCK_DEALLOC(ipl_mutex
.l
);
552 LOCK_DEALLOC(ipf_rw
.l
);
553 LOCK_DEALLOC(ipf_auth
.l
);
554 LOCK_DEALLOC(ipf_natfrag
.l
);
555 LOCK_DEALLOC(ipf_nat
.l
);
556 LOCK_DEALLOC(ipf_state
.l
);
557 LOCK_DEALLOC(ipf_frag
.l
);
558 LOCK_DEALLOC(ipf_mutex
.l
);
559 LOCK_DEALLOC(ipfi_mutex
.l
);
566 IPL_EXTERN(init
)(void)
572 ipfi_mutex
.l
= LOCK_ALLOC((uchar_t
)-1, IPF_LOCK_PL
, (lkinfo_t
*)-1, KM_NOSLEEP
);
573 ipf_mutex
.l
= LOCK_ALLOC((uchar_t
)-1, IPF_LOCK_PL
, (lkinfo_t
*)-1, KM_NOSLEEP
);
574 ipf_frag
.l
= LOCK_ALLOC((uchar_t
)-1, IPF_LOCK_PL
, (lkinfo_t
*)-1, KM_NOSLEEP
);
575 ipf_state
.l
= LOCK_ALLOC((uchar_t
)-1, IPF_LOCK_PL
, (lkinfo_t
*)-1, KM_NOSLEEP
);
576 ipf_nat
.l
= LOCK_ALLOC((uchar_t
)-1, IPF_LOCK_PL
, (lkinfo_t
*)-1, KM_NOSLEEP
);
577 ipf_natfrag
.l
= LOCK_ALLOC((uchar_t
)-1, IPF_LOCK_PL
, (lkinfo_t
*)-1, KM_NOSLEEP
);
578 ipf_auth
.l
= LOCK_ALLOC((uchar_t
)-1, IPF_LOCK_PL
, (lkinfo_t
*)-1, KM_NOSLEEP
);
579 ipf_rw
.l
= LOCK_ALLOC((uchar_t
)-1, IPF_LOCK_PL
, (lkinfo_t
*)-1, KM_NOSLEEP
);
580 ipl_mutex
.l
= LOCK_ALLOC((uchar_t
)-1, IPF_LOCK_PL
, (lkinfo_t
*)-1, KM_NOSLEEP
);
582 if (!ipfi_mutex
.l
|| !ipf_mutex
.l
|| !ipf_frag
.l
|| !ipf_state
.l
||
583 !ipf_nat
.l
|| !ipf_natfrag
.l
|| !ipf_auth
.l
|| !ipf_rw
.l
||
585 panic("IP Filter: LOCK_ALLOC failed");
590 IPL_EXTERN(unload
)();