diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/Kconfig | 9 | ||||
-rw-r--r-- | net/ipv4/Makefile | 1 | ||||
-rw-r--r-- | net/ipv4/esp4.c | 26 | ||||
-rw-r--r-- | net/ipv4/ipcomp.c | 5 | ||||
-rw-r--r-- | net/ipv4/ipvs/ip_vs_core.c | 10 | ||||
-rw-r--r-- | net/ipv4/netfilter.c | 9 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_nat_standalone.c | 3 | ||||
-rw-r--r-- | net/ipv4/netfilter/ipt_REJECT.c | 97 | ||||
-rw-r--r-- | net/ipv4/netfilter/iptable_mangle.c | 3 | ||||
-rw-r--r-- | net/ipv4/tcp_input.c | 2 | ||||
-rw-r--r-- | net/ipv4/udp.c | 2 | ||||
-rw-r--r-- | net/ipv4/xfrm4_mode_beet.c | 139 |
12 files changed, 214 insertions, 92 deletions
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index d172a9804448..5572071af735 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig | |||
@@ -434,6 +434,15 @@ config INET_XFRM_MODE_TUNNEL | |||
434 | 434 | ||
435 | If unsure, say Y. | 435 | If unsure, say Y. |
436 | 436 | ||
437 | config INET_XFRM_MODE_BEET | ||
438 | tristate "IP: IPsec BEET mode" | ||
439 | default y | ||
440 | select XFRM | ||
441 | ---help--- | ||
442 | Support for IPsec BEET mode. | ||
443 | |||
444 | If unsure, say Y. | ||
445 | |||
437 | config INET_DIAG | 446 | config INET_DIAG |
438 | tristate "INET: socket monitoring interface" | 447 | tristate "INET: socket monitoring interface" |
439 | default y | 448 | default y |
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index f66049e28aeb..15645c51520c 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile | |||
@@ -23,6 +23,7 @@ obj-$(CONFIG_INET_AH) += ah4.o | |||
23 | obj-$(CONFIG_INET_ESP) += esp4.o | 23 | obj-$(CONFIG_INET_ESP) += esp4.o |
24 | obj-$(CONFIG_INET_IPCOMP) += ipcomp.o | 24 | obj-$(CONFIG_INET_IPCOMP) += ipcomp.o |
25 | obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o | 25 | obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o |
26 | obj-$(CONFIG_INET_XFRM_MODE_BEET) += xfrm4_mode_beet.o | ||
26 | obj-$(CONFIG_INET_TUNNEL) += tunnel4.o | 27 | obj-$(CONFIG_INET_TUNNEL) += tunnel4.o |
27 | obj-$(CONFIG_INET_XFRM_MODE_TRANSPORT) += xfrm4_mode_transport.o | 28 | obj-$(CONFIG_INET_XFRM_MODE_TRANSPORT) += xfrm4_mode_transport.o |
28 | obj-$(CONFIG_INET_XFRM_MODE_TUNNEL) += xfrm4_mode_tunnel.o | 29 | obj-$(CONFIG_INET_XFRM_MODE_TUNNEL) += xfrm4_mode_tunnel.o |
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 13b29360d102..b5c205b57669 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c | |||
@@ -253,7 +253,8 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) | |||
253 | * as per draft-ietf-ipsec-udp-encaps-06, | 253 | * as per draft-ietf-ipsec-udp-encaps-06, |
254 | * section 3.1.2 | 254 | * section 3.1.2 |
255 | */ | 255 | */ |
256 | if (x->props.mode == XFRM_MODE_TRANSPORT) | 256 | if (x->props.mode == XFRM_MODE_TRANSPORT || |
257 | x->props.mode == XFRM_MODE_BEET) | ||
257 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 258 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
258 | } | 259 | } |
259 | 260 | ||
@@ -271,17 +272,28 @@ static u32 esp4_get_max_size(struct xfrm_state *x, int mtu) | |||
271 | { | 272 | { |
272 | struct esp_data *esp = x->data; | 273 | struct esp_data *esp = x->data; |
273 | u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4); | 274 | u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4); |
274 | 275 | int enclen = 0; | |
275 | if (x->props.mode == XFRM_MODE_TUNNEL) { | 276 | |
276 | mtu = ALIGN(mtu + 2, blksize); | 277 | switch (x->props.mode) { |
277 | } else { | 278 | case XFRM_MODE_TUNNEL: |
278 | /* The worst case. */ | 279 | mtu = ALIGN(mtu +2, blksize); |
280 | break; | ||
281 | default: | ||
282 | case XFRM_MODE_TRANSPORT: | ||
283 | /* The worst case */ | ||
279 | mtu = ALIGN(mtu + 2, 4) + blksize - 4; | 284 | mtu = ALIGN(mtu + 2, 4) + blksize - 4; |
285 | break; | ||
286 | case XFRM_MODE_BEET: | ||
287 | /* The worst case. */ | ||
288 | enclen = IPV4_BEET_PHMAXLEN; | ||
289 | mtu = ALIGN(mtu + enclen + 2, blksize); | ||
290 | break; | ||
280 | } | 291 | } |
292 | |||
281 | if (esp->conf.padlen) | 293 | if (esp->conf.padlen) |
282 | mtu = ALIGN(mtu, esp->conf.padlen); | 294 | mtu = ALIGN(mtu, esp->conf.padlen); |
283 | 295 | ||
284 | return mtu + x->props.header_len + esp->auth.icv_trunc_len; | 296 | return mtu + x->props.header_len + esp->auth.icv_trunc_len - enclen; |
285 | } | 297 | } |
286 | 298 | ||
287 | static void esp4_err(struct sk_buff *skb, u32 info) | 299 | static void esp4_err(struct sk_buff *skb, u32 info) |
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index 2017d36024d4..3839b706142e 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c | |||
@@ -206,6 +206,7 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info) | |||
206 | static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x) | 206 | static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x) |
207 | { | 207 | { |
208 | struct xfrm_state *t; | 208 | struct xfrm_state *t; |
209 | u8 mode = XFRM_MODE_TUNNEL; | ||
209 | 210 | ||
210 | t = xfrm_state_alloc(); | 211 | t = xfrm_state_alloc(); |
211 | if (t == NULL) | 212 | if (t == NULL) |
@@ -216,7 +217,9 @@ static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x) | |||
216 | t->id.daddr.a4 = x->id.daddr.a4; | 217 | t->id.daddr.a4 = x->id.daddr.a4; |
217 | memcpy(&t->sel, &x->sel, sizeof(t->sel)); | 218 | memcpy(&t->sel, &x->sel, sizeof(t->sel)); |
218 | t->props.family = AF_INET; | 219 | t->props.family = AF_INET; |
219 | t->props.mode = XFRM_MODE_TUNNEL; | 220 | if (x->props.mode == XFRM_MODE_BEET) |
221 | mode = x->props.mode; | ||
222 | t->props.mode = mode; | ||
220 | t->props.saddr.a4 = x->props.saddr.a4; | 223 | t->props.saddr.a4 = x->props.saddr.a4; |
221 | t->props.flags = x->props.flags; | 224 | t->props.flags = x->props.flags; |
222 | 225 | ||
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c index 6dee03935f78..1445bb47fea4 100644 --- a/net/ipv4/ipvs/ip_vs_core.c +++ b/net/ipv4/ipvs/ip_vs_core.c | |||
@@ -813,6 +813,16 @@ ip_vs_out(unsigned int hooknum, struct sk_buff **pskb, | |||
813 | skb->nh.iph->saddr = cp->vaddr; | 813 | skb->nh.iph->saddr = cp->vaddr; |
814 | ip_send_check(skb->nh.iph); | 814 | ip_send_check(skb->nh.iph); |
815 | 815 | ||
816 | /* For policy routing, packets originating from this | ||
817 | * machine itself may be routed differently to packets | ||
818 | * passing through. We want this packet to be routed as | ||
819 | * if it came from this machine itself. So re-compute | ||
820 | * the routing information. | ||
821 | */ | ||
822 | if (ip_route_me_harder(pskb, RTN_LOCAL) != 0) | ||
823 | goto drop; | ||
824 | skb = *pskb; | ||
825 | |||
816 | IP_VS_DBG_PKT(10, pp, skb, 0, "After SNAT"); | 826 | IP_VS_DBG_PKT(10, pp, skb, 0, "After SNAT"); |
817 | 827 | ||
818 | ip_vs_out_stats(cp, skb); | 828 | ip_vs_out_stats(cp, skb); |
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index 5ac15379a0cf..e2005c6810a4 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c | |||
@@ -8,7 +8,7 @@ | |||
8 | #include <net/ip.h> | 8 | #include <net/ip.h> |
9 | 9 | ||
10 | /* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */ | 10 | /* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */ |
11 | int ip_route_me_harder(struct sk_buff **pskb) | 11 | int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type) |
12 | { | 12 | { |
13 | struct iphdr *iph = (*pskb)->nh.iph; | 13 | struct iphdr *iph = (*pskb)->nh.iph; |
14 | struct rtable *rt; | 14 | struct rtable *rt; |
@@ -16,10 +16,13 @@ int ip_route_me_harder(struct sk_buff **pskb) | |||
16 | struct dst_entry *odst; | 16 | struct dst_entry *odst; |
17 | unsigned int hh_len; | 17 | unsigned int hh_len; |
18 | 18 | ||
19 | if (addr_type == RTN_UNSPEC) | ||
20 | addr_type = inet_addr_type(iph->saddr); | ||
21 | |||
19 | /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause | 22 | /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause |
20 | * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook. | 23 | * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook. |
21 | */ | 24 | */ |
22 | if (inet_addr_type(iph->saddr) == RTN_LOCAL) { | 25 | if (addr_type == RTN_LOCAL) { |
23 | fl.nl_u.ip4_u.daddr = iph->daddr; | 26 | fl.nl_u.ip4_u.daddr = iph->daddr; |
24 | fl.nl_u.ip4_u.saddr = iph->saddr; | 27 | fl.nl_u.ip4_u.saddr = iph->saddr; |
25 | fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); | 28 | fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); |
@@ -156,7 +159,7 @@ static int nf_ip_reroute(struct sk_buff **pskb, const struct nf_info *info) | |||
156 | if (!(iph->tos == rt_info->tos | 159 | if (!(iph->tos == rt_info->tos |
157 | && iph->daddr == rt_info->daddr | 160 | && iph->daddr == rt_info->daddr |
158 | && iph->saddr == rt_info->saddr)) | 161 | && iph->saddr == rt_info->saddr)) |
159 | return ip_route_me_harder(pskb); | 162 | return ip_route_me_harder(pskb, RTN_UNSPEC); |
160 | } | 163 | } |
161 | return 0; | 164 | return 0; |
162 | } | 165 | } |
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index 021395b67463..d85d2de50449 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c | |||
@@ -265,7 +265,8 @@ ip_nat_local_fn(unsigned int hooknum, | |||
265 | ct->tuplehash[!dir].tuple.src.u.all | 265 | ct->tuplehash[!dir].tuple.src.u.all |
266 | #endif | 266 | #endif |
267 | ) | 267 | ) |
268 | return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP; | 268 | if (ip_route_me_harder(pskb, RTN_UNSPEC)) |
269 | ret = NF_DROP; | ||
269 | } | 270 | } |
270 | return ret; | 271 | return ret; |
271 | } | 272 | } |
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index fd0c05efed8a..ad0312d0e4fd 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c | |||
@@ -38,76 +38,16 @@ MODULE_DESCRIPTION("iptables REJECT target module"); | |||
38 | #define DEBUGP(format, args...) | 38 | #define DEBUGP(format, args...) |
39 | #endif | 39 | #endif |
40 | 40 | ||
41 | static inline struct rtable *route_reverse(struct sk_buff *skb, | ||
42 | struct tcphdr *tcph, int hook) | ||
43 | { | ||
44 | struct iphdr *iph = skb->nh.iph; | ||
45 | struct dst_entry *odst; | ||
46 | struct flowi fl = {}; | ||
47 | struct rtable *rt; | ||
48 | |||
49 | /* We don't require ip forwarding to be enabled to be able to | ||
50 | * send a RST reply for bridged traffic. */ | ||
51 | if (hook != NF_IP_FORWARD | ||
52 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
53 | || (skb->nf_bridge && skb->nf_bridge->mask & BRNF_BRIDGED) | ||
54 | #endif | ||
55 | ) { | ||
56 | fl.nl_u.ip4_u.daddr = iph->saddr; | ||
57 | if (hook == NF_IP_LOCAL_IN) | ||
58 | fl.nl_u.ip4_u.saddr = iph->daddr; | ||
59 | fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); | ||
60 | |||
61 | if (ip_route_output_key(&rt, &fl) != 0) | ||
62 | return NULL; | ||
63 | } else { | ||
64 | /* non-local src, find valid iif to satisfy | ||
65 | * rp-filter when calling ip_route_input. */ | ||
66 | fl.nl_u.ip4_u.daddr = iph->daddr; | ||
67 | if (ip_route_output_key(&rt, &fl) != 0) | ||
68 | return NULL; | ||
69 | |||
70 | odst = skb->dst; | ||
71 | if (ip_route_input(skb, iph->saddr, iph->daddr, | ||
72 | RT_TOS(iph->tos), rt->u.dst.dev) != 0) { | ||
73 | dst_release(&rt->u.dst); | ||
74 | return NULL; | ||
75 | } | ||
76 | dst_release(&rt->u.dst); | ||
77 | rt = (struct rtable *)skb->dst; | ||
78 | skb->dst = odst; | ||
79 | |||
80 | fl.nl_u.ip4_u.daddr = iph->saddr; | ||
81 | fl.nl_u.ip4_u.saddr = iph->daddr; | ||
82 | fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); | ||
83 | } | ||
84 | |||
85 | if (rt->u.dst.error) { | ||
86 | dst_release(&rt->u.dst); | ||
87 | return NULL; | ||
88 | } | ||
89 | |||
90 | fl.proto = IPPROTO_TCP; | ||
91 | fl.fl_ip_sport = tcph->dest; | ||
92 | fl.fl_ip_dport = tcph->source; | ||
93 | security_skb_classify_flow(skb, &fl); | ||
94 | |||
95 | xfrm_lookup((struct dst_entry **)&rt, &fl, NULL, 0); | ||
96 | |||
97 | return rt; | ||
98 | } | ||
99 | |||
100 | /* Send RST reply */ | 41 | /* Send RST reply */ |
101 | static void send_reset(struct sk_buff *oldskb, int hook) | 42 | static void send_reset(struct sk_buff *oldskb, int hook) |
102 | { | 43 | { |
103 | struct sk_buff *nskb; | 44 | struct sk_buff *nskb; |
104 | struct iphdr *iph = oldskb->nh.iph; | 45 | struct iphdr *iph = oldskb->nh.iph; |
105 | struct tcphdr _otcph, *oth, *tcph; | 46 | struct tcphdr _otcph, *oth, *tcph; |
106 | struct rtable *rt; | ||
107 | __be16 tmp_port; | 47 | __be16 tmp_port; |
108 | __be32 tmp_addr; | 48 | __be32 tmp_addr; |
109 | int needs_ack; | 49 | int needs_ack; |
110 | int hh_len; | 50 | unsigned int addr_type; |
111 | 51 | ||
112 | /* IP header checks: fragment. */ | 52 | /* IP header checks: fragment. */ |
113 | if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)) | 53 | if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)) |
@@ -126,23 +66,13 @@ static void send_reset(struct sk_buff *oldskb, int hook) | |||
126 | if (nf_ip_checksum(oldskb, hook, iph->ihl * 4, IPPROTO_TCP)) | 66 | if (nf_ip_checksum(oldskb, hook, iph->ihl * 4, IPPROTO_TCP)) |
127 | return; | 67 | return; |
128 | 68 | ||
129 | if ((rt = route_reverse(oldskb, oth, hook)) == NULL) | ||
130 | return; | ||
131 | |||
132 | hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); | ||
133 | |||
134 | /* We need a linear, writeable skb. We also need to expand | 69 | /* We need a linear, writeable skb. We also need to expand |
135 | headroom in case hh_len of incoming interface < hh_len of | 70 | headroom in case hh_len of incoming interface < hh_len of |
136 | outgoing interface */ | 71 | outgoing interface */ |
137 | nskb = skb_copy_expand(oldskb, hh_len, skb_tailroom(oldskb), | 72 | nskb = skb_copy_expand(oldskb, LL_MAX_HEADER, skb_tailroom(oldskb), |
138 | GFP_ATOMIC); | 73 | GFP_ATOMIC); |
139 | if (!nskb) { | 74 | if (!nskb) |
140 | dst_release(&rt->u.dst); | ||
141 | return; | 75 | return; |
142 | } | ||
143 | |||
144 | dst_release(nskb->dst); | ||
145 | nskb->dst = &rt->u.dst; | ||
146 | 76 | ||
147 | /* This packet will not be the same as the other: clear nf fields */ | 77 | /* This packet will not be the same as the other: clear nf fields */ |
148 | nf_reset(nskb); | 78 | nf_reset(nskb); |
@@ -184,6 +114,21 @@ static void send_reset(struct sk_buff *oldskb, int hook) | |||
184 | tcph->window = 0; | 114 | tcph->window = 0; |
185 | tcph->urg_ptr = 0; | 115 | tcph->urg_ptr = 0; |
186 | 116 | ||
117 | /* Set DF, id = 0 */ | ||
118 | nskb->nh.iph->frag_off = htons(IP_DF); | ||
119 | nskb->nh.iph->id = 0; | ||
120 | |||
121 | addr_type = RTN_UNSPEC; | ||
122 | if (hook != NF_IP_FORWARD | ||
123 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
124 | || (nskb->nf_bridge && nskb->nf_bridge->mask & BRNF_BRIDGED) | ||
125 | #endif | ||
126 | ) | ||
127 | addr_type = RTN_LOCAL; | ||
128 | |||
129 | if (ip_route_me_harder(&nskb, addr_type)) | ||
130 | goto free_nskb; | ||
131 | |||
187 | /* Adjust TCP checksum */ | 132 | /* Adjust TCP checksum */ |
188 | nskb->ip_summed = CHECKSUM_NONE; | 133 | nskb->ip_summed = CHECKSUM_NONE; |
189 | tcph->check = 0; | 134 | tcph->check = 0; |
@@ -192,12 +137,8 @@ static void send_reset(struct sk_buff *oldskb, int hook) | |||
192 | nskb->nh.iph->daddr, | 137 | nskb->nh.iph->daddr, |
193 | csum_partial((char *)tcph, | 138 | csum_partial((char *)tcph, |
194 | sizeof(struct tcphdr), 0)); | 139 | sizeof(struct tcphdr), 0)); |
195 | 140 | /* Adjust IP TTL */ | |
196 | /* Adjust IP TTL, DF */ | ||
197 | nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT); | 141 | nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT); |
198 | /* Set DF, id = 0 */ | ||
199 | nskb->nh.iph->frag_off = htons(IP_DF); | ||
200 | nskb->nh.iph->id = 0; | ||
201 | 142 | ||
202 | /* Adjust IP checksum */ | 143 | /* Adjust IP checksum */ |
203 | nskb->nh.iph->check = 0; | 144 | nskb->nh.iph->check = 0; |
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index e62ea2bb9c0a..b91f3582359b 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c | |||
@@ -157,7 +157,8 @@ ipt_local_hook(unsigned int hook, | |||
157 | || (*pskb)->nfmark != nfmark | 157 | || (*pskb)->nfmark != nfmark |
158 | #endif | 158 | #endif |
159 | || (*pskb)->nh.iph->tos != tos)) | 159 | || (*pskb)->nh.iph->tos != tos)) |
160 | return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP; | 160 | if (ip_route_me_harder(pskb, RTN_UNSPEC)) |
161 | ret = NF_DROP; | ||
161 | 162 | ||
162 | return ret; | 163 | return ret; |
163 | } | 164 | } |
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 3f884cea14ff..cf06accbe687 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -2259,7 +2259,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p) | |||
2259 | u32 pkts_acked = 0; | 2259 | u32 pkts_acked = 0; |
2260 | void (*rtt_sample)(struct sock *sk, u32 usrtt) | 2260 | void (*rtt_sample)(struct sock *sk, u32 usrtt) |
2261 | = icsk->icsk_ca_ops->rtt_sample; | 2261 | = icsk->icsk_ca_ops->rtt_sample; |
2262 | struct timeval tv; | 2262 | struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }; |
2263 | 2263 | ||
2264 | while ((skb = skb_peek(&sk->sk_write_queue)) && | 2264 | while ((skb = skb_peek(&sk->sk_write_queue)) && |
2265 | skb != sk->sk_send_head) { | 2265 | skb != sk->sk_send_head) { |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 6d6142f9c478..865d75214a9a 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -675,6 +675,8 @@ do_append_data: | |||
675 | udp_flush_pending_frames(sk); | 675 | udp_flush_pending_frames(sk); |
676 | else if (!corkreq) | 676 | else if (!corkreq) |
677 | err = udp_push_pending_frames(sk, up); | 677 | err = udp_push_pending_frames(sk, up); |
678 | else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) | ||
679 | up->pending = 0; | ||
678 | release_sock(sk); | 680 | release_sock(sk); |
679 | 681 | ||
680 | out: | 682 | out: |
diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c new file mode 100644 index 000000000000..89cf59ea7bbe --- /dev/null +++ b/net/ipv4/xfrm4_mode_beet.c | |||
@@ -0,0 +1,139 @@ | |||
1 | /* | ||
2 | * xfrm4_mode_beet.c - BEET mode encapsulation for IPv4. | ||
3 | * | ||
4 | * Copyright (c) 2006 Diego Beltrami <diego.beltrami@gmail.com> | ||
5 | * Miika Komu <miika@iki.fi> | ||
6 | * Herbert Xu <herbert@gondor.apana.org.au> | ||
7 | * Abhinav Pathak <abhinav.pathak@hiit.fi> | ||
8 | * Jeff Ahrenholz <ahrenholz@gmail.com> | ||
9 | */ | ||
10 | |||
11 | #include <linux/init.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | #include <linux/stringify.h> | ||
16 | #include <net/dst.h> | ||
17 | #include <net/ip.h> | ||
18 | #include <net/xfrm.h> | ||
19 | |||
20 | /* Add encapsulation header. | ||
21 | * | ||
22 | * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt. | ||
23 | * The following fields in it shall be filled in by x->type->output: | ||
24 | * tot_len | ||
25 | * check | ||
26 | * | ||
27 | * On exit, skb->h will be set to the start of the payload to be processed | ||
28 | * by x->type->output and skb->nh will be set to the top IP header. | ||
29 | */ | ||
30 | static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb) | ||
31 | { | ||
32 | struct iphdr *iph, *top_iph = NULL; | ||
33 | int hdrlen, optlen; | ||
34 | |||
35 | iph = skb->nh.iph; | ||
36 | skb->h.ipiph = iph; | ||
37 | |||
38 | hdrlen = 0; | ||
39 | optlen = iph->ihl * 4 - sizeof(*iph); | ||
40 | if (unlikely(optlen)) | ||
41 | hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4); | ||
42 | |||
43 | skb->nh.raw = skb_push(skb, x->props.header_len + hdrlen); | ||
44 | top_iph = skb->nh.iph; | ||
45 | hdrlen = iph->ihl * 4 - optlen; | ||
46 | skb->h.raw += hdrlen; | ||
47 | |||
48 | memmove(top_iph, iph, hdrlen); | ||
49 | if (unlikely(optlen)) { | ||
50 | struct ip_beet_phdr *ph; | ||
51 | |||
52 | BUG_ON(optlen < 0); | ||
53 | |||
54 | ph = (struct ip_beet_phdr *)skb->h.raw; | ||
55 | ph->padlen = 4 - (optlen & 4); | ||
56 | ph->hdrlen = (optlen + ph->padlen + sizeof(*ph)) / 8; | ||
57 | ph->nexthdr = top_iph->protocol; | ||
58 | |||
59 | top_iph->protocol = IPPROTO_BEETPH; | ||
60 | top_iph->ihl = sizeof(struct iphdr) / 4; | ||
61 | } | ||
62 | |||
63 | top_iph->saddr = x->props.saddr.a4; | ||
64 | top_iph->daddr = x->id.daddr.a4; | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static int xfrm4_beet_input(struct xfrm_state *x, struct sk_buff *skb) | ||
70 | { | ||
71 | struct iphdr *iph = skb->nh.iph; | ||
72 | int phlen = 0; | ||
73 | int optlen = 0; | ||
74 | __u8 ph_nexthdr = 0, protocol = 0; | ||
75 | int err = -EINVAL; | ||
76 | |||
77 | protocol = iph->protocol; | ||
78 | |||
79 | if (unlikely(iph->protocol == IPPROTO_BEETPH)) { | ||
80 | struct ip_beet_phdr *ph = (struct ip_beet_phdr*)(iph + 1); | ||
81 | |||
82 | if (!pskb_may_pull(skb, sizeof(*ph))) | ||
83 | goto out; | ||
84 | |||
85 | phlen = ph->hdrlen * 8; | ||
86 | optlen = phlen - ph->padlen - sizeof(*ph); | ||
87 | if (optlen < 0 || optlen & 3 || optlen > 250) | ||
88 | goto out; | ||
89 | |||
90 | if (!pskb_may_pull(skb, phlen)) | ||
91 | goto out; | ||
92 | |||
93 | ph_nexthdr = ph->nexthdr; | ||
94 | } | ||
95 | |||
96 | skb_push(skb, sizeof(*iph) - phlen + optlen); | ||
97 | memmove(skb->data, skb->nh.raw, sizeof(*iph)); | ||
98 | skb->nh.raw = skb->data; | ||
99 | |||
100 | iph = skb->nh.iph; | ||
101 | iph->ihl = (sizeof(*iph) + optlen) / 4; | ||
102 | iph->tot_len = htons(skb->len); | ||
103 | iph->daddr = x->sel.daddr.a4; | ||
104 | iph->saddr = x->sel.saddr.a4; | ||
105 | if (ph_nexthdr) | ||
106 | iph->protocol = ph_nexthdr; | ||
107 | else | ||
108 | iph->protocol = protocol; | ||
109 | iph->check = 0; | ||
110 | iph->check = ip_fast_csum(skb->nh.raw, iph->ihl); | ||
111 | err = 0; | ||
112 | out: | ||
113 | return err; | ||
114 | } | ||
115 | |||
116 | static struct xfrm_mode xfrm4_beet_mode = { | ||
117 | .input = xfrm4_beet_input, | ||
118 | .output = xfrm4_beet_output, | ||
119 | .owner = THIS_MODULE, | ||
120 | .encap = XFRM_MODE_BEET, | ||
121 | }; | ||
122 | |||
123 | static int __init xfrm4_beet_init(void) | ||
124 | { | ||
125 | return xfrm_register_mode(&xfrm4_beet_mode, AF_INET); | ||
126 | } | ||
127 | |||
128 | static void __exit xfrm4_beet_exit(void) | ||
129 | { | ||
130 | int err; | ||
131 | |||
132 | err = xfrm_unregister_mode(&xfrm4_beet_mode, AF_INET); | ||
133 | BUG_ON(err); | ||
134 | } | ||
135 | |||
136 | module_init(xfrm4_beet_init); | ||
137 | module_exit(xfrm4_beet_exit); | ||
138 | MODULE_LICENSE("GPL"); | ||
139 | MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_BEET); | ||