diff -E -b -x '*o' -x '*.cmd' -x '*.mod*c' -urN include/asm/socket.h /usr/src/linux/include/asm/socket.h --- include/asm/socket.h 2005-10-09 23:21:40.000000000 +0200 +++ /usr/src/linux/include/asm/socket.h 2005-10-11 18:31:51.000000000 +0200 @@ -53,4 +53,6 @@ #define SO_PEERSEC 31 +#define SO_ACCEPTFILTER 32 + #endif /* _ASM_SOCKET_H */ diff -E -b -x '*o' -x '*.cmd' -x '*.mod*c' -urN include/net/accf.h /usr/src/linux/include/net/accf.h --- include/net/accf.h 1970-01-01 01:00:00.000000000 +0100 +++ /usr/src/linux/include/net/accf.h 2005-10-11 20:38:52.000000000 +0200 @@ -0,0 +1,13 @@ +#ifndef _ACCF_H +#define _ACCF_H + +#include +#include + +extern void accf_data_handler(struct sock *sk); + +extern void sk_accf_install(struct sock *sk, void (*func)(struct sock *), + void *data); +extern void sk_accf_uninstall(struct sock *sk); + +#endif diff -E -b -x '*o' -x '*.cmd' -x '*.mod*c' -urN include/net/sock.h /usr/src/linux/include/net/sock.h --- include/net/sock.h 2005-10-09 23:21:42.000000000 +0200 +++ /usr/src/linux/include/net/sock.h 2005-10-11 17:56:27.000000000 +0200 @@ -248,6 +248,9 @@ int (*sk_backlog_rcv)(struct sock *sk, struct sk_buff *skb); void (*sk_destruct)(struct sock *sk); + void (*sk_accf_func)(struct sock *sk); + void *sk_accf_data; + struct sock *sk_accf_parent; }; /* diff -E -b -x '*o' -x '*.cmd' -x '*.mod*c' -urN net/core/sock.c /usr/src/linux/net/core/sock.c --- net/core/sock.c 2005-10-09 23:21:58.000000000 +0200 +++ /usr/src/linux/net/core/sock.c 2005-10-12 01:42:58.000000000 +0200 @@ -128,6 +128,8 @@ #include #endif +#include + /* Take into consideration the size of the struct sk_buff overhead in the * determination of these values, since that is non-constant across * platforms. This makes socket queueing behavior and performance @@ -440,6 +442,13 @@ ret = -ENONET; break; + case SO_ACCEPTFILTER: + spin_lock_bh(&sk->sk_lock.slock); + /* XXX have it select the right filter */ + sk_accf_install(sk, accf_data_handler, (void *)10); + spin_unlock_bh(&sk->sk_lock.slock); + break; + /* We implement the SO_SNDLOWAT etc to not be settable (1003.1g 5.3) */ default: @@ -1118,7 +1127,9 @@ static void sock_def_readable(struct sock *sk, int len) { read_lock(&sk->sk_callback_lock); - if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + if (sk->sk_accf_func != NULL) + sk->sk_accf_func(sk); + else if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) wake_up_interruptible(sk->sk_sleep); sk_wake_async(sk,1,POLL_IN); read_unlock(&sk->sk_callback_lock); diff -E -b -x '*o' -x '*.cmd' -x '*.mod*c' -urN net/ipv4/accf.c /usr/src/linux/net/ipv4/accf.c --- net/ipv4/accf.c 1970-01-01 01:00:00.000000000 +0100 +++ /usr/src/linux/net/ipv4/accf.c 2005-10-12 01:03:20.000000000 +0200 @@ -0,0 +1,38 @@ +#include +#include + +#include + +void accf_data_handler(struct sock *sk) +{ + struct sk_buff *skb; + int received = 0; + skb_queue_walk(&sk->sk_receive_queue, skb) { + /* XXX Should we discard certain packets? */ + received += skb->len; + } + + if (received >= (int)sk->sk_accf_data) { + printk(KERN_INFO "%s: waking up parent (%d)\n", __func__, received); + sk->sk_state_change(sk->sk_accf_parent); + sk_accf_uninstall(sk); + } +} + +void sk_accf_install(struct sock *sk, void (*func)(struct sock *), void *data) +{ + sk->sk_accf_func = func; + sk->sk_accf_data = data; + sk->sk_accf_parent = sk; +} + +void sk_accf_uninstall(struct sock *sk) +{ + sk->sk_accf_func = NULL; + sk->sk_accf_data = NULL; + sk->sk_accf_parent = NULL; +} + +EXPORT_SYMBOL(accf_data_handler); +EXPORT_SYMBOL(sk_accf_install); +EXPORT_SYMBOL(sk_accf_uninstall); diff -E -b -x '*o' -x '*.cmd' -x '*.mod*c' -urN net/ipv4/Makefile /usr/src/linux/net/ipv4/Makefile --- net/ipv4/Makefile 2005-10-11 18:09:02.000000000 +0200 +++ /usr/src/linux/net/ipv4/Makefile 2005-10-11 20:02:27.000000000 +0200 @@ -7,7 +7,8 @@ ip_output.o ip_sockglue.o \ tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o tcp_minisocks.o \ datagram.o raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \ - sysctl_net_ipv4.o fib_frontend.o fib_semantics.o fib_hash.o + sysctl_net_ipv4.o fib_frontend.o fib_semantics.o fib_hash.o \ + accf.o obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o diff -E -b -x '*o' -x '*.cmd' -x '*.mod*c' -urN net/ipv4/tcp_minisocks.c /usr/src/linux/net/ipv4/tcp_minisocks.c --- net/ipv4/tcp_minisocks.c 2005-10-09 23:22:05.000000000 +0200 +++ /usr/src/linux/net/ipv4/tcp_minisocks.c 2005-10-12 01:55:52.000000000 +0200 @@ -1055,7 +1055,8 @@ ret = tcp_rcv_state_process(child, skb, skb->h.th, skb->len); /* Wakeup parent, send SIGIO */ - if (state == TCP_SYN_RECV && child->sk_state != state) + if (!sk->sk_accf_func && + state == TCP_SYN_RECV && child->sk_state != state) parent->sk_data_ready(parent, 0); } else { /* Alas, it is possible again, because we do lookup