aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-07-26 09:38:48 -0400
committerIngo Molnar <mingo@elte.hu>2008-07-26 09:38:48 -0400
commitbda307ed7bdc160fcf1475a49f6c2e796fcb1294 (patch)
treeaa24926a83001373cb4ac2d8be9fd1b6994e7c60 /net
parent0791e13fbb1ea4e1808d055922c3f116b924bdc9 (diff)
parent024e8ac04453b3525448c31ef39848cf675ba6db (diff)
Merge branch 'linus' into x86/cleanups
Diffstat (limited to 'net')
-rw-r--r--net/802/psnap.c4
-rw-r--r--net/9p/trans_fd.c2
-rw-r--r--net/compat.c52
-rw-r--r--net/core/dev.c3
-rw-r--r--net/core/sock.c2
-rw-r--r--net/core/sysctl_net_core.c4
-rw-r--r--net/core/utils.c5
-rw-r--r--net/ipv4/Kconfig4
-rw-r--r--net/ipv4/af_inet.c9
-rw-r--r--net/ipv4/ipcomp.c315
-rw-r--r--net/ipv4/netfilter/Kconfig2
-rw-r--r--net/ipv4/tcp_input.c3
-rw-r--r--net/ipv6/Kconfig4
-rw-r--r--net/ipv6/af_inet6.c9
-rw-r--r--net/ipv6/ipcomp6.c298
-rw-r--r--net/ipv6/netfilter/Kconfig2
-rw-r--r--net/sched/sch_generic.c4
-rw-r--r--net/sched/sch_sfq.c9
-rw-r--r--net/sctp/socket.c2
-rw-r--r--net/socket.c142
-rw-r--r--net/sysctl_net.c14
-rw-r--r--net/xfrm/Kconfig6
-rw-r--r--net/xfrm/Makefile1
-rw-r--r--net/xfrm/xfrm_ipcomp.c385
24 files changed, 617 insertions, 664 deletions
diff --git a/net/802/psnap.c b/net/802/psnap.c
index ea4643931446..b3cfe5a14fca 100644
--- a/net/802/psnap.c
+++ b/net/802/psnap.c
@@ -31,11 +31,9 @@ static struct llc_sap *snap_sap;
31 */ 31 */
32static struct datalink_proto *find_snap_client(unsigned char *desc) 32static struct datalink_proto *find_snap_client(unsigned char *desc)
33{ 33{
34 struct list_head *entry;
35 struct datalink_proto *proto = NULL, *p; 34 struct datalink_proto *proto = NULL, *p;
36 35
37 list_for_each_rcu(entry, &snap_list) { 36 list_for_each_entry_rcu(p, &snap_list, node) {
38 p = list_entry(entry, struct datalink_proto, node);
39 if (!memcmp(p->type, desc, 5)) { 37 if (!memcmp(p->type, desc, 5)) {
40 proto = p; 38 proto = p;
41 break; 39 break;
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
index 4507f744f44e..cdf137af7adc 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -1285,7 +1285,7 @@ static int p9_socket_open(struct p9_trans *trans, struct socket *csocket)
1285 int fd, ret; 1285 int fd, ret;
1286 1286
1287 csocket->sk->sk_allocation = GFP_NOIO; 1287 csocket->sk->sk_allocation = GFP_NOIO;
1288 fd = sock_map_fd(csocket); 1288 fd = sock_map_fd(csocket, 0);
1289 if (fd < 0) { 1289 if (fd < 0) {
1290 P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to map fd\n"); 1290 P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to map fd\n");
1291 return fd; 1291 return fd;
diff --git a/net/compat.c b/net/compat.c
index 6e1b03b51933..67fb6a3834a3 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -722,9 +722,10 @@ EXPORT_SYMBOL(compat_mc_getsockopt);
722 722
723/* Argument list sizes for compat_sys_socketcall */ 723/* Argument list sizes for compat_sys_socketcall */
724#define AL(x) ((x) * sizeof(u32)) 724#define AL(x) ((x) * sizeof(u32))
725static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), 725static unsigned char nas[19]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
726 AL(3),AL(3),AL(4),AL(4),AL(4),AL(6), 726 AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
727 AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)}; 727 AL(6),AL(2),AL(5),AL(5),AL(3),AL(3),
728 AL(6)};
728#undef AL 729#undef AL
729 730
730asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned flags) 731asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned flags)
@@ -737,13 +738,52 @@ asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg, uns
737 return sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT); 738 return sys_recvmsg(fd, (struct msghdr __user *)msg, flags | MSG_CMSG_COMPAT);
738} 739}
739 740
741asmlinkage long compat_sys_paccept(int fd, struct sockaddr __user *upeer_sockaddr,
742 int __user *upeer_addrlen,
743 const compat_sigset_t __user *sigmask,
744 compat_size_t sigsetsize, int flags)
745{
746 compat_sigset_t ss32;
747 sigset_t ksigmask, sigsaved;
748 int ret;
749
750 if (sigmask) {
751 if (sigsetsize != sizeof(compat_sigset_t))
752 return -EINVAL;
753 if (copy_from_user(&ss32, sigmask, sizeof(ss32)))
754 return -EFAULT;
755 sigset_from_compat(&ksigmask, &ss32);
756
757 sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
758 sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
759 }
760
761 ret = do_accept(fd, upeer_sockaddr, upeer_addrlen, flags);
762
763 if (ret == -ERESTARTNOHAND) {
764 /*
765 * Don't restore the signal mask yet. Let do_signal() deliver
766 * the signal on the way back to userspace, before the signal
767 * mask is restored.
768 */
769 if (sigmask) {
770 memcpy(&current->saved_sigmask, &sigsaved,
771 sizeof(sigsaved));
772 set_restore_sigmask();
773 }
774 } else if (sigmask)
775 sigprocmask(SIG_SETMASK, &sigsaved, NULL);
776
777 return ret;
778}
779
740asmlinkage long compat_sys_socketcall(int call, u32 __user *args) 780asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
741{ 781{
742 int ret; 782 int ret;
743 u32 a[6]; 783 u32 a[6];
744 u32 a0, a1; 784 u32 a0, a1;
745 785
746 if (call < SYS_SOCKET || call > SYS_RECVMSG) 786 if (call < SYS_SOCKET || call > SYS_PACCEPT)
747 return -EINVAL; 787 return -EINVAL;
748 if (copy_from_user(a, args, nas[call])) 788 if (copy_from_user(a, args, nas[call]))
749 return -EFAULT; 789 return -EFAULT;
@@ -764,7 +804,7 @@ asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
764 ret = sys_listen(a0, a1); 804 ret = sys_listen(a0, a1);
765 break; 805 break;
766 case SYS_ACCEPT: 806 case SYS_ACCEPT:
767 ret = sys_accept(a0, compat_ptr(a1), compat_ptr(a[2])); 807 ret = do_accept(a0, compat_ptr(a1), compat_ptr(a[2]), 0);
768 break; 808 break;
769 case SYS_GETSOCKNAME: 809 case SYS_GETSOCKNAME:
770 ret = sys_getsockname(a0, compat_ptr(a1), compat_ptr(a[2])); 810 ret = sys_getsockname(a0, compat_ptr(a1), compat_ptr(a[2]));
@@ -804,6 +844,10 @@ asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
804 case SYS_RECVMSG: 844 case SYS_RECVMSG:
805 ret = compat_sys_recvmsg(a0, compat_ptr(a1), a[2]); 845 ret = compat_sys_recvmsg(a0, compat_ptr(a1), a[2]);
806 break; 846 break;
847 case SYS_PACCEPT:
848 ret = compat_sys_paccept(a0, compat_ptr(a1), compat_ptr(a[2]),
849 compat_ptr(a[3]), a[4], a[5]);
850 break;
807 default: 851 default:
808 ret = -EINVAL; 852 ret = -EINVAL;
809 break; 853 break;
diff --git a/net/core/dev.c b/net/core/dev.c
index 7463a2150b09..53af7841018a 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1341,9 +1341,6 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
1341 1341
1342void __netif_schedule(struct Qdisc *q) 1342void __netif_schedule(struct Qdisc *q)
1343{ 1343{
1344 if (WARN_ON_ONCE(q == &noop_qdisc))
1345 return;
1346
1347 if (!test_and_set_bit(__QDISC_STATE_SCHED, &q->state)) { 1344 if (!test_and_set_bit(__QDISC_STATE_SCHED, &q->state)) {
1348 struct softnet_data *sd; 1345 struct softnet_data *sd;
1349 unsigned long flags; 1346 unsigned long flags;
diff --git a/net/core/sock.c b/net/core/sock.c
index 10a64d57078c..91f8bbc93526 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -180,7 +180,7 @@ static const char *af_family_clock_key_strings[AF_MAX+1] = {
180 "clock-AF_ASH" , "clock-AF_ECONET" , "clock-AF_ATMSVC" , 180 "clock-AF_ASH" , "clock-AF_ECONET" , "clock-AF_ATMSVC" ,
181 "clock-21" , "clock-AF_SNA" , "clock-AF_IRDA" , 181 "clock-21" , "clock-AF_SNA" , "clock-AF_IRDA" ,
182 "clock-AF_PPPOX" , "clock-AF_WANPIPE" , "clock-AF_LLC" , 182 "clock-AF_PPPOX" , "clock-AF_WANPIPE" , "clock-AF_LLC" ,
183 "clock-27" , "clock-28" , "clock-29" , 183 "clock-27" , "clock-28" , "clock-AF_CAN" ,
184 "clock-AF_TIPC" , "clock-AF_BLUETOOTH", "clock-AF_IUCV" , 184 "clock-AF_TIPC" , "clock-AF_BLUETOOTH", "clock-AF_IUCV" ,
185 "clock-AF_RXRPC" , "clock-AF_MAX" 185 "clock-AF_RXRPC" , "clock-AF_MAX"
186}; 186};
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index a570e2af22cb..f686467ff12b 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -67,7 +67,7 @@ static struct ctl_table net_core_table[] = {
67 { 67 {
68 .ctl_name = NET_CORE_MSG_COST, 68 .ctl_name = NET_CORE_MSG_COST,
69 .procname = "message_cost", 69 .procname = "message_cost",
70 .data = &net_msg_cost, 70 .data = &net_ratelimit_state.interval,
71 .maxlen = sizeof(int), 71 .maxlen = sizeof(int),
72 .mode = 0644, 72 .mode = 0644,
73 .proc_handler = &proc_dointvec_jiffies, 73 .proc_handler = &proc_dointvec_jiffies,
@@ -76,7 +76,7 @@ static struct ctl_table net_core_table[] = {
76 { 76 {
77 .ctl_name = NET_CORE_MSG_BURST, 77 .ctl_name = NET_CORE_MSG_BURST,
78 .procname = "message_burst", 78 .procname = "message_burst",
79 .data = &net_msg_burst, 79 .data = &net_ratelimit_state.burst,
80 .maxlen = sizeof(int), 80 .maxlen = sizeof(int),
81 .mode = 0644, 81 .mode = 0644,
82 .proc_handler = &proc_dointvec, 82 .proc_handler = &proc_dointvec,
diff --git a/net/core/utils.c b/net/core/utils.c
index 8031eb59054e..72e0ebe964a0 100644
--- a/net/core/utils.c
+++ b/net/core/utils.c
@@ -31,17 +31,16 @@
31#include <asm/system.h> 31#include <asm/system.h>
32#include <asm/uaccess.h> 32#include <asm/uaccess.h>
33 33
34int net_msg_cost __read_mostly = 5*HZ;
35int net_msg_burst __read_mostly = 10;
36int net_msg_warn __read_mostly = 1; 34int net_msg_warn __read_mostly = 1;
37EXPORT_SYMBOL(net_msg_warn); 35EXPORT_SYMBOL(net_msg_warn);
38 36
37DEFINE_RATELIMIT_STATE(net_ratelimit_state, 5 * HZ, 10);
39/* 38/*
40 * All net warning printk()s should be guarded by this function. 39 * All net warning printk()s should be guarded by this function.
41 */ 40 */
42int net_ratelimit(void) 41int net_ratelimit(void)
43{ 42{
44 return __printk_ratelimit(net_msg_cost, net_msg_burst); 43 return __ratelimit(&net_ratelimit_state);
45} 44}
46EXPORT_SYMBOL(net_ratelimit); 45EXPORT_SYMBOL(net_ratelimit);
47 46
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index 4670683b4688..591ea23639ca 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -356,10 +356,8 @@ config INET_ESP
356 356
357config INET_IPCOMP 357config INET_IPCOMP
358 tristate "IP: IPComp transformation" 358 tristate "IP: IPComp transformation"
359 select XFRM
360 select INET_XFRM_TUNNEL 359 select INET_XFRM_TUNNEL
361 select CRYPTO 360 select XFRM_IPCOMP
362 select CRYPTO_DEFLATE
363 ---help--- 361 ---help---
364 Support for IP Payload Compression Protocol (IPComp) (RFC3173), 362 Support for IP Payload Compression Protocol (IPComp) (RFC3173),
365 typically needed for IPsec. 363 typically needed for IPsec.
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index dd919d84285f..f440a9f54924 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -264,7 +264,6 @@ static inline int inet_netns_ok(struct net *net, int protocol)
264static int inet_create(struct net *net, struct socket *sock, int protocol) 264static int inet_create(struct net *net, struct socket *sock, int protocol)
265{ 265{
266 struct sock *sk; 266 struct sock *sk;
267 struct list_head *p;
268 struct inet_protosw *answer; 267 struct inet_protosw *answer;
269 struct inet_sock *inet; 268 struct inet_sock *inet;
270 struct proto *answer_prot; 269 struct proto *answer_prot;
@@ -281,13 +280,12 @@ static int inet_create(struct net *net, struct socket *sock, int protocol)
281 sock->state = SS_UNCONNECTED; 280 sock->state = SS_UNCONNECTED;
282 281
283 /* Look for the requested type/protocol pair. */ 282 /* Look for the requested type/protocol pair. */
284 answer = NULL;
285lookup_protocol: 283lookup_protocol:
286 err = -ESOCKTNOSUPPORT; 284 err = -ESOCKTNOSUPPORT;
287 rcu_read_lock(); 285 rcu_read_lock();
288 list_for_each_rcu(p, &inetsw[sock->type]) { 286 list_for_each_entry_rcu(answer, &inetsw[sock->type], list) {
289 answer = list_entry(p, struct inet_protosw, list);
290 287
288 err = 0;
291 /* Check the non-wild match. */ 289 /* Check the non-wild match. */
292 if (protocol == answer->protocol) { 290 if (protocol == answer->protocol) {
293 if (protocol != IPPROTO_IP) 291 if (protocol != IPPROTO_IP)
@@ -302,10 +300,9 @@ lookup_protocol:
302 break; 300 break;
303 } 301 }
304 err = -EPROTONOSUPPORT; 302 err = -EPROTONOSUPPORT;
305 answer = NULL;
306 } 303 }
307 304
308 if (unlikely(answer == NULL)) { 305 if (unlikely(err)) {
309 if (try_loading_module < 2) { 306 if (try_loading_module < 2) {
310 rcu_read_unlock(); 307 rcu_read_unlock();
311 /* 308 /*
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index a75807b971b3..a42b64d040c4 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -14,153 +14,14 @@
14 * - Adaptive compression. 14 * - Adaptive compression.
15 */ 15 */
16#include <linux/module.h> 16#include <linux/module.h>
17#include <linux/crypto.h>
18#include <linux/err.h> 17#include <linux/err.h>
19#include <linux/pfkeyv2.h>
20#include <linux/percpu.h>
21#include <linux/smp.h>
22#include <linux/list.h>
23#include <linux/vmalloc.h>
24#include <linux/rtnetlink.h> 18#include <linux/rtnetlink.h>
25#include <linux/mutex.h>
26#include <net/ip.h> 19#include <net/ip.h>
27#include <net/xfrm.h> 20#include <net/xfrm.h>
28#include <net/icmp.h> 21#include <net/icmp.h>
29#include <net/ipcomp.h> 22#include <net/ipcomp.h>
30#include <net/protocol.h> 23#include <net/protocol.h>
31 24#include <net/sock.h>
32struct ipcomp_tfms {
33 struct list_head list;
34 struct crypto_comp **tfms;
35 int users;
36};
37
38static DEFINE_MUTEX(ipcomp_resource_mutex);
39static void **ipcomp_scratches;
40static int ipcomp_scratch_users;
41static LIST_HEAD(ipcomp_tfms_list);
42
43static int ipcomp_decompress(struct xfrm_state *x, struct sk_buff *skb)
44{
45 struct ipcomp_data *ipcd = x->data;
46 const int plen = skb->len;
47 int dlen = IPCOMP_SCRATCH_SIZE;
48 const u8 *start = skb->data;
49 const int cpu = get_cpu();
50 u8 *scratch = *per_cpu_ptr(ipcomp_scratches, cpu);
51 struct crypto_comp *tfm = *per_cpu_ptr(ipcd->tfms, cpu);
52 int err = crypto_comp_decompress(tfm, start, plen, scratch, &dlen);
53
54 if (err)
55 goto out;
56
57 if (dlen < (plen + sizeof(struct ip_comp_hdr))) {
58 err = -EINVAL;
59 goto out;
60 }
61
62 err = pskb_expand_head(skb, 0, dlen - plen, GFP_ATOMIC);
63 if (err)
64 goto out;
65
66 skb->truesize += dlen - plen;
67 __skb_put(skb, dlen - plen);
68 skb_copy_to_linear_data(skb, scratch, dlen);
69out:
70 put_cpu();
71 return err;
72}
73
74static int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb)
75{
76 int nexthdr;
77 int err = -ENOMEM;
78 struct ip_comp_hdr *ipch;
79
80 if (skb_linearize_cow(skb))
81 goto out;
82
83 skb->ip_summed = CHECKSUM_NONE;
84
85 /* Remove ipcomp header and decompress original payload */
86 ipch = (void *)skb->data;
87 nexthdr = ipch->nexthdr;
88
89 skb->transport_header = skb->network_header + sizeof(*ipch);
90 __skb_pull(skb, sizeof(*ipch));
91 err = ipcomp_decompress(x, skb);
92 if (err)
93 goto out;
94
95 err = nexthdr;
96
97out:
98 return err;
99}
100
101static int ipcomp_compress(struct xfrm_state *x, struct sk_buff *skb)
102{
103 struct ipcomp_data *ipcd = x->data;
104 const int plen = skb->len;
105 int dlen = IPCOMP_SCRATCH_SIZE;
106 u8 *start = skb->data;
107 const int cpu = get_cpu();
108 u8 *scratch = *per_cpu_ptr(ipcomp_scratches, cpu);
109 struct crypto_comp *tfm = *per_cpu_ptr(ipcd->tfms, cpu);
110 int err;
111
112 local_bh_disable();
113 err = crypto_comp_compress(tfm, start, plen, scratch, &dlen);
114 local_bh_enable();
115 if (err)
116 goto out;
117
118 if ((dlen + sizeof(struct ip_comp_hdr)) >= plen) {
119 err = -EMSGSIZE;
120 goto out;
121 }
122
123 memcpy(start + sizeof(struct ip_comp_hdr), scratch, dlen);
124 put_cpu();
125
126 pskb_trim(skb, dlen + sizeof(struct ip_comp_hdr));
127 return 0;
128
129out:
130 put_cpu();
131 return err;
132}
133
134static int ipcomp_output(struct xfrm_state *x, struct sk_buff *skb)
135{
136 int err;
137 struct ip_comp_hdr *ipch;
138 struct ipcomp_data *ipcd = x->data;
139
140 if (skb->len < ipcd->threshold) {
141 /* Don't bother compressing */
142 goto out_ok;
143 }
144
145 if (skb_linearize_cow(skb))
146 goto out_ok;
147
148 err = ipcomp_compress(x, skb);
149
150 if (err) {
151 goto out_ok;
152 }
153
154 /* Install ipcomp header, convert into ipcomp datagram. */
155 ipch = ip_comp_hdr(skb);
156 ipch->nexthdr = *skb_mac_header(skb);
157 ipch->flags = 0;
158 ipch->cpi = htons((u16 )ntohl(x->id.spi));
159 *skb_mac_header(skb) = IPPROTO_COMP;
160out_ok:
161 skb_push(skb, -skb_network_offset(skb));
162 return 0;
163}
164 25
165static void ipcomp4_err(struct sk_buff *skb, u32 info) 26static void ipcomp4_err(struct sk_buff *skb, u32 info)
166{ 27{
@@ -241,156 +102,12 @@ out:
241 return err; 102 return err;
242} 103}
243 104
244static void ipcomp_free_scratches(void) 105static int ipcomp4_init_state(struct xfrm_state *x)
245{
246 int i;
247 void **scratches;
248
249 if (--ipcomp_scratch_users)
250 return;
251
252 scratches = ipcomp_scratches;
253 if (!scratches)
254 return;
255
256 for_each_possible_cpu(i)
257 vfree(*per_cpu_ptr(scratches, i));
258
259 free_percpu(scratches);
260}
261
262static void **ipcomp_alloc_scratches(void)
263{
264 int i;
265 void **scratches;
266
267 if (ipcomp_scratch_users++)
268 return ipcomp_scratches;
269
270 scratches = alloc_percpu(void *);
271 if (!scratches)
272 return NULL;
273
274 ipcomp_scratches = scratches;
275
276 for_each_possible_cpu(i) {
277 void *scratch = vmalloc(IPCOMP_SCRATCH_SIZE);
278 if (!scratch)
279 return NULL;
280 *per_cpu_ptr(scratches, i) = scratch;
281 }
282
283 return scratches;
284}
285
286static void ipcomp_free_tfms(struct crypto_comp **tfms)
287{
288 struct ipcomp_tfms *pos;
289 int cpu;
290
291 list_for_each_entry(pos, &ipcomp_tfms_list, list) {
292 if (pos->tfms == tfms)
293 break;
294 }
295
296 BUG_TRAP(pos);
297
298 if (--pos->users)
299 return;
300
301 list_del(&pos->list);
302 kfree(pos);
303
304 if (!tfms)
305 return;
306
307 for_each_possible_cpu(cpu) {
308 struct crypto_comp *tfm = *per_cpu_ptr(tfms, cpu);
309 crypto_free_comp(tfm);
310 }
311 free_percpu(tfms);
312}
313
314static struct crypto_comp **ipcomp_alloc_tfms(const char *alg_name)
315{
316 struct ipcomp_tfms *pos;
317 struct crypto_comp **tfms;
318 int cpu;
319
320 /* This can be any valid CPU ID so we don't need locking. */
321 cpu = raw_smp_processor_id();
322
323 list_for_each_entry(pos, &ipcomp_tfms_list, list) {
324 struct crypto_comp *tfm;
325
326 tfms = pos->tfms;
327 tfm = *per_cpu_ptr(tfms, cpu);
328
329 if (!strcmp(crypto_comp_name(tfm), alg_name)) {
330 pos->users++;
331 return tfms;
332 }
333 }
334
335 pos = kmalloc(sizeof(*pos), GFP_KERNEL);
336 if (!pos)
337 return NULL;
338
339 pos->users = 1;
340 INIT_LIST_HEAD(&pos->list);
341 list_add(&pos->list, &ipcomp_tfms_list);
342
343 pos->tfms = tfms = alloc_percpu(struct crypto_comp *);
344 if (!tfms)
345 goto error;
346
347 for_each_possible_cpu(cpu) {
348 struct crypto_comp *tfm = crypto_alloc_comp(alg_name, 0,
349 CRYPTO_ALG_ASYNC);
350 if (IS_ERR(tfm))
351 goto error;
352 *per_cpu_ptr(tfms, cpu) = tfm;
353 }
354
355 return tfms;
356
357error:
358 ipcomp_free_tfms(tfms);
359 return NULL;
360}
361
362static void ipcomp_free_data(struct ipcomp_data *ipcd)
363{
364 if (ipcd->tfms)
365 ipcomp_free_tfms(ipcd->tfms);
366 ipcomp_free_scratches();
367}
368
369static void ipcomp_destroy(struct xfrm_state *x)
370{
371 struct ipcomp_data *ipcd = x->data;
372 if (!ipcd)
373 return;
374 xfrm_state_delete_tunnel(x);
375 mutex_lock(&ipcomp_resource_mutex);
376 ipcomp_free_data(ipcd);
377 mutex_unlock(&ipcomp_resource_mutex);
378 kfree(ipcd);
379}
380
381static int ipcomp_init_state(struct xfrm_state *x)
382{ 106{
383 int err; 107 int err;
384 struct ipcomp_data *ipcd; 108 struct ipcomp_data *ipcd;
385 struct xfrm_algo_desc *calg_desc; 109 struct xfrm_algo_desc *calg_desc;
386 110
387 err = -EINVAL;
388 if (!x->calg)
389 goto out;
390
391 if (x->encap)
392 goto out;
393
394 x->props.header_len = 0; 111 x->props.header_len = 0;
395 switch (x->props.mode) { 112 switch (x->props.mode) {
396 case XFRM_MODE_TRANSPORT: 113 case XFRM_MODE_TRANSPORT:
@@ -402,40 +119,22 @@ static int ipcomp_init_state(struct xfrm_state *x)
402 goto out; 119 goto out;
403 } 120 }
404 121
405 err = -ENOMEM; 122 err = ipcomp_init_state(x);
406 ipcd = kzalloc(sizeof(*ipcd), GFP_KERNEL); 123 if (err)
407 if (!ipcd)
408 goto out; 124 goto out;
409 125
410 mutex_lock(&ipcomp_resource_mutex);
411 if (!ipcomp_alloc_scratches())
412 goto error;
413
414 ipcd->tfms = ipcomp_alloc_tfms(x->calg->alg_name);
415 if (!ipcd->tfms)
416 goto error;
417 mutex_unlock(&ipcomp_resource_mutex);
418
419 if (x->props.mode == XFRM_MODE_TUNNEL) { 126 if (x->props.mode == XFRM_MODE_TUNNEL) {
420 err = ipcomp_tunnel_attach(x); 127 err = ipcomp_tunnel_attach(x);
421 if (err) 128 if (err)
422 goto error_tunnel; 129 goto error_tunnel;
423 } 130 }
424 131
425 calg_desc = xfrm_calg_get_byname(x->calg->alg_name, 0);
426 BUG_ON(!calg_desc);
427 ipcd->threshold = calg_desc->uinfo.comp.threshold;
428 x->data = ipcd;
429 err = 0; 132 err = 0;
430out: 133out:
431 return err; 134 return err;
432 135
433error_tunnel: 136error_tunnel:
434 mutex_lock(&ipcomp_resource_mutex); 137 ipcomp_destroy(x);
435error:
436 ipcomp_free_data(ipcd);
437 mutex_unlock(&ipcomp_resource_mutex);
438 kfree(ipcd);
439 goto out; 138 goto out;
440} 139}
441 140
@@ -443,7 +142,7 @@ static const struct xfrm_type ipcomp_type = {
443 .description = "IPCOMP4", 142 .description = "IPCOMP4",
444 .owner = THIS_MODULE, 143 .owner = THIS_MODULE,
445 .proto = IPPROTO_COMP, 144 .proto = IPPROTO_COMP,
446 .init_state = ipcomp_init_state, 145 .init_state = ipcomp4_init_state,
447 .destructor = ipcomp_destroy, 146 .destructor = ipcomp_destroy,
448 .input = ipcomp_input, 147 .input = ipcomp_input,
449 .output = ipcomp_output 148 .output = ipcomp_output
@@ -481,7 +180,7 @@ module_init(ipcomp4_init);
481module_exit(ipcomp4_fini); 180module_exit(ipcomp4_fini);
482 181
483MODULE_LICENSE("GPL"); 182MODULE_LICENSE("GPL");
484MODULE_DESCRIPTION("IP Payload Compression Protocol (IPComp) - RFC3173"); 183MODULE_DESCRIPTION("IP Payload Compression Protocol (IPComp/IPv4) - RFC3173");
485MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>"); 184MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
486 185
487MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_COMP); 186MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_COMP);
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index f23e60c93ef9..90eb7cb47e77 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -369,7 +369,7 @@ config IP_NF_SECURITY
369 tristate "Security table" 369 tristate "Security table"
370 depends on IP_NF_IPTABLES 370 depends on IP_NF_IPTABLES
371 depends on SECURITY 371 depends on SECURITY
372 default m if NETFILTER_ADVANCED=n 372 depends on NETFILTER_ADVANCED
373 help 373 help
374 This option adds a `security' table to iptables, for use 374 This option adds a `security' table to iptables, for use
375 with Mandatory Access Control (MAC) policy. 375 with Mandatory Access Control (MAC) policy.
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 1f5e6049883e..75efd244f2af 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -3292,6 +3292,7 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
3292 * log. Something worked... 3292 * log. Something worked...
3293 */ 3293 */
3294 sk->sk_err_soft = 0; 3294 sk->sk_err_soft = 0;
3295 icsk->icsk_probes_out = 0;
3295 tp->rcv_tstamp = tcp_time_stamp; 3296 tp->rcv_tstamp = tcp_time_stamp;
3296 prior_packets = tp->packets_out; 3297 prior_packets = tp->packets_out;
3297 if (!prior_packets) 3298 if (!prior_packets)
@@ -3324,8 +3325,6 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
3324 return 1; 3325 return 1;
3325 3326
3326no_queue: 3327no_queue:
3327 icsk->icsk_probes_out = 0;
3328
3329 /* If this ack opens up a zero window, clear backoff. It was 3328 /* If this ack opens up a zero window, clear backoff. It was
3330 * being used to time the probes, and is probably far higher than 3329 * being used to time the probes, and is probably far higher than
3331 * it needs to be for normal retransmission. 3330 * it needs to be for normal retransmission.
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index 42814a2ec9d7..ec992159b5f8 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -96,10 +96,8 @@ config INET6_ESP
96 96
97config INET6_IPCOMP 97config INET6_IPCOMP
98 tristate "IPv6: IPComp transformation" 98 tristate "IPv6: IPComp transformation"
99 select XFRM
100 select INET6_XFRM_TUNNEL 99 select INET6_XFRM_TUNNEL
101 select CRYPTO 100 select XFRM_IPCOMP
102 select CRYPTO_DEFLATE
103 ---help--- 101 ---help---
104 Support for IP Payload Compression Protocol (IPComp) (RFC3173), 102 Support for IP Payload Compression Protocol (IPComp) (RFC3173),
105 typically needed for IPsec. 103 typically needed for IPsec.
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 3d828bc4b1cf..60461ad7fa6f 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -83,7 +83,6 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol)
83 struct inet_sock *inet; 83 struct inet_sock *inet;
84 struct ipv6_pinfo *np; 84 struct ipv6_pinfo *np;
85 struct sock *sk; 85 struct sock *sk;
86 struct list_head *p;
87 struct inet_protosw *answer; 86 struct inet_protosw *answer;
88 struct proto *answer_prot; 87 struct proto *answer_prot;
89 unsigned char answer_flags; 88 unsigned char answer_flags;
@@ -97,13 +96,12 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol)
97 build_ehash_secret(); 96 build_ehash_secret();
98 97
99 /* Look for the requested type/protocol pair. */ 98 /* Look for the requested type/protocol pair. */
100 answer = NULL;
101lookup_protocol: 99lookup_protocol:
102 err = -ESOCKTNOSUPPORT; 100 err = -ESOCKTNOSUPPORT;
103 rcu_read_lock(); 101 rcu_read_lock();
104 list_for_each_rcu(p, &inetsw6[sock->type]) { 102 list_for_each_entry_rcu(answer, &inetsw6[sock->type], list) {
105 answer = list_entry(p, struct inet_protosw, list);
106 103
104 err = 0;
107 /* Check the non-wild match. */ 105 /* Check the non-wild match. */
108 if (protocol == answer->protocol) { 106 if (protocol == answer->protocol) {
109 if (protocol != IPPROTO_IP) 107 if (protocol != IPPROTO_IP)
@@ -118,10 +116,9 @@ lookup_protocol:
118 break; 116 break;
119 } 117 }
120 err = -EPROTONOSUPPORT; 118 err = -EPROTONOSUPPORT;
121 answer = NULL;
122 } 119 }
123 120
124 if (!answer) { 121 if (err) {
125 if (try_loading_module < 2) { 122 if (try_loading_module < 2) {
126 rcu_read_unlock(); 123 rcu_read_unlock();
127 /* 124 /*
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
index ee6de425ce6b..0cfcea42153a 100644
--- a/net/ipv6/ipcomp6.c
+++ b/net/ipv6/ipcomp6.c
@@ -50,125 +50,6 @@
50#include <linux/icmpv6.h> 50#include <linux/icmpv6.h>
51#include <linux/mutex.h> 51#include <linux/mutex.h>
52 52
53struct ipcomp6_tfms {
54 struct list_head list;
55 struct crypto_comp **tfms;
56 int users;
57};
58
59static DEFINE_MUTEX(ipcomp6_resource_mutex);
60static void **ipcomp6_scratches;
61static int ipcomp6_scratch_users;
62static LIST_HEAD(ipcomp6_tfms_list);
63
64static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb)
65{
66 int nexthdr;
67 int err = -ENOMEM;
68 struct ip_comp_hdr *ipch;
69 int plen, dlen;
70 struct ipcomp_data *ipcd = x->data;
71 u8 *start, *scratch;
72 struct crypto_comp *tfm;
73 int cpu;
74
75 if (skb_linearize_cow(skb))
76 goto out;
77
78 skb->ip_summed = CHECKSUM_NONE;
79
80 /* Remove ipcomp header and decompress original payload */
81 ipch = (void *)skb->data;
82 nexthdr = ipch->nexthdr;
83
84 skb->transport_header = skb->network_header + sizeof(*ipch);
85 __skb_pull(skb, sizeof(*ipch));
86
87 /* decompression */
88 plen = skb->len;
89 dlen = IPCOMP_SCRATCH_SIZE;
90 start = skb->data;
91
92 cpu = get_cpu();
93 scratch = *per_cpu_ptr(ipcomp6_scratches, cpu);
94 tfm = *per_cpu_ptr(ipcd->tfms, cpu);
95
96 err = crypto_comp_decompress(tfm, start, plen, scratch, &dlen);
97 if (err)
98 goto out_put_cpu;
99
100 if (dlen < (plen + sizeof(*ipch))) {
101 err = -EINVAL;
102 goto out_put_cpu;
103 }
104
105 err = pskb_expand_head(skb, 0, dlen - plen, GFP_ATOMIC);
106 if (err) {
107 goto out_put_cpu;
108 }
109
110 skb->truesize += dlen - plen;
111 __skb_put(skb, dlen - plen);
112 skb_copy_to_linear_data(skb, scratch, dlen);
113 err = nexthdr;
114
115out_put_cpu:
116 put_cpu();
117out:
118 return err;
119}
120
121static int ipcomp6_output(struct xfrm_state *x, struct sk_buff *skb)
122{
123 int err;
124 struct ip_comp_hdr *ipch;
125 struct ipcomp_data *ipcd = x->data;
126 int plen, dlen;
127 u8 *start, *scratch;
128 struct crypto_comp *tfm;
129 int cpu;
130
131 /* check whether datagram len is larger than threshold */
132 if (skb->len < ipcd->threshold) {
133 goto out_ok;
134 }
135
136 if (skb_linearize_cow(skb))
137 goto out_ok;
138
139 /* compression */
140 plen = skb->len;
141 dlen = IPCOMP_SCRATCH_SIZE;
142 start = skb->data;
143
144 cpu = get_cpu();
145 scratch = *per_cpu_ptr(ipcomp6_scratches, cpu);
146 tfm = *per_cpu_ptr(ipcd->tfms, cpu);
147
148 local_bh_disable();
149 err = crypto_comp_compress(tfm, start, plen, scratch, &dlen);
150 local_bh_enable();
151 if (err || (dlen + sizeof(*ipch)) >= plen) {
152 put_cpu();
153 goto out_ok;
154 }
155 memcpy(start + sizeof(struct ip_comp_hdr), scratch, dlen);
156 put_cpu();
157 pskb_trim(skb, dlen + sizeof(struct ip_comp_hdr));
158
159 /* insert ipcomp header and replace datagram */
160 ipch = ip_comp_hdr(skb);
161 ipch->nexthdr = *skb_mac_header(skb);
162 ipch->flags = 0;
163 ipch->cpi = htons((u16 )ntohl(x->id.spi));
164 *skb_mac_header(skb) = IPPROTO_COMP;
165
166out_ok:
167 skb_push(skb, -skb_network_offset(skb));
168
169 return 0;
170}
171
172static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 53static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
173 int type, int code, int offset, __be32 info) 54 int type, int code, int offset, __be32 info)
174{ 55{
@@ -251,161 +132,12 @@ out:
251 return err; 132 return err;
252} 133}
253 134
254static void ipcomp6_free_scratches(void)
255{
256 int i;
257 void **scratches;
258
259 if (--ipcomp6_scratch_users)
260 return;
261
262 scratches = ipcomp6_scratches;
263 if (!scratches)
264 return;
265
266 for_each_possible_cpu(i) {
267 void *scratch = *per_cpu_ptr(scratches, i);
268
269 vfree(scratch);
270 }
271
272 free_percpu(scratches);
273}
274
275static void **ipcomp6_alloc_scratches(void)
276{
277 int i;
278 void **scratches;
279
280 if (ipcomp6_scratch_users++)
281 return ipcomp6_scratches;
282
283 scratches = alloc_percpu(void *);
284 if (!scratches)
285 return NULL;
286
287 ipcomp6_scratches = scratches;
288
289 for_each_possible_cpu(i) {
290 void *scratch = vmalloc(IPCOMP_SCRATCH_SIZE);
291 if (!scratch)
292 return NULL;
293 *per_cpu_ptr(scratches, i) = scratch;
294 }
295
296 return scratches;
297}
298
299static void ipcomp6_free_tfms(struct crypto_comp **tfms)
300{
301 struct ipcomp6_tfms *pos;
302 int cpu;
303
304 list_for_each_entry(pos, &ipcomp6_tfms_list, list) {
305 if (pos->tfms == tfms)
306 break;
307 }
308
309 BUG_TRAP(pos);
310
311 if (--pos->users)
312 return;
313
314 list_del(&pos->list);
315 kfree(pos);
316
317 if (!tfms)
318 return;
319
320 for_each_possible_cpu(cpu) {
321 struct crypto_comp *tfm = *per_cpu_ptr(tfms, cpu);
322 crypto_free_comp(tfm);
323 }
324 free_percpu(tfms);
325}
326
327static struct crypto_comp **ipcomp6_alloc_tfms(const char *alg_name)
328{
329 struct ipcomp6_tfms *pos;
330 struct crypto_comp **tfms;
331 int cpu;
332
333 /* This can be any valid CPU ID so we don't need locking. */
334 cpu = raw_smp_processor_id();
335
336 list_for_each_entry(pos, &ipcomp6_tfms_list, list) {
337 struct crypto_comp *tfm;
338
339 tfms = pos->tfms;
340 tfm = *per_cpu_ptr(tfms, cpu);
341
342 if (!strcmp(crypto_comp_name(tfm), alg_name)) {
343 pos->users++;
344 return tfms;
345 }
346 }
347
348 pos = kmalloc(sizeof(*pos), GFP_KERNEL);
349 if (!pos)
350 return NULL;
351
352 pos->users = 1;
353 INIT_LIST_HEAD(&pos->list);
354 list_add(&pos->list, &ipcomp6_tfms_list);
355
356 pos->tfms = tfms = alloc_percpu(struct crypto_comp *);
357 if (!tfms)
358 goto error;
359
360 for_each_possible_cpu(cpu) {
361 struct crypto_comp *tfm = crypto_alloc_comp(alg_name, 0,
362 CRYPTO_ALG_ASYNC);
363 if (IS_ERR(tfm))
364 goto error;
365 *per_cpu_ptr(tfms, cpu) = tfm;
366 }
367
368 return tfms;
369
370error:
371 ipcomp6_free_tfms(tfms);
372 return NULL;
373}
374
375static void ipcomp6_free_data(struct ipcomp_data *ipcd)
376{
377 if (ipcd->tfms)
378 ipcomp6_free_tfms(ipcd->tfms);
379 ipcomp6_free_scratches();
380}
381
382static void ipcomp6_destroy(struct xfrm_state *x)
383{
384 struct ipcomp_data *ipcd = x->data;
385 if (!ipcd)
386 return;
387 xfrm_state_delete_tunnel(x);
388 mutex_lock(&ipcomp6_resource_mutex);
389 ipcomp6_free_data(ipcd);
390 mutex_unlock(&ipcomp6_resource_mutex);
391 kfree(ipcd);
392
393 xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr);
394}
395
396static int ipcomp6_init_state(struct xfrm_state *x) 135static int ipcomp6_init_state(struct xfrm_state *x)
397{ 136{
398 int err; 137 int err;
399 struct ipcomp_data *ipcd; 138 struct ipcomp_data *ipcd;
400 struct xfrm_algo_desc *calg_desc; 139 struct xfrm_algo_desc *calg_desc;
401 140
402 err = -EINVAL;
403 if (!x->calg)
404 goto out;
405
406 if (x->encap)
407 goto out;
408
409 x->props.header_len = 0; 141 x->props.header_len = 0;
410 switch (x->props.mode) { 142 switch (x->props.mode) {
411 case XFRM_MODE_TRANSPORT: 143 case XFRM_MODE_TRANSPORT:
@@ -417,39 +149,21 @@ static int ipcomp6_init_state(struct xfrm_state *x)
417 goto out; 149 goto out;
418 } 150 }
419 151
420 err = -ENOMEM; 152 err = ipcomp_init_state(x);
421 ipcd = kzalloc(sizeof(*ipcd), GFP_KERNEL); 153 if (err)
422 if (!ipcd)
423 goto out; 154 goto out;
424 155
425 mutex_lock(&ipcomp6_resource_mutex);
426 if (!ipcomp6_alloc_scratches())
427 goto error;
428
429 ipcd->tfms = ipcomp6_alloc_tfms(x->calg->alg_name);
430 if (!ipcd->tfms)
431 goto error;
432 mutex_unlock(&ipcomp6_resource_mutex);
433
434 if (x->props.mode == XFRM_MODE_TUNNEL) { 156 if (x->props.mode == XFRM_MODE_TUNNEL) {
435 err = ipcomp6_tunnel_attach(x); 157 err = ipcomp6_tunnel_attach(x);
436 if (err) 158 if (err)
437 goto error_tunnel; 159 goto error_tunnel;
438 } 160 }
439 161
440 calg_desc = xfrm_calg_get_byname(x->calg->alg_name, 0);
441 BUG_ON(!calg_desc);
442 ipcd->threshold = calg_desc->uinfo.comp.threshold;
443 x->data = ipcd;
444 err = 0; 162 err = 0;
445out: 163out:
446 return err; 164 return err;
447error_tunnel: 165error_tunnel:
448 mutex_lock(&ipcomp6_resource_mutex); 166 ipcomp_destroy(x);
449error:
450 ipcomp6_free_data(ipcd);
451 mutex_unlock(&ipcomp6_resource_mutex);
452 kfree(ipcd);
453 167
454 goto out; 168 goto out;
455} 169}
@@ -460,9 +174,9 @@ static const struct xfrm_type ipcomp6_type =
460 .owner = THIS_MODULE, 174 .owner = THIS_MODULE,
461 .proto = IPPROTO_COMP, 175 .proto = IPPROTO_COMP,
462 .init_state = ipcomp6_init_state, 176 .init_state = ipcomp6_init_state,
463 .destructor = ipcomp6_destroy, 177 .destructor = ipcomp_destroy,
464 .input = ipcomp6_input, 178 .input = ipcomp_input,
465 .output = ipcomp6_output, 179 .output = ipcomp_output,
466 .hdr_offset = xfrm6_find_1stfragopt, 180 .hdr_offset = xfrm6_find_1stfragopt,
467}; 181};
468 182
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index 689dec899c57..0cfcce7b18d8 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -213,7 +213,7 @@ config IP6_NF_SECURITY
213 tristate "Security table" 213 tristate "Security table"
214 depends on IP6_NF_IPTABLES 214 depends on IP6_NF_IPTABLES
215 depends on SECURITY 215 depends on SECURITY
216 default m if NETFILTER_ADVANCED=n 216 depends on NETFILTER_ADVANCED
217 help 217 help
218 This option adds a `security' table to iptables, for use 218 This option adds a `security' table to iptables, for use
219 with Mandatory Access Control (MAC) policy. 219 with Mandatory Access Control (MAC) policy.
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 4ac7e3a8c253..43abd4d27ea6 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -736,9 +736,9 @@ static void shutdown_scheduler_queue(struct net_device *dev,
736 dev_queue->qdisc = qdisc_default; 736 dev_queue->qdisc = qdisc_default;
737 dev_queue->qdisc_sleeping = qdisc_default; 737 dev_queue->qdisc_sleeping = qdisc_default;
738 738
739 spin_lock(root_lock); 739 spin_lock_bh(root_lock);
740 qdisc_destroy(qdisc); 740 qdisc_destroy(qdisc);
741 spin_unlock(root_lock); 741 spin_unlock_bh(root_lock);
742 } 742 }
743} 743}
744 744
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 8589da666568..73f53844ce97 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -536,7 +536,14 @@ static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb)
536 536
537 opt.limit = q->limit; 537 opt.limit = q->limit;
538 opt.divisor = SFQ_HASH_DIVISOR; 538 opt.divisor = SFQ_HASH_DIVISOR;
539 opt.flows = q->limit; 539 opt.flows = 0;
540 if (q->tail != SFQ_DEPTH) {
541 unsigned int i;
542
543 for (i = 0; i < SFQ_HASH_DIVISOR; i++)
544 if (q->ht[i] != SFQ_DEPTH)
545 opt.flows++;
546 }
540 547
541 NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); 548 NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
542 549
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 79bece16aede..dbb79adf8f3c 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -3910,7 +3910,7 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval
3910 goto out; 3910 goto out;
3911 3911
3912 /* Map the socket to an unused fd that can be returned to the user. */ 3912 /* Map the socket to an unused fd that can be returned to the user. */
3913 retval = sock_map_fd(newsock); 3913 retval = sock_map_fd(newsock, 0);
3914 if (retval < 0) { 3914 if (retval < 0) {
3915 sock_release(newsock); 3915 sock_release(newsock);
3916 goto out; 3916 goto out;
diff --git a/net/socket.c b/net/socket.c
index 1ba57d888981..1310a82cbba7 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -63,11 +63,13 @@
63#include <linux/file.h> 63#include <linux/file.h>
64#include <linux/net.h> 64#include <linux/net.h>
65#include <linux/interrupt.h> 65#include <linux/interrupt.h>
66#include <linux/thread_info.h>
66#include <linux/rcupdate.h> 67#include <linux/rcupdate.h>
67#include <linux/netdevice.h> 68#include <linux/netdevice.h>
68#include <linux/proc_fs.h> 69#include <linux/proc_fs.h>
69#include <linux/seq_file.h> 70#include <linux/seq_file.h>
70#include <linux/mutex.h> 71#include <linux/mutex.h>
72#include <linux/thread_info.h>
71#include <linux/wanrouter.h> 73#include <linux/wanrouter.h>
72#include <linux/if_bridge.h> 74#include <linux/if_bridge.h>
73#include <linux/if_frad.h> 75#include <linux/if_frad.h>
@@ -349,11 +351,11 @@ static struct dentry_operations sockfs_dentry_operations = {
349 * but we take care of internal coherence yet. 351 * but we take care of internal coherence yet.
350 */ 352 */
351 353
352static int sock_alloc_fd(struct file **filep) 354static int sock_alloc_fd(struct file **filep, int flags)
353{ 355{
354 int fd; 356 int fd;
355 357
356 fd = get_unused_fd(); 358 fd = get_unused_fd_flags(flags);
357 if (likely(fd >= 0)) { 359 if (likely(fd >= 0)) {
358 struct file *file = get_empty_filp(); 360 struct file *file = get_empty_filp();
359 361
@@ -367,7 +369,7 @@ static int sock_alloc_fd(struct file **filep)
367 return fd; 369 return fd;
368} 370}
369 371
370static int sock_attach_fd(struct socket *sock, struct file *file) 372static int sock_attach_fd(struct socket *sock, struct file *file, int flags)
371{ 373{
372 struct dentry *dentry; 374 struct dentry *dentry;
373 struct qstr name = { .name = "" }; 375 struct qstr name = { .name = "" };
@@ -389,20 +391,20 @@ static int sock_attach_fd(struct socket *sock, struct file *file)
389 init_file(file, sock_mnt, dentry, FMODE_READ | FMODE_WRITE, 391 init_file(file, sock_mnt, dentry, FMODE_READ | FMODE_WRITE,
390 &socket_file_ops); 392 &socket_file_ops);
391 SOCK_INODE(sock)->i_fop = &socket_file_ops; 393 SOCK_INODE(sock)->i_fop = &socket_file_ops;
392 file->f_flags = O_RDWR; 394 file->f_flags = O_RDWR | (flags & O_NONBLOCK);
393 file->f_pos = 0; 395 file->f_pos = 0;
394 file->private_data = sock; 396 file->private_data = sock;
395 397
396 return 0; 398 return 0;
397} 399}
398 400
399int sock_map_fd(struct socket *sock) 401int sock_map_fd(struct socket *sock, int flags)
400{ 402{
401 struct file *newfile; 403 struct file *newfile;
402 int fd = sock_alloc_fd(&newfile); 404 int fd = sock_alloc_fd(&newfile, flags);
403 405
404 if (likely(fd >= 0)) { 406 if (likely(fd >= 0)) {
405 int err = sock_attach_fd(sock, newfile); 407 int err = sock_attach_fd(sock, newfile, flags);
406 408
407 if (unlikely(err < 0)) { 409 if (unlikely(err < 0)) {
408 put_filp(newfile); 410 put_filp(newfile);
@@ -1218,12 +1220,27 @@ asmlinkage long sys_socket(int family, int type, int protocol)
1218{ 1220{
1219 int retval; 1221 int retval;
1220 struct socket *sock; 1222 struct socket *sock;
1223 int flags;
1224
1225 /* Check the SOCK_* constants for consistency. */
1226 BUILD_BUG_ON(SOCK_CLOEXEC != O_CLOEXEC);
1227 BUILD_BUG_ON((SOCK_MAX | SOCK_TYPE_MASK) != SOCK_TYPE_MASK);
1228 BUILD_BUG_ON(SOCK_CLOEXEC & SOCK_TYPE_MASK);
1229 BUILD_BUG_ON(SOCK_NONBLOCK & SOCK_TYPE_MASK);
1230
1231 flags = type & ~SOCK_TYPE_MASK;
1232 if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1233 return -EINVAL;
1234 type &= SOCK_TYPE_MASK;
1235
1236 if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
1237 flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
1221 1238
1222 retval = sock_create(family, type, protocol, &sock); 1239 retval = sock_create(family, type, protocol, &sock);
1223 if (retval < 0) 1240 if (retval < 0)
1224 goto out; 1241 goto out;
1225 1242
1226 retval = sock_map_fd(sock); 1243 retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));
1227 if (retval < 0) 1244 if (retval < 0)
1228 goto out_release; 1245 goto out_release;
1229 1246
@@ -1246,6 +1263,15 @@ asmlinkage long sys_socketpair(int family, int type, int protocol,
1246 struct socket *sock1, *sock2; 1263 struct socket *sock1, *sock2;
1247 int fd1, fd2, err; 1264 int fd1, fd2, err;
1248 struct file *newfile1, *newfile2; 1265 struct file *newfile1, *newfile2;
1266 int flags;
1267
1268 flags = type & ~SOCK_TYPE_MASK;
1269 if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1270 return -EINVAL;
1271 type &= SOCK_TYPE_MASK;
1272
1273 if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
1274 flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
1249 1275
1250 /* 1276 /*
1251 * Obtain the first socket and check if the underlying protocol 1277 * Obtain the first socket and check if the underlying protocol
@@ -1264,13 +1290,13 @@ asmlinkage long sys_socketpair(int family, int type, int protocol,
1264 if (err < 0) 1290 if (err < 0)
1265 goto out_release_both; 1291 goto out_release_both;
1266 1292
1267 fd1 = sock_alloc_fd(&newfile1); 1293 fd1 = sock_alloc_fd(&newfile1, flags & O_CLOEXEC);
1268 if (unlikely(fd1 < 0)) { 1294 if (unlikely(fd1 < 0)) {
1269 err = fd1; 1295 err = fd1;
1270 goto out_release_both; 1296 goto out_release_both;
1271 } 1297 }
1272 1298
1273 fd2 = sock_alloc_fd(&newfile2); 1299 fd2 = sock_alloc_fd(&newfile2, flags & O_CLOEXEC);
1274 if (unlikely(fd2 < 0)) { 1300 if (unlikely(fd2 < 0)) {
1275 err = fd2; 1301 err = fd2;
1276 put_filp(newfile1); 1302 put_filp(newfile1);
@@ -1278,12 +1304,12 @@ asmlinkage long sys_socketpair(int family, int type, int protocol,
1278 goto out_release_both; 1304 goto out_release_both;
1279 } 1305 }
1280 1306
1281 err = sock_attach_fd(sock1, newfile1); 1307 err = sock_attach_fd(sock1, newfile1, flags & O_NONBLOCK);
1282 if (unlikely(err < 0)) { 1308 if (unlikely(err < 0)) {
1283 goto out_fd2; 1309 goto out_fd2;
1284 } 1310 }
1285 1311
1286 err = sock_attach_fd(sock2, newfile2); 1312 err = sock_attach_fd(sock2, newfile2, flags & O_NONBLOCK);
1287 if (unlikely(err < 0)) { 1313 if (unlikely(err < 0)) {
1288 fput(newfile1); 1314 fput(newfile1);
1289 goto out_fd1; 1315 goto out_fd1;
@@ -1401,14 +1427,20 @@ asmlinkage long sys_listen(int fd, int backlog)
1401 * clean when we restucture accept also. 1427 * clean when we restucture accept also.
1402 */ 1428 */
1403 1429
1404asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, 1430long do_accept(int fd, struct sockaddr __user *upeer_sockaddr,
1405 int __user *upeer_addrlen) 1431 int __user *upeer_addrlen, int flags)
1406{ 1432{
1407 struct socket *sock, *newsock; 1433 struct socket *sock, *newsock;
1408 struct file *newfile; 1434 struct file *newfile;
1409 int err, len, newfd, fput_needed; 1435 int err, len, newfd, fput_needed;
1410 struct sockaddr_storage address; 1436 struct sockaddr_storage address;
1411 1437
1438 if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1439 return -EINVAL;
1440
1441 if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
1442 flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
1443
1412 sock = sockfd_lookup_light(fd, &err, &fput_needed); 1444 sock = sockfd_lookup_light(fd, &err, &fput_needed);
1413 if (!sock) 1445 if (!sock)
1414 goto out; 1446 goto out;
@@ -1426,14 +1458,14 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr,
1426 */ 1458 */
1427 __module_get(newsock->ops->owner); 1459 __module_get(newsock->ops->owner);
1428 1460
1429 newfd = sock_alloc_fd(&newfile); 1461 newfd = sock_alloc_fd(&newfile, flags & O_CLOEXEC);
1430 if (unlikely(newfd < 0)) { 1462 if (unlikely(newfd < 0)) {
1431 err = newfd; 1463 err = newfd;
1432 sock_release(newsock); 1464 sock_release(newsock);
1433 goto out_put; 1465 goto out_put;
1434 } 1466 }
1435 1467
1436 err = sock_attach_fd(newsock, newfile); 1468 err = sock_attach_fd(newsock, newfile, flags & O_NONBLOCK);
1437 if (err < 0) 1469 if (err < 0)
1438 goto out_fd_simple; 1470 goto out_fd_simple;
1439 1471
@@ -1479,6 +1511,66 @@ out_fd:
1479 goto out_put; 1511 goto out_put;
1480} 1512}
1481 1513
1514#ifdef HAVE_SET_RESTORE_SIGMASK
1515asmlinkage long sys_paccept(int fd, struct sockaddr __user *upeer_sockaddr,
1516 int __user *upeer_addrlen,
1517 const sigset_t __user *sigmask,
1518 size_t sigsetsize, int flags)
1519{
1520 sigset_t ksigmask, sigsaved;
1521 int ret;
1522
1523 if (sigmask) {
1524 /* XXX: Don't preclude handling different sized sigset_t's. */
1525 if (sigsetsize != sizeof(sigset_t))
1526 return -EINVAL;
1527 if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask)))
1528 return -EFAULT;
1529
1530 sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP));
1531 sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
1532 }
1533
1534 ret = do_accept(fd, upeer_sockaddr, upeer_addrlen, flags);
1535
1536 if (ret < 0 && signal_pending(current)) {
1537 /*
1538 * Don't restore the signal mask yet. Let do_signal() deliver
1539 * the signal on the way back to userspace, before the signal
1540 * mask is restored.
1541 */
1542 if (sigmask) {
1543 memcpy(&current->saved_sigmask, &sigsaved,
1544 sizeof(sigsaved));
1545 set_restore_sigmask();
1546 }
1547 } else if (sigmask)
1548 sigprocmask(SIG_SETMASK, &sigsaved, NULL);
1549
1550 return ret;
1551}
1552#else
1553asmlinkage long sys_paccept(int fd, struct sockaddr __user *upeer_sockaddr,
1554 int __user *upeer_addrlen,
1555 const sigset_t __user *sigmask,
1556 size_t sigsetsize, int flags)
1557{
1558 /* The platform does not support restoring the signal mask in the
1559 * return path. So we do not allow using paccept() with a signal
1560 * mask. */
1561 if (sigmask)
1562 return -EINVAL;
1563
1564 return do_accept(fd, upeer_sockaddr, upeer_addrlen, flags);
1565}
1566#endif
1567
1568asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr,
1569 int __user *upeer_addrlen)
1570{
1571 return do_accept(fd, upeer_sockaddr, upeer_addrlen, 0);
1572}
1573
1482/* 1574/*
1483 * Attempt to connect to a socket with the server address. The address 1575 * Attempt to connect to a socket with the server address. The address
1484 * is in user space so we verify it is OK and move it to kernel space. 1576 * is in user space so we verify it is OK and move it to kernel space.
@@ -1999,10 +2091,11 @@ out:
1999 2091
2000/* Argument list sizes for sys_socketcall */ 2092/* Argument list sizes for sys_socketcall */
2001#define AL(x) ((x) * sizeof(unsigned long)) 2093#define AL(x) ((x) * sizeof(unsigned long))
2002static const unsigned char nargs[18]={ 2094static const unsigned char nargs[19]={
2003 AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), 2095 AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
2004 AL(3),AL(3),AL(4),AL(4),AL(4),AL(6), 2096 AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
2005 AL(6),AL(2),AL(5),AL(5),AL(3),AL(3) 2097 AL(6),AL(2),AL(5),AL(5),AL(3),AL(3),
2098 AL(6)
2006}; 2099};
2007 2100
2008#undef AL 2101#undef AL
@@ -2021,7 +2114,7 @@ asmlinkage long sys_socketcall(int call, unsigned long __user *args)
2021 unsigned long a0, a1; 2114 unsigned long a0, a1;
2022 int err; 2115 int err;
2023 2116
2024 if (call < 1 || call > SYS_RECVMSG) 2117 if (call < 1 || call > SYS_PACCEPT)
2025 return -EINVAL; 2118 return -EINVAL;
2026 2119
2027 /* copy_from_user should be SMP safe. */ 2120 /* copy_from_user should be SMP safe. */
@@ -2050,8 +2143,8 @@ asmlinkage long sys_socketcall(int call, unsigned long __user *args)
2050 break; 2143 break;
2051 case SYS_ACCEPT: 2144 case SYS_ACCEPT:
2052 err = 2145 err =
2053 sys_accept(a0, (struct sockaddr __user *)a1, 2146 do_accept(a0, (struct sockaddr __user *)a1,
2054 (int __user *)a[2]); 2147 (int __user *)a[2], 0);
2055 break; 2148 break;
2056 case SYS_GETSOCKNAME: 2149 case SYS_GETSOCKNAME:
2057 err = 2150 err =
@@ -2098,6 +2191,13 @@ asmlinkage long sys_socketcall(int call, unsigned long __user *args)
2098 case SYS_RECVMSG: 2191 case SYS_RECVMSG:
2099 err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]); 2192 err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]);
2100 break; 2193 break;
2194 case SYS_PACCEPT:
2195 err =
2196 sys_paccept(a0, (struct sockaddr __user *)a1,
2197 (int __user *)a[2],
2198 (const sigset_t __user *) a[3],
2199 a[4], a[5]);
2200 break;
2101 default: 2201 default:
2102 err = -EINVAL; 2202 err = -EINVAL;
2103 break; 2203 break;
diff --git a/net/sysctl_net.c b/net/sysctl_net.c
index 007c1a6708ee..63ada437fc2f 100644
--- a/net/sysctl_net.c
+++ b/net/sysctl_net.c
@@ -35,8 +35,22 @@ net_ctl_header_lookup(struct ctl_table_root *root, struct nsproxy *namespaces)
35 return &namespaces->net_ns->sysctl_table_headers; 35 return &namespaces->net_ns->sysctl_table_headers;
36} 36}
37 37
38/* Return standard mode bits for table entry. */
39static int net_ctl_permissions(struct ctl_table_root *root,
40 struct nsproxy *nsproxy,
41 struct ctl_table *table)
42{
43 /* Allow network administrator to have same access as root. */
44 if (capable(CAP_NET_ADMIN)) {
45 int mode = (table->mode >> 6) & 7;
46 return (mode << 6) | (mode << 3) | mode;
47 }
48 return table->mode;
49}
50
38static struct ctl_table_root net_sysctl_root = { 51static struct ctl_table_root net_sysctl_root = {
39 .lookup = net_ctl_header_lookup, 52 .lookup = net_ctl_header_lookup,
53 .permissions = net_ctl_permissions,
40}; 54};
41 55
42static LIST_HEAD(net_sysctl_ro_tables); 56static LIST_HEAD(net_sysctl_ro_tables);
diff --git a/net/xfrm/Kconfig b/net/xfrm/Kconfig
index 9201ef8ad90e..6d081674515f 100644
--- a/net/xfrm/Kconfig
+++ b/net/xfrm/Kconfig
@@ -46,6 +46,12 @@ config XFRM_STATISTICS
46 46
47 If unsure, say N. 47 If unsure, say N.
48 48
49config XFRM_IPCOMP
50 tristate
51 select XFRM
52 select CRYPTO
53 select CRYPTO_DEFLATE
54
49config NET_KEY 55config NET_KEY
50 tristate "PF_KEY sockets" 56 tristate "PF_KEY sockets"
51 select XFRM 57 select XFRM
diff --git a/net/xfrm/Makefile b/net/xfrm/Makefile
index 332cfb0ff566..0f439a72ccab 100644
--- a/net/xfrm/Makefile
+++ b/net/xfrm/Makefile
@@ -6,4 +6,5 @@ obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_hash.o \
6 xfrm_input.o xfrm_output.o xfrm_algo.o 6 xfrm_input.o xfrm_output.o xfrm_algo.o
7obj-$(CONFIG_XFRM_STATISTICS) += xfrm_proc.o 7obj-$(CONFIG_XFRM_STATISTICS) += xfrm_proc.o
8obj-$(CONFIG_XFRM_USER) += xfrm_user.o 8obj-$(CONFIG_XFRM_USER) += xfrm_user.o
9obj-$(CONFIG_XFRM_IPCOMP) += xfrm_ipcomp.o
9 10
diff --git a/net/xfrm/xfrm_ipcomp.c b/net/xfrm/xfrm_ipcomp.c
new file mode 100644
index 000000000000..800f669083fb
--- /dev/null
+++ b/net/xfrm/xfrm_ipcomp.c
@@ -0,0 +1,385 @@
1/*
2 * IP Payload Compression Protocol (IPComp) - RFC3173.
3 *
4 * Copyright (c) 2003 James Morris <jmorris@intercode.com.au>
5 * Copyright (c) 2003-2008 Herbert Xu <herbert@gondor.apana.org.au>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * Todo:
13 * - Tunable compression parameters.
14 * - Compression stats.
15 * - Adaptive compression.
16 */
17
18#include <linux/crypto.h>
19#include <linux/err.h>
20#include <linux/gfp.h>
21#include <linux/list.h>
22#include <linux/module.h>
23#include <linux/mutex.h>
24#include <linux/percpu.h>
25#include <linux/rtnetlink.h>
26#include <linux/smp.h>
27#include <linux/vmalloc.h>
28#include <net/ip.h>
29#include <net/ipcomp.h>
30#include <net/xfrm.h>
31
32struct ipcomp_tfms {
33 struct list_head list;
34 struct crypto_comp **tfms;
35 int users;
36};
37
38static DEFINE_MUTEX(ipcomp_resource_mutex);
39static void **ipcomp_scratches;
40static int ipcomp_scratch_users;
41static LIST_HEAD(ipcomp_tfms_list);
42
43static int ipcomp_decompress(struct xfrm_state *x, struct sk_buff *skb)
44{
45 struct ipcomp_data *ipcd = x->data;
46 const int plen = skb->len;
47 int dlen = IPCOMP_SCRATCH_SIZE;
48 const u8 *start = skb->data;
49 const int cpu = get_cpu();
50 u8 *scratch = *per_cpu_ptr(ipcomp_scratches, cpu);
51 struct crypto_comp *tfm = *per_cpu_ptr(ipcd->tfms, cpu);
52 int err = crypto_comp_decompress(tfm, start, plen, scratch, &dlen);
53 int len;
54
55 if (err)
56 goto out;
57
58 if (dlen < (plen + sizeof(struct ip_comp_hdr))) {
59 err = -EINVAL;
60 goto out;
61 }
62
63 len = dlen - plen;
64 if (len > skb_tailroom(skb))
65 len = skb_tailroom(skb);
66
67 skb->truesize += len;
68 __skb_put(skb, len);
69
70 len += plen;
71 skb_copy_to_linear_data(skb, scratch, len);
72
73 while ((scratch += len, dlen -= len) > 0) {
74 skb_frag_t *frag;
75
76 err = -EMSGSIZE;
77 if (WARN_ON(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS))
78 goto out;
79
80 frag = skb_shinfo(skb)->frags + skb_shinfo(skb)->nr_frags;
81 frag->page = alloc_page(GFP_ATOMIC);
82
83 err = -ENOMEM;
84 if (!frag->page)
85 goto out;
86
87 len = PAGE_SIZE;
88 if (dlen < len)
89 len = dlen;
90
91 memcpy(page_address(frag->page), scratch, len);
92
93 frag->page_offset = 0;
94 frag->size = len;
95 skb->truesize += len;
96 skb->data_len += len;
97 skb->len += len;
98
99 skb_shinfo(skb)->nr_frags++;
100 }
101
102 err = 0;
103
104out:
105 put_cpu();
106 return err;
107}
108
109int ipcomp_input(struct xfrm_state *x, struct sk_buff *skb)
110{
111 int nexthdr;
112 int err = -ENOMEM;
113 struct ip_comp_hdr *ipch;
114
115 if (skb_linearize_cow(skb))
116 goto out;
117
118 skb->ip_summed = CHECKSUM_NONE;
119
120 /* Remove ipcomp header and decompress original payload */
121 ipch = (void *)skb->data;
122 nexthdr = ipch->nexthdr;
123
124 skb->transport_header = skb->network_header + sizeof(*ipch);
125 __skb_pull(skb, sizeof(*ipch));
126 err = ipcomp_decompress(x, skb);
127 if (err)
128 goto out;
129
130 err = nexthdr;
131
132out:
133 return err;
134}
135EXPORT_SYMBOL_GPL(ipcomp_input);
136
137static int ipcomp_compress(struct xfrm_state *x, struct sk_buff *skb)
138{
139 struct ipcomp_data *ipcd = x->data;
140 const int plen = skb->len;
141 int dlen = IPCOMP_SCRATCH_SIZE;
142 u8 *start = skb->data;
143 const int cpu = get_cpu();
144 u8 *scratch = *per_cpu_ptr(ipcomp_scratches, cpu);
145 struct crypto_comp *tfm = *per_cpu_ptr(ipcd->tfms, cpu);
146 int err;
147
148 local_bh_disable();
149 err = crypto_comp_compress(tfm, start, plen, scratch, &dlen);
150 local_bh_enable();
151 if (err)
152 goto out;
153
154 if ((dlen + sizeof(struct ip_comp_hdr)) >= plen) {
155 err = -EMSGSIZE;
156 goto out;
157 }
158
159 memcpy(start + sizeof(struct ip_comp_hdr), scratch, dlen);
160 put_cpu();
161
162 pskb_trim(skb, dlen + sizeof(struct ip_comp_hdr));
163 return 0;
164
165out:
166 put_cpu();
167 return err;
168}
169
170int ipcomp_output(struct xfrm_state *x, struct sk_buff *skb)
171{
172 int err;
173 struct ip_comp_hdr *ipch;
174 struct ipcomp_data *ipcd = x->data;
175
176 if (skb->len < ipcd->threshold) {
177 /* Don't bother compressing */
178 goto out_ok;
179 }
180
181 if (skb_linearize_cow(skb))
182 goto out_ok;
183
184 err = ipcomp_compress(x, skb);
185
186 if (err) {
187 goto out_ok;
188 }
189
190 /* Install ipcomp header, convert into ipcomp datagram. */
191 ipch = ip_comp_hdr(skb);
192 ipch->nexthdr = *skb_mac_header(skb);
193 ipch->flags = 0;
194 ipch->cpi = htons((u16 )ntohl(x->id.spi));
195 *skb_mac_header(skb) = IPPROTO_COMP;
196out_ok:
197 skb_push(skb, -skb_network_offset(skb));
198 return 0;
199}
200EXPORT_SYMBOL_GPL(ipcomp_output);
201
202static void ipcomp_free_scratches(void)
203{
204 int i;
205 void **scratches;
206
207 if (--ipcomp_scratch_users)
208 return;
209
210 scratches = ipcomp_scratches;
211 if (!scratches)
212 return;
213
214 for_each_possible_cpu(i)
215 vfree(*per_cpu_ptr(scratches, i));
216
217 free_percpu(scratches);
218}
219
220static void **ipcomp_alloc_scratches(void)
221{
222 int i;
223 void **scratches;
224
225 if (ipcomp_scratch_users++)
226 return ipcomp_scratches;
227
228 scratches = alloc_percpu(void *);
229 if (!scratches)
230 return NULL;
231
232 ipcomp_scratches = scratches;
233
234 for_each_possible_cpu(i) {
235 void *scratch = vmalloc(IPCOMP_SCRATCH_SIZE);
236 if (!scratch)
237 return NULL;
238 *per_cpu_ptr(scratches, i) = scratch;
239 }
240
241 return scratches;
242}
243
244static void ipcomp_free_tfms(struct crypto_comp **tfms)
245{
246 struct ipcomp_tfms *pos;
247 int cpu;
248
249 list_for_each_entry(pos, &ipcomp_tfms_list, list) {
250 if (pos->tfms == tfms)
251 break;
252 }
253
254 BUG_TRAP(pos);
255
256 if (--pos->users)
257 return;
258
259 list_del(&pos->list);
260 kfree(pos);
261
262 if (!tfms)
263 return;
264
265 for_each_possible_cpu(cpu) {
266 struct crypto_comp *tfm = *per_cpu_ptr(tfms, cpu);
267 crypto_free_comp(tfm);
268 }
269 free_percpu(tfms);
270}
271
272static struct crypto_comp **ipcomp_alloc_tfms(const char *alg_name)
273{
274 struct ipcomp_tfms *pos;
275 struct crypto_comp **tfms;
276 int cpu;
277
278 /* This can be any valid CPU ID so we don't need locking. */
279 cpu = raw_smp_processor_id();
280
281 list_for_each_entry(pos, &ipcomp_tfms_list, list) {
282 struct crypto_comp *tfm;
283
284 tfms = pos->tfms;
285 tfm = *per_cpu_ptr(tfms, cpu);
286
287 if (!strcmp(crypto_comp_name(tfm), alg_name)) {
288 pos->users++;
289 return tfms;
290 }
291 }
292
293 pos = kmalloc(sizeof(*pos), GFP_KERNEL);
294 if (!pos)
295 return NULL;
296
297 pos->users = 1;
298 INIT_LIST_HEAD(&pos->list);
299 list_add(&pos->list, &ipcomp_tfms_list);
300
301 pos->tfms = tfms = alloc_percpu(struct crypto_comp *);
302 if (!tfms)
303 goto error;
304
305 for_each_possible_cpu(cpu) {
306 struct crypto_comp *tfm = crypto_alloc_comp(alg_name, 0,
307 CRYPTO_ALG_ASYNC);
308 if (IS_ERR(tfm))
309 goto error;
310 *per_cpu_ptr(tfms, cpu) = tfm;
311 }
312
313 return tfms;
314
315error:
316 ipcomp_free_tfms(tfms);
317 return NULL;
318}
319
320static void ipcomp_free_data(struct ipcomp_data *ipcd)
321{
322 if (ipcd->tfms)
323 ipcomp_free_tfms(ipcd->tfms);
324 ipcomp_free_scratches();
325}
326
327void ipcomp_destroy(struct xfrm_state *x)
328{
329 struct ipcomp_data *ipcd = x->data;
330 if (!ipcd)
331 return;
332 xfrm_state_delete_tunnel(x);
333 mutex_lock(&ipcomp_resource_mutex);
334 ipcomp_free_data(ipcd);
335 mutex_unlock(&ipcomp_resource_mutex);
336 kfree(ipcd);
337}
338EXPORT_SYMBOL_GPL(ipcomp_destroy);
339
340int ipcomp_init_state(struct xfrm_state *x)
341{
342 int err;
343 struct ipcomp_data *ipcd;
344 struct xfrm_algo_desc *calg_desc;
345
346 err = -EINVAL;
347 if (!x->calg)
348 goto out;
349
350 if (x->encap)
351 goto out;
352
353 err = -ENOMEM;
354 ipcd = kzalloc(sizeof(*ipcd), GFP_KERNEL);
355 if (!ipcd)
356 goto out;
357
358 mutex_lock(&ipcomp_resource_mutex);
359 if (!ipcomp_alloc_scratches())
360 goto error;
361
362 ipcd->tfms = ipcomp_alloc_tfms(x->calg->alg_name);
363 if (!ipcd->tfms)
364 goto error;
365 mutex_unlock(&ipcomp_resource_mutex);
366
367 calg_desc = xfrm_calg_get_byname(x->calg->alg_name, 0);
368 BUG_ON(!calg_desc);
369 ipcd->threshold = calg_desc->uinfo.comp.threshold;
370 x->data = ipcd;
371 err = 0;
372out:
373 return err;
374
375error:
376 ipcomp_free_data(ipcd);
377 mutex_unlock(&ipcomp_resource_mutex);
378 kfree(ipcd);
379 goto out;
380}
381EXPORT_SYMBOL_GPL(ipcomp_init_state);
382
383MODULE_LICENSE("GPL");
384MODULE_DESCRIPTION("IP Payload Compression Protocol (IPComp) - RFC3173");
385MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");