2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (C) 1997 by Darren Reed & Guido van Rooij.
25 * Redistribution and use in source and binary forms are permitted
26 * provided that this notice is preserved and due credit is given
27 * to the original author and the contributors.
30 #define __FreeBSD_version 300000 /* just a hack - no <sys/osreldate.h> */
36 #include <sys/errno.h>
37 #include <sys/types.h>
38 #include <sys/param.h>
41 #if defined(KERNEL) && (__FreeBSD_version >= 220000)
42 # include <sys/filio.h>
43 # include <sys/fcntl.h>
45 # include <sys/ioctl.h>
49 # include <sys/protosw.h>
51 #include <sys/socket.h>
53 # include <sys/systm.h>
55 #if !defined(__SVR4) && !defined(__svr4__)
57 # include <sys/mbuf.h>
60 # include <sys/filio.h>
61 # include <sys/byteorder.h>
62 # include <sys/dditypes.h>
63 # include <sys/stream.h>
64 # include <sys/kmem.h>
66 #if defined(KERNEL) && (__FreeBSD_version >= 300000)
67 # include <sys/malloc.h>
69 #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi)
70 # include <kern/cpu_number.h>
76 #if !defined(KERNEL) && (__FreeBSD_version >= 300000)
77 # include <net/if_var.h>
79 #include <net/route.h>
80 #include <netinet/in.h>
81 #include <netinet/in_systm.h>
82 #include <netinet/ip.h>
88 # include <netinet/ip_var.h>
94 # ifdef IFF_DRVRLOCK /* IRIX6 */
95 #include <sys/hashing.h>
98 #include <netinet/tcp.h>
99 #if defined(__sgi) && !defined(IFF_DRVRLOCK) /* IRIX < 6 */
100 extern struct ifqueue ipintrq
; /* ip packet input queue */
103 # include <netinet/in_var.h>
104 # include <netinet/tcp_fsm.h>
107 #include <netinet/udp.h>
108 #include <netinet/ip_icmp.h>
109 #include "netinet/ip_compat.h"
110 #include <netinet/tcpip.h>
111 #include "netinet/ip_fil.h"
112 #include "netinet/ip_auth.h"
113 #if !SOLARIS && !defined(linux)
114 # include <net/netisr.h>
116 # include <machine/cpufunc.h>
121 #if (SOLARIS || defined(__sgi)) && defined(_KERNEL)
122 extern kmutex_t ipf_auth
;
124 extern kcondvar_t ipfauthwait
;
128 static struct wait_queue
*ipfauthwait
= NULL
;
131 int fr_authsize
= FR_NUMAUTH
;
133 int fr_defaultauthage
= 600;
134 fr_authstat_t fr_authstats
;
135 static frauth_t fr_auth
[FR_NUMAUTH
];
136 mb_t
*fr_authpkts
[FR_NUMAUTH
];
137 static int fr_authstart
= 0, fr_authend
= 0, fr_authnext
= 0;
138 static frauthent_t
*fae_list
= NULL
;
139 frentry_t
*ipauth
= NULL
;
143 * Check if a packet has authorization. If the packet is found to match an
144 * authorization result and that would result in a feedback loop (i.e. it
145 * will end up returning FR_AUTH) then return FR_BLOCK instead.
147 int fr_checkauth(ip
, fin
)
151 u_short id
= ip
->ip_id
;
155 MUTEX_ENTER(&ipf_auth
);
156 for (i
= fr_authstart
; i
!= fr_authend
; ) {
158 * index becomes -2 only after an SIOCAUTHW. Check this in
159 * case the same packet gets sent again and it hasn't yet been
162 if ((fr_auth
[i
].fra_index
== -2) &&
163 (id
== fr_auth
[i
].fra_info
.fin_id
) &&
164 !bcmp((char *)fin
,(char *)&fr_auth
[i
].fra_info
,FI_CSIZE
)) {
166 * Avoid feedback loop.
168 if (!(pass
= fr_auth
[i
].fra_pass
) || (pass
& FR_AUTH
))
170 fr_authstats
.fas_hits
++;
171 fr_auth
[i
].fra_index
= -1;
173 if (i
== fr_authstart
) {
174 while (fr_auth
[i
].fra_index
== -1) {
182 if (fr_authstart
== fr_authend
) {
184 fr_authstart
= fr_authend
= 0;
187 MUTEX_EXIT(&ipf_auth
);
194 fr_authstats
.fas_miss
++;
195 MUTEX_EXIT(&ipf_auth
);
201 * Check if we have room in the auth array to hold details for another packet.
202 * If we do, store it and wake up any user programs which are waiting to
203 * hear about these events.
205 int fr_newauth(m
, fin
, ip
206 #if defined(_KERNEL) && SOLARIS
218 MUTEX_ENTER(&ipf_auth
);
219 if ((fr_authstart
> fr_authend
) && (fr_authstart
- fr_authend
== -1)) {
220 fr_authstats
.fas_nospace
++;
221 MUTEX_EXIT(&ipf_auth
);
224 if (fr_authend
- fr_authstart
== FR_NUMAUTH
- 1) {
225 fr_authstats
.fas_nospace
++;
226 MUTEX_EXIT(&ipf_auth
);
230 fr_authstats
.fas_added
++;
233 if (fr_authend
== FR_NUMAUTH
)
235 MUTEX_EXIT(&ipf_auth
);
236 fr_auth
[i
].fra_index
= i
;
237 fr_auth
[i
].fra_pass
= 0;
238 fr_auth
[i
].fra_age
= fr_defaultauthage
;
239 bcopy((char *)fin
, (char *)&fr_auth
[i
].fra_info
, sizeof(*fin
));
240 #if !defined(sparc) && !defined(m68k)
242 * No need to copyback here as we want to undo the changes, not keep
245 # if SOLARIS && defined(KERNEL)
246 if (ip
== (ip_t
*)m
->b_rptr
)
252 ip
->ip_len
= htons(bo
);
253 # if !SOLARIS /* 4.4BSD converts this ip_input.c, but I don't in solaris.c */
255 ip
->ip_id
= htons(bo
);
258 ip
->ip_off
= htons(bo
);
261 #if SOLARIS && defined(KERNEL)
262 m
->b_rptr
-= qif
->qf_off
;
263 fr_authpkts
[i
] = *(mblk_t
**)fin
->fin_mp
;
264 fr_auth
[i
].fra_q
= qif
->qf_q
;
265 cv_signal(&ipfauthwait
);
268 # if defined(linux) && defined(KERNEL)
269 wake_up_interruptible(&ipfauthwait
);
271 WAKEUP(&fr_authnext
);
278 int fr_auth_ioctl(data
, cmd
, fr
, frptr
)
280 #if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003)
285 frentry_t
*fr
, **frptr
;
294 frauth_t auth
, *au
= &auth
;
295 frauthent_t
*fae
, **faep
;
308 for (faep
= &fae_list
; (fae
= *faep
); )
309 if (&fae
->fae_fr
== fr
)
312 faep
= &fae
->fae_next
;
313 if (cmd
== SIOCRMAFR
) {
317 *faep
= fae
->fae_next
;
318 *frptr
= fr
->fr_next
;
322 KMALLOC(fae
, frauthent_t
*, sizeof(*fae
));
324 IRCOPY((char *)data
, (char *)&fae
->fae_fr
,
325 sizeof(fae
->fae_fr
));
327 fae
->fae_age
= fr_defaultauthage
;
328 fae
->fae_fr
.fr_hits
= 0;
329 fae
->fae_fr
.fr_next
= *frptr
;
330 *frptr
= &fae
->fae_fr
;
331 fae
->fae_next
= *faep
;
338 IWCOPY((char *)&fr_authstats
, data
, sizeof(fr_authstats
));
342 MUTEX_ENTER(&ipf_auth
);
343 if ((fr_authnext
!= fr_authend
) && fr_authpkts
[fr_authnext
]) {
344 IWCOPY((char *)&fr_auth
[fr_authnext
++], data
,
346 if (fr_authnext
== FR_NUMAUTH
)
348 MUTEX_EXIT(&ipf_auth
);
353 if (!cv_wait_sig(&ipfauthwait
, &ipf_auth
)) {
354 mutex_exit(&ipf_auth
);
359 interruptible_sleep_on(&ipfauthwait
);
360 if (current
->signal
& ~current
->blocked
)
363 error
= SLEEP(&fr_authnext
, "fr_authnext");
367 MUTEX_EXIT(&ipf_auth
);
369 goto fr_authioctlloop
;
372 IRCOPY(data
, (caddr_t
)&auth
, sizeof(auth
));
373 MUTEX_ENTER(&ipf_auth
);
375 if ((i
< 0) || (i
> FR_NUMAUTH
) ||
376 (fr_auth
[i
].fra_info
.fin_id
!= au
->fra_info
.fin_id
)) {
377 MUTEX_EXIT(&ipf_auth
);
381 fr_auth
[i
].fra_index
= -2;
382 fr_auth
[i
].fra_pass
= au
->fra_pass
;
383 fr_authpkts
[i
] = NULL
;
385 MUTEX_EXIT(&ipf_auth
);
388 if (m
&& au
->fra_info
.fin_out
) {
390 error
= fr_qout(fr_auth
[i
].fra_q
, m
);
393 m
->m_pkthdr
.rcvif
= NULL
;
396 error
= ip_output(m
, NULL
, NULL
, IP_FORWARDING
, NULL
);
397 # endif /* SOLARIS */
399 fr_authstats
.fas_sendfail
++;
401 fr_authstats
.fas_sendok
++;
404 error
= fr_qin(fr_auth
[i
].fra_q
, m
);
413 schednetisr(NETISR_IP
);
415 # endif /* SOLARIS */
417 fr_authstats
.fas_quefail
++;
419 fr_authstats
.fas_queok
++;
428 * If we experience an error which will result in the packet
429 * not being processed, make sure we advance to the next one.
431 if (error
== ENOBUFS
) {
433 fr_auth
[i
].fra_index
= -1;
434 fr_auth
[i
].fra_pass
= 0;
435 if (i
== fr_authstart
) {
436 while (fr_auth
[i
].fra_index
== -1) {
444 if (fr_authstart
== fr_authend
) {
446 fr_authstart
= fr_authend
= 0;
464 * Free all network buffer memory used to keep saved packets.
469 register frauthent_t
*fae
, **faep
;
472 MUTEX_ENTER(&ipf_auth
);
473 for (i
= 0; i
< FR_NUMAUTH
; i
++) {
474 if ((m
= fr_authpkts
[i
])) {
476 fr_authpkts
[i
] = NULL
;
477 fr_auth
[i
].fra_index
= -1;
482 for (faep
= &fae_list
; (fae
= *faep
); ) {
483 *faep
= fae
->fae_next
;
486 MUTEX_EXIT(&ipf_auth
);
491 * Slowly expire held auth records. Timeouts are set
492 * in expectation of this being called twice per second.
497 register frauth_t
*fra
;
498 register frauthent_t
*fae
, **faep
;
505 MUTEX_ENTER(&ipf_auth
);
506 for (i
= 0, fra
= fr_auth
; i
< FR_NUMAUTH
; i
++, fra
++) {
507 if ((!--fra
->fra_age
) && (m
= fr_authpkts
[i
])) {
509 fr_authpkts
[i
] = NULL
;
510 fr_auth
[i
].fra_index
= -1;
511 fr_authstats
.fas_expire
++;
516 for (faep
= &fae_list
; (fae
= *faep
); ) {
517 if (!--fra
->fra_age
) {
518 *faep
= fae
->fae_next
;
520 fr_authstats
.fas_expire
++;
522 faep
= &fae
->fae_next
;
524 MUTEX_EXIT(&ipf_auth
);