aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/bridge/netfilter/ebt_mark.c21
-rw-r--r--net/core/neighbour.c12
-rw-r--r--net/ipv4/Kconfig9
-rw-r--r--net/ipv4/Makefile1
-rw-r--r--net/ipv4/esp4.c26
-rw-r--r--net/ipv4/ipcomp.c5
-rw-r--r--net/ipv4/ipvs/ip_vs_core.c10
-rw-r--r--net/ipv4/netfilter.c9
-rw-r--r--net/ipv4/netfilter/ip_nat_standalone.c3
-rw-r--r--net/ipv4/netfilter/ipt_REJECT.c97
-rw-r--r--net/ipv4/netfilter/iptable_mangle.c3
-rw-r--r--net/ipv4/tcp_input.c2
-rw-r--r--net/ipv4/udp.c2
-rw-r--r--net/ipv4/xfrm4_mode_beet.c139
-rw-r--r--net/ipv6/Kconfig10
-rw-r--r--net/ipv6/Makefile1
-rw-r--r--net/ipv6/ipcomp6.c5
-rw-r--r--net/ipv6/udp.c64
-rw-r--r--net/ipv6/xfrm6_mode_beet.c107
-rw-r--r--net/netfilter/Kconfig2
-rw-r--r--net/sched/estimator.c196
-rw-r--r--net/sched/sch_htb.c2
-rw-r--r--net/tipc/link.c5
-rw-r--r--net/xfrm/xfrm_hash.h7
-rw-r--r--net/xfrm/xfrm_policy.c7
-rw-r--r--net/xfrm/xfrm_state.c16
-rw-r--r--net/xfrm/xfrm_user.c1
27 files changed, 416 insertions, 346 deletions
diff --git a/net/bridge/netfilter/ebt_mark.c b/net/bridge/netfilter/ebt_mark.c
index 770c0df972a3..b54306a934e5 100644
--- a/net/bridge/netfilter/ebt_mark.c
+++ b/net/bridge/netfilter/ebt_mark.c
@@ -22,24 +22,37 @@ static int ebt_target_mark(struct sk_buff **pskb, unsigned int hooknr,
22 const void *data, unsigned int datalen) 22 const void *data, unsigned int datalen)
23{ 23{
24 struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data; 24 struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data;
25 int action = info->target & -16;
25 26
26 if ((*pskb)->nfmark != info->mark) 27 if (action == MARK_SET_VALUE)
27 (*pskb)->nfmark = info->mark; 28 (*pskb)->nfmark = info->mark;
29 else if (action == MARK_OR_VALUE)
30 (*pskb)->nfmark |= info->mark;
31 else if (action == MARK_AND_VALUE)
32 (*pskb)->nfmark &= info->mark;
33 else
34 (*pskb)->nfmark ^= info->mark;
28 35
29 return info->target; 36 return info->target | -16;
30} 37}
31 38
32static int ebt_target_mark_check(const char *tablename, unsigned int hookmask, 39static int ebt_target_mark_check(const char *tablename, unsigned int hookmask,
33 const struct ebt_entry *e, void *data, unsigned int datalen) 40 const struct ebt_entry *e, void *data, unsigned int datalen)
34{ 41{
35 struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data; 42 struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data;
43 int tmp;
36 44
37 if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_t_info))) 45 if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_t_info)))
38 return -EINVAL; 46 return -EINVAL;
39 if (BASE_CHAIN && info->target == EBT_RETURN) 47 tmp = info->target | -16;
48 if (BASE_CHAIN && tmp == EBT_RETURN)
40 return -EINVAL; 49 return -EINVAL;
41 CLEAR_BASE_CHAIN_BIT; 50 CLEAR_BASE_CHAIN_BIT;
42 if (INVALID_TARGET) 51 if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0)
52 return -EINVAL;
53 tmp = info->target & -16;
54 if (tmp != MARK_SET_VALUE && tmp != MARK_OR_VALUE &&
55 tmp != MARK_AND_VALUE && tmp != MARK_XOR_VALUE)
43 return -EINVAL; 56 return -EINVAL;
44 return 0; 57 return 0;
45} 58}
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 8ce8c471d868..b4b478353b27 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -344,12 +344,12 @@ struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
344{ 344{
345 struct neighbour *n; 345 struct neighbour *n;
346 int key_len = tbl->key_len; 346 int key_len = tbl->key_len;
347 u32 hash_val = tbl->hash(pkey, dev) & tbl->hash_mask; 347 u32 hash_val = tbl->hash(pkey, dev);
348 348
349 NEIGH_CACHE_STAT_INC(tbl, lookups); 349 NEIGH_CACHE_STAT_INC(tbl, lookups);
350 350
351 read_lock_bh(&tbl->lock); 351 read_lock_bh(&tbl->lock);
352 for (n = tbl->hash_buckets[hash_val]; n; n = n->next) { 352 for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) {
353 if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) { 353 if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) {
354 neigh_hold(n); 354 neigh_hold(n);
355 NEIGH_CACHE_STAT_INC(tbl, hits); 355 NEIGH_CACHE_STAT_INC(tbl, hits);
@@ -364,12 +364,12 @@ struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, const void *pkey)
364{ 364{
365 struct neighbour *n; 365 struct neighbour *n;
366 int key_len = tbl->key_len; 366 int key_len = tbl->key_len;
367 u32 hash_val = tbl->hash(pkey, NULL) & tbl->hash_mask; 367 u32 hash_val = tbl->hash(pkey, NULL);
368 368
369 NEIGH_CACHE_STAT_INC(tbl, lookups); 369 NEIGH_CACHE_STAT_INC(tbl, lookups);
370 370
371 read_lock_bh(&tbl->lock); 371 read_lock_bh(&tbl->lock);
372 for (n = tbl->hash_buckets[hash_val]; n; n = n->next) { 372 for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) {
373 if (!memcmp(n->primary_key, pkey, key_len)) { 373 if (!memcmp(n->primary_key, pkey, key_len)) {
374 neigh_hold(n); 374 neigh_hold(n);
375 NEIGH_CACHE_STAT_INC(tbl, hits); 375 NEIGH_CACHE_STAT_INC(tbl, hits);
@@ -1998,12 +1998,12 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
1998 int rc, h, s_h = cb->args[1]; 1998 int rc, h, s_h = cb->args[1];
1999 int idx, s_idx = idx = cb->args[2]; 1999 int idx, s_idx = idx = cb->args[2];
2000 2000
2001 read_lock_bh(&tbl->lock);
2001 for (h = 0; h <= tbl->hash_mask; h++) { 2002 for (h = 0; h <= tbl->hash_mask; h++) {
2002 if (h < s_h) 2003 if (h < s_h)
2003 continue; 2004 continue;
2004 if (h > s_h) 2005 if (h > s_h)
2005 s_idx = 0; 2006 s_idx = 0;
2006 read_lock_bh(&tbl->lock);
2007 for (n = tbl->hash_buckets[h], idx = 0; n; n = n->next, idx++) { 2007 for (n = tbl->hash_buckets[h], idx = 0; n; n = n->next, idx++) {
2008 if (idx < s_idx) 2008 if (idx < s_idx)
2009 continue; 2009 continue;
@@ -2016,8 +2016,8 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
2016 goto out; 2016 goto out;
2017 } 2017 }
2018 } 2018 }
2019 read_unlock_bh(&tbl->lock);
2020 } 2019 }
2020 read_unlock_bh(&tbl->lock);
2021 rc = skb->len; 2021 rc = skb->len;
2022out: 2022out:
2023 cb->args[1] = h; 2023 cb->args[1] = h;
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
437config 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
437config INET_DIAG 446config 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
23obj-$(CONFIG_INET_ESP) += esp4.o 23obj-$(CONFIG_INET_ESP) += esp4.o
24obj-$(CONFIG_INET_IPCOMP) += ipcomp.o 24obj-$(CONFIG_INET_IPCOMP) += ipcomp.o
25obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o 25obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o
26obj-$(CONFIG_INET_XFRM_MODE_BEET) += xfrm4_mode_beet.o
26obj-$(CONFIG_INET_TUNNEL) += tunnel4.o 27obj-$(CONFIG_INET_TUNNEL) += tunnel4.o
27obj-$(CONFIG_INET_XFRM_MODE_TRANSPORT) += xfrm4_mode_transport.o 28obj-$(CONFIG_INET_XFRM_MODE_TRANSPORT) += xfrm4_mode_transport.o
28obj-$(CONFIG_INET_XFRM_MODE_TUNNEL) += xfrm4_mode_tunnel.o 29obj-$(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
287static void esp4_err(struct sk_buff *skb, u32 info) 299static 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)
206static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x) 206static 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 */
11int ip_route_me_harder(struct sk_buff **pskb) 11int 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
41static 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 */
101static void send_reset(struct sk_buff *oldskb, int hook) 42static 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
680out: 682out:
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 */
30static 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
69static 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;
112out:
113 return err;
114}
115
116static 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
123static int __init xfrm4_beet_init(void)
124{
125 return xfrm_register_mode(&xfrm4_beet_mode, AF_INET);
126}
127
128static 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
136module_init(xfrm4_beet_init);
137module_exit(xfrm4_beet_exit);
138MODULE_LICENSE("GPL");
139MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_BEET);
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index a2d211da2aba..a460e8132b4d 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -136,6 +136,16 @@ config INET6_XFRM_MODE_TUNNEL
136 136
137 If unsure, say Y. 137 If unsure, say Y.
138 138
139config INET6_XFRM_MODE_BEET
140 tristate "IPv6: IPsec BEET mode"
141 depends on IPV6
142 default IPV6
143 select XFRM
144 ---help---
145 Support for IPsec BEET mode.
146
147 If unsure, say Y.
148
139config INET6_XFRM_MODE_ROUTEOPTIMIZATION 149config INET6_XFRM_MODE_ROUTEOPTIMIZATION
140 tristate "IPv6: MIPv6 route optimization mode (EXPERIMENTAL)" 150 tristate "IPv6: MIPv6 route optimization mode (EXPERIMENTAL)"
141 depends on IPV6 && EXPERIMENTAL 151 depends on IPV6 && EXPERIMENTAL
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index 0213c6612b58..87274e47fe32 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o
26obj-$(CONFIG_INET6_XFRM_MODE_TRANSPORT) += xfrm6_mode_transport.o 26obj-$(CONFIG_INET6_XFRM_MODE_TRANSPORT) += xfrm6_mode_transport.o
27obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o 27obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o
28obj-$(CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION) += xfrm6_mode_ro.o 28obj-$(CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION) += xfrm6_mode_ro.o
29obj-$(CONFIG_INET6_XFRM_MODE_BEET) += xfrm6_mode_beet.o
29obj-$(CONFIG_NETFILTER) += netfilter/ 30obj-$(CONFIG_NETFILTER) += netfilter/
30 31
31obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o 32obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
index a2860e35efd7..71f59f18ede8 100644
--- a/net/ipv6/ipcomp6.c
+++ b/net/ipv6/ipcomp6.c
@@ -199,6 +199,7 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
199static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x) 199static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x)
200{ 200{
201 struct xfrm_state *t = NULL; 201 struct xfrm_state *t = NULL;
202 u8 mode = XFRM_MODE_TUNNEL;
202 203
203 t = xfrm_state_alloc(); 204 t = xfrm_state_alloc();
204 if (!t) 205 if (!t)
@@ -212,7 +213,9 @@ static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x)
212 memcpy(t->id.daddr.a6, x->id.daddr.a6, sizeof(struct in6_addr)); 213 memcpy(t->id.daddr.a6, x->id.daddr.a6, sizeof(struct in6_addr));
213 memcpy(&t->sel, &x->sel, sizeof(t->sel)); 214 memcpy(&t->sel, &x->sel, sizeof(t->sel));
214 t->props.family = AF_INET6; 215 t->props.family = AF_INET6;
215 t->props.mode = XFRM_MODE_TUNNEL; 216 if (x->props.mode == XFRM_MODE_BEET)
217 mode = x->props.mode;
218 t->props.mode = mode;
216 memcpy(t->props.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr)); 219 memcpy(t->props.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr));
217 220
218 if (xfrm_init_state(t)) 221 if (xfrm_init_state(t))
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 9662561701d1..e0c3934a7e4b 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -546,7 +546,7 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
546 struct in6_addr *daddr, *final_p = NULL, final; 546 struct in6_addr *daddr, *final_p = NULL, final;
547 struct ipv6_txoptions *opt = NULL; 547 struct ipv6_txoptions *opt = NULL;
548 struct ip6_flowlabel *flowlabel = NULL; 548 struct ip6_flowlabel *flowlabel = NULL;
549 struct flowi *fl = &inet->cork.fl; 549 struct flowi fl;
550 struct dst_entry *dst; 550 struct dst_entry *dst;
551 int addr_len = msg->msg_namelen; 551 int addr_len = msg->msg_namelen;
552 int ulen = len; 552 int ulen = len;
@@ -626,19 +626,19 @@ do_udp_sendmsg:
626 } 626 }
627 ulen += sizeof(struct udphdr); 627 ulen += sizeof(struct udphdr);
628 628
629 memset(fl, 0, sizeof(*fl)); 629 memset(&fl, 0, sizeof(fl));
630 630
631 if (sin6) { 631 if (sin6) {
632 if (sin6->sin6_port == 0) 632 if (sin6->sin6_port == 0)
633 return -EINVAL; 633 return -EINVAL;
634 634
635 fl->fl_ip_dport = sin6->sin6_port; 635 fl.fl_ip_dport = sin6->sin6_port;
636 daddr = &sin6->sin6_addr; 636 daddr = &sin6->sin6_addr;
637 637
638 if (np->sndflow) { 638 if (np->sndflow) {
639 fl->fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; 639 fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
640 if (fl->fl6_flowlabel&IPV6_FLOWLABEL_MASK) { 640 if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
641 flowlabel = fl6_sock_lookup(sk, fl->fl6_flowlabel); 641 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
642 if (flowlabel == NULL) 642 if (flowlabel == NULL)
643 return -EINVAL; 643 return -EINVAL;
644 daddr = &flowlabel->dst; 644 daddr = &flowlabel->dst;
@@ -656,32 +656,32 @@ do_udp_sendmsg:
656 if (addr_len >= sizeof(struct sockaddr_in6) && 656 if (addr_len >= sizeof(struct sockaddr_in6) &&
657 sin6->sin6_scope_id && 657 sin6->sin6_scope_id &&
658 ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL) 658 ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL)
659 fl->oif = sin6->sin6_scope_id; 659 fl.oif = sin6->sin6_scope_id;
660 } else { 660 } else {
661 if (sk->sk_state != TCP_ESTABLISHED) 661 if (sk->sk_state != TCP_ESTABLISHED)
662 return -EDESTADDRREQ; 662 return -EDESTADDRREQ;
663 663
664 fl->fl_ip_dport = inet->dport; 664 fl.fl_ip_dport = inet->dport;
665 daddr = &np->daddr; 665 daddr = &np->daddr;
666 fl->fl6_flowlabel = np->flow_label; 666 fl.fl6_flowlabel = np->flow_label;
667 connected = 1; 667 connected = 1;
668 } 668 }
669 669
670 if (!fl->oif) 670 if (!fl.oif)
671 fl->oif = sk->sk_bound_dev_if; 671 fl.oif = sk->sk_bound_dev_if;
672 672
673 if (msg->msg_controllen) { 673 if (msg->msg_controllen) {
674 opt = &opt_space; 674 opt = &opt_space;
675 memset(opt, 0, sizeof(struct ipv6_txoptions)); 675 memset(opt, 0, sizeof(struct ipv6_txoptions));
676 opt->tot_len = sizeof(*opt); 676 opt->tot_len = sizeof(*opt);
677 677
678 err = datagram_send_ctl(msg, fl, opt, &hlimit, &tclass); 678 err = datagram_send_ctl(msg, &fl, opt, &hlimit, &tclass);
679 if (err < 0) { 679 if (err < 0) {
680 fl6_sock_release(flowlabel); 680 fl6_sock_release(flowlabel);
681 return err; 681 return err;
682 } 682 }
683 if ((fl->fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) { 683 if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) {
684 flowlabel = fl6_sock_lookup(sk, fl->fl6_flowlabel); 684 flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
685 if (flowlabel == NULL) 685 if (flowlabel == NULL)
686 return -EINVAL; 686 return -EINVAL;
687 } 687 }
@@ -695,39 +695,39 @@ do_udp_sendmsg:
695 opt = fl6_merge_options(&opt_space, flowlabel, opt); 695 opt = fl6_merge_options(&opt_space, flowlabel, opt);
696 opt = ipv6_fixup_options(&opt_space, opt); 696 opt = ipv6_fixup_options(&opt_space, opt);
697 697
698 fl->proto = IPPROTO_UDP; 698 fl.proto = IPPROTO_UDP;
699 ipv6_addr_copy(&fl->fl6_dst, daddr); 699 ipv6_addr_copy(&fl.fl6_dst, daddr);
700 if (ipv6_addr_any(&fl->fl6_src) && !ipv6_addr_any(&np->saddr)) 700 if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr))
701 ipv6_addr_copy(&fl->fl6_src, &np->saddr); 701 ipv6_addr_copy(&fl.fl6_src, &np->saddr);
702 fl->fl_ip_sport = inet->sport; 702 fl.fl_ip_sport = inet->sport;
703 703
704 /* merge ip6_build_xmit from ip6_output */ 704 /* merge ip6_build_xmit from ip6_output */
705 if (opt && opt->srcrt) { 705 if (opt && opt->srcrt) {
706 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; 706 struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
707 ipv6_addr_copy(&final, &fl->fl6_dst); 707 ipv6_addr_copy(&final, &fl.fl6_dst);
708 ipv6_addr_copy(&fl->fl6_dst, rt0->addr); 708 ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
709 final_p = &final; 709 final_p = &final;
710 connected = 0; 710 connected = 0;
711 } 711 }
712 712
713 if (!fl->oif && ipv6_addr_is_multicast(&fl->fl6_dst)) { 713 if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) {
714 fl->oif = np->mcast_oif; 714 fl.oif = np->mcast_oif;
715 connected = 0; 715 connected = 0;
716 } 716 }
717 717
718 security_sk_classify_flow(sk, fl); 718 security_sk_classify_flow(sk, &fl);
719 719
720 err = ip6_sk_dst_lookup(sk, &dst, fl); 720 err = ip6_sk_dst_lookup(sk, &dst, &fl);
721 if (err) 721 if (err)
722 goto out; 722 goto out;
723 if (final_p) 723 if (final_p)
724 ipv6_addr_copy(&fl->fl6_dst, final_p); 724 ipv6_addr_copy(&fl.fl6_dst, final_p);
725 725
726 if ((err = xfrm_lookup(&dst, fl, sk, 0)) < 0) 726 if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
727 goto out; 727 goto out;
728 728
729 if (hlimit < 0) { 729 if (hlimit < 0) {
730 if (ipv6_addr_is_multicast(&fl->fl6_dst)) 730 if (ipv6_addr_is_multicast(&fl.fl6_dst))
731 hlimit = np->mcast_hops; 731 hlimit = np->mcast_hops;
732 else 732 else
733 hlimit = np->hop_limit; 733 hlimit = np->hop_limit;
@@ -763,21 +763,23 @@ back_from_confirm:
763do_append_data: 763do_append_data:
764 up->len += ulen; 764 up->len += ulen;
765 err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen, 765 err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen,
766 sizeof(struct udphdr), hlimit, tclass, opt, fl, 766 sizeof(struct udphdr), hlimit, tclass, opt, &fl,
767 (struct rt6_info*)dst, 767 (struct rt6_info*)dst,
768 corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); 768 corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
769 if (err) 769 if (err)
770 udp_v6_flush_pending_frames(sk); 770 udp_v6_flush_pending_frames(sk);
771 else if (!corkreq) 771 else if (!corkreq)
772 err = udp_v6_push_pending_frames(sk, up); 772 err = udp_v6_push_pending_frames(sk, up);
773 else if (unlikely(skb_queue_empty(&sk->sk_write_queue)))
774 up->pending = 0;
773 775
774 if (dst) { 776 if (dst) {
775 if (connected) { 777 if (connected) {
776 ip6_dst_store(sk, dst, 778 ip6_dst_store(sk, dst,
777 ipv6_addr_equal(&fl->fl6_dst, &np->daddr) ? 779 ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ?
778 &np->daddr : NULL, 780 &np->daddr : NULL,
779#ifdef CONFIG_IPV6_SUBTREES 781#ifdef CONFIG_IPV6_SUBTREES
780 ipv6_addr_equal(&fl->fl6_src, &np->saddr) ? 782 ipv6_addr_equal(&fl.fl6_src, &np->saddr) ?
781 &np->saddr : 783 &np->saddr :
782#endif 784#endif
783 NULL); 785 NULL);
diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c
new file mode 100644
index 000000000000..edcfffa9e87b
--- /dev/null
+++ b/net/ipv6/xfrm6_mode_beet.c
@@ -0,0 +1,107 @@
1/*
2 * xfrm6_mode_beet.c - BEET mode encapsulation for IPv6.
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/dsfield.h>
17#include <net/dst.h>
18#include <net/inet_ecn.h>
19#include <net/ipv6.h>
20#include <net/xfrm.h>
21
22/* Add encapsulation header.
23 *
24 * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt.
25 * The following fields in it shall be filled in by x->type->output:
26 * payload_len
27 *
28 * On exit, skb->h will be set to the start of the encapsulation header to be
29 * filled in by x->type->output and skb->nh will be set to the nextheader field
30 * of the extension header directly preceding the encapsulation header, or in
31 * its absence, that of the top IP header. The value of skb->data will always
32 * point to the top IP header.
33 */
34static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb)
35{
36 struct ipv6hdr *iph, *top_iph;
37 u8 *prevhdr;
38 int hdr_len;
39
40 skb_push(skb, x->props.header_len);
41 iph = skb->nh.ipv6h;
42
43 hdr_len = ip6_find_1stfragopt(skb, &prevhdr);
44 skb->nh.raw = prevhdr - x->props.header_len;
45 skb->h.raw = skb->data + hdr_len;
46 memmove(skb->data, iph, hdr_len);
47
48 skb->nh.raw = skb->data;
49 top_iph = skb->nh.ipv6h;
50 skb->nh.raw = &top_iph->nexthdr;
51 skb->h.ipv6h = top_iph + 1;
52
53 ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
54 ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
55
56 return 0;
57}
58
59static int xfrm6_beet_input(struct xfrm_state *x, struct sk_buff *skb)
60{
61 struct ipv6hdr *ip6h;
62 int size = sizeof(struct ipv6hdr);
63 int err = -EINVAL;
64
65 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
66 goto out;
67
68 skb_push(skb, size);
69 memmove(skb->data, skb->nh.raw, size);
70 skb->nh.raw = skb->data;
71
72 skb->mac.raw = memmove(skb->data - skb->mac_len,
73 skb->mac.raw, skb->mac_len);
74
75 ip6h = skb->nh.ipv6h;
76 ip6h->payload_len = htons(skb->len - size);
77 ipv6_addr_copy(&ip6h->daddr, (struct in6_addr *) &x->sel.daddr.a6);
78 ipv6_addr_copy(&ip6h->saddr, (struct in6_addr *) &x->sel.saddr.a6);
79 err = 0;
80out:
81 return err;
82}
83
84static struct xfrm_mode xfrm6_beet_mode = {
85 .input = xfrm6_beet_input,
86 .output = xfrm6_beet_output,
87 .owner = THIS_MODULE,
88 .encap = XFRM_MODE_BEET,
89};
90
91static int __init xfrm6_beet_init(void)
92{
93 return xfrm_register_mode(&xfrm6_beet_mode, AF_INET6);
94}
95
96static void __exit xfrm6_beet_exit(void)
97{
98 int err;
99
100 err = xfrm_unregister_mode(&xfrm6_beet_mode, AF_INET6);
101 BUG_ON(err);
102}
103
104module_init(xfrm6_beet_init);
105module_exit(xfrm6_beet_exit);
106MODULE_LICENSE("GPL");
107MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_BEET);
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 0a28d2c5c44f..ce94732b8e23 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -365,7 +365,7 @@ config NETFILTER_XT_MATCH_MULTIPORT
365 365
366config NETFILTER_XT_MATCH_PHYSDEV 366config NETFILTER_XT_MATCH_PHYSDEV
367 tristate '"physdev" match support' 367 tristate '"physdev" match support'
368 depends on NETFILTER_XTABLES && BRIDGE_NETFILTER 368 depends on NETFILTER_XTABLES && BRIDGE && BRIDGE_NETFILTER
369 help 369 help
370 Physdev packet matching matches against the physical bridge ports 370 Physdev packet matching matches against the physical bridge ports
371 the IP packet arrived on or will leave by. 371 the IP packet arrived on or will leave by.
diff --git a/net/sched/estimator.c b/net/sched/estimator.c
deleted file mode 100644
index 0ebc98e9be2d..000000000000
--- a/net/sched/estimator.c
+++ /dev/null
@@ -1,196 +0,0 @@
1/*
2 * net/sched/estimator.c Simple rate estimator.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 */
11
12#include <asm/uaccess.h>
13#include <asm/system.h>
14#include <linux/bitops.h>
15#include <linux/module.h>
16#include <linux/types.h>
17#include <linux/kernel.h>
18#include <linux/jiffies.h>
19#include <linux/string.h>
20#include <linux/mm.h>
21#include <linux/socket.h>
22#include <linux/sockios.h>
23#include <linux/in.h>
24#include <linux/errno.h>
25#include <linux/interrupt.h>
26#include <linux/netdevice.h>
27#include <linux/skbuff.h>
28#include <linux/rtnetlink.h>
29#include <linux/init.h>
30#include <net/sock.h>
31#include <net/pkt_sched.h>
32
33/*
34 This code is NOT intended to be used for statistics collection,
35 its purpose is to provide a base for statistical multiplexing
36 for controlled load service.
37 If you need only statistics, run a user level daemon which
38 periodically reads byte counters.
39
40 Unfortunately, rate estimation is not a very easy task.
41 F.e. I did not find a simple way to estimate the current peak rate
42 and even failed to formulate the problem 8)8)
43
44 So I preferred not to built an estimator into the scheduler,
45 but run this task separately.
46 Ideally, it should be kernel thread(s), but for now it runs
47 from timers, which puts apparent top bounds on the number of rated
48 flows, has minimal overhead on small, but is enough
49 to handle controlled load service, sets of aggregates.
50
51 We measure rate over A=(1<<interval) seconds and evaluate EWMA:
52
53 avrate = avrate*(1-W) + rate*W
54
55 where W is chosen as negative power of 2: W = 2^(-ewma_log)
56
57 The resulting time constant is:
58
59 T = A/(-ln(1-W))
60
61
62 NOTES.
63
64 * The stored value for avbps is scaled by 2^5, so that maximal
65 rate is ~1Gbit, avpps is scaled by 2^10.
66
67 * Minimal interval is HZ/4=250msec (it is the greatest common divisor
68 for HZ=100 and HZ=1024 8)), maximal interval
69 is (HZ*2^EST_MAX_INTERVAL)/4 = 8sec. Shorter intervals
70 are too expensive, longer ones can be implemented
71 at user level painlessly.
72 */
73
74#define EST_MAX_INTERVAL 5
75
76struct qdisc_estimator
77{
78 struct qdisc_estimator *next;
79 struct tc_stats *stats;
80 spinlock_t *stats_lock;
81 unsigned interval;
82 int ewma_log;
83 u64 last_bytes;
84 u32 last_packets;
85 u32 avpps;
86 u32 avbps;
87};
88
89struct qdisc_estimator_head
90{
91 struct timer_list timer;
92 struct qdisc_estimator *list;
93};
94
95static struct qdisc_estimator_head elist[EST_MAX_INTERVAL+1];
96
97/* Estimator array lock */
98static DEFINE_RWLOCK(est_lock);
99
100static void est_timer(unsigned long arg)
101{
102 int idx = (int)arg;
103 struct qdisc_estimator *e;
104
105 read_lock(&est_lock);
106 for (e = elist[idx].list; e; e = e->next) {
107 struct tc_stats *st = e->stats;
108 u64 nbytes;
109 u32 npackets;
110 u32 rate;
111
112 spin_lock(e->stats_lock);
113 nbytes = st->bytes;
114 npackets = st->packets;
115 rate = (nbytes - e->last_bytes)<<(7 - idx);
116 e->last_bytes = nbytes;
117 e->avbps += ((long)rate - (long)e->avbps) >> e->ewma_log;
118 st->bps = (e->avbps+0xF)>>5;
119
120 rate = (npackets - e->last_packets)<<(12 - idx);
121 e->last_packets = npackets;
122 e->avpps += ((long)rate - (long)e->avpps) >> e->ewma_log;
123 e->stats->pps = (e->avpps+0x1FF)>>10;
124 spin_unlock(e->stats_lock);
125 }
126
127 mod_timer(&elist[idx].timer, jiffies + ((HZ<<idx)/4));
128 read_unlock(&est_lock);
129}
130
131int qdisc_new_estimator(struct tc_stats *stats, spinlock_t *stats_lock, struct rtattr *opt)
132{
133 struct qdisc_estimator *est;
134 struct tc_estimator *parm = RTA_DATA(opt);
135
136 if (RTA_PAYLOAD(opt) < sizeof(*parm))
137 return -EINVAL;
138
139 if (parm->interval < -2 || parm->interval > 3)
140 return -EINVAL;
141
142 est = kzalloc(sizeof(*est), GFP_KERNEL);
143 if (est == NULL)
144 return -ENOBUFS;
145
146 est->interval = parm->interval + 2;
147 est->stats = stats;
148 est->stats_lock = stats_lock;
149 est->ewma_log = parm->ewma_log;
150 est->last_bytes = stats->bytes;
151 est->avbps = stats->bps<<5;
152 est->last_packets = stats->packets;
153 est->avpps = stats->pps<<10;
154
155 est->next = elist[est->interval].list;
156 if (est->next == NULL) {
157 init_timer(&elist[est->interval].timer);
158 elist[est->interval].timer.data = est->interval;
159 elist[est->interval].timer.expires = jiffies + ((HZ<<est->interval)/4);
160 elist[est->interval].timer.function = est_timer;
161 add_timer(&elist[est->interval].timer);
162 }
163 write_lock_bh(&est_lock);
164 elist[est->interval].list = est;
165 write_unlock_bh(&est_lock);
166 return 0;
167}
168
169void qdisc_kill_estimator(struct tc_stats *stats)
170{
171 int idx;
172 struct qdisc_estimator *est, **pest;
173
174 for (idx=0; idx <= EST_MAX_INTERVAL; idx++) {
175 int killed = 0;
176 pest = &elist[idx].list;
177 while ((est=*pest) != NULL) {
178 if (est->stats != stats) {
179 pest = &est->next;
180 continue;
181 }
182
183 write_lock_bh(&est_lock);
184 *pest = est->next;
185 write_unlock_bh(&est_lock);
186
187 kfree(est);
188 killed++;
189 }
190 if (killed && elist[idx].list == NULL)
191 del_timer(&elist[idx].timer);
192 }
193}
194
195EXPORT_SYMBOL(qdisc_kill_estimator);
196EXPORT_SYMBOL(qdisc_new_estimator);
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 6c058e3660c0..bb3ddd4784b1 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -391,7 +391,7 @@ static inline void htb_add_class_to_row(struct htb_sched *q,
391/* If this triggers, it is a bug in this code, but it need not be fatal */ 391/* If this triggers, it is a bug in this code, but it need not be fatal */
392static void htb_safe_rb_erase(struct rb_node *rb, struct rb_root *root) 392static void htb_safe_rb_erase(struct rb_node *rb, struct rb_root *root)
393{ 393{
394 if (!RB_EMPTY_NODE(rb)) { 394 if (RB_EMPTY_NODE(rb)) {
395 WARN_ON(1); 395 WARN_ON(1);
396 } else { 396 } else {
397 rb_erase(rb, root); 397 rb_erase(rb, root);
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 693f02eca6d6..53bc8cb5adbc 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -1666,8 +1666,9 @@ static void link_retransmit_failure(struct link *l_ptr, struct sk_buff *buf)
1666 char addr_string[16]; 1666 char addr_string[16];
1667 1667
1668 tipc_printf(TIPC_OUTPUT, "Msg seq number: %u, ", msg_seqno(msg)); 1668 tipc_printf(TIPC_OUTPUT, "Msg seq number: %u, ", msg_seqno(msg));
1669 tipc_printf(TIPC_OUTPUT, "Outstanding acks: %u\n", (u32)TIPC_SKB_CB(buf)->handle); 1669 tipc_printf(TIPC_OUTPUT, "Outstanding acks: %lu\n",
1670 1670 (unsigned long) TIPC_SKB_CB(buf)->handle);
1671
1671 n_ptr = l_ptr->owner->next; 1672 n_ptr = l_ptr->owner->next;
1672 tipc_node_lock(n_ptr); 1673 tipc_node_lock(n_ptr);
1673 1674
diff --git a/net/xfrm/xfrm_hash.h b/net/xfrm/xfrm_hash.h
index 6ac4e4f033ac..d401dc8f05ed 100644
--- a/net/xfrm/xfrm_hash.h
+++ b/net/xfrm/xfrm_hash.h
@@ -41,17 +41,18 @@ static inline unsigned int __xfrm_dst_hash(xfrm_address_t *daddr, xfrm_address_t
41 return (h ^ (h >> 16)) & hmask; 41 return (h ^ (h >> 16)) & hmask;
42} 42}
43 43
44static inline unsigned __xfrm_src_hash(xfrm_address_t *saddr, 44static inline unsigned __xfrm_src_hash(xfrm_address_t *daddr,
45 xfrm_address_t *saddr,
45 unsigned short family, 46 unsigned short family,
46 unsigned int hmask) 47 unsigned int hmask)
47{ 48{
48 unsigned int h = family; 49 unsigned int h = family;
49 switch (family) { 50 switch (family) {
50 case AF_INET: 51 case AF_INET:
51 h ^= __xfrm4_addr_hash(saddr); 52 h ^= __xfrm4_daddr_saddr_hash(daddr, saddr);
52 break; 53 break;
53 case AF_INET6: 54 case AF_INET6:
54 h ^= __xfrm6_addr_hash(saddr); 55 h ^= __xfrm6_daddr_saddr_hash(daddr, saddr);
55 break; 56 break;
56 }; 57 };
57 return (h ^ (h >> 16)) & hmask; 58 return (h ^ (h >> 16)) & hmask;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index b6e2e79d7261..2a7861661f14 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -778,8 +778,9 @@ void xfrm_policy_flush(u8 type)
778 for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { 778 for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
779 struct xfrm_policy *pol; 779 struct xfrm_policy *pol;
780 struct hlist_node *entry; 780 struct hlist_node *entry;
781 int i; 781 int i, killed;
782 782
783 killed = 0;
783 again1: 784 again1:
784 hlist_for_each_entry(pol, entry, 785 hlist_for_each_entry(pol, entry,
785 &xfrm_policy_inexact[dir], bydst) { 786 &xfrm_policy_inexact[dir], bydst) {
@@ -790,6 +791,7 @@ void xfrm_policy_flush(u8 type)
790 write_unlock_bh(&xfrm_policy_lock); 791 write_unlock_bh(&xfrm_policy_lock);
791 792
792 xfrm_policy_kill(pol); 793 xfrm_policy_kill(pol);
794 killed++;
793 795
794 write_lock_bh(&xfrm_policy_lock); 796 write_lock_bh(&xfrm_policy_lock);
795 goto again1; 797 goto again1;
@@ -807,13 +809,14 @@ void xfrm_policy_flush(u8 type)
807 write_unlock_bh(&xfrm_policy_lock); 809 write_unlock_bh(&xfrm_policy_lock);
808 810
809 xfrm_policy_kill(pol); 811 xfrm_policy_kill(pol);
812 killed++;
810 813
811 write_lock_bh(&xfrm_policy_lock); 814 write_lock_bh(&xfrm_policy_lock);
812 goto again2; 815 goto again2;
813 } 816 }
814 } 817 }
815 818
816 xfrm_policy_count[dir] = 0; 819 xfrm_policy_count[dir] -= killed;
817 } 820 }
818 atomic_inc(&flow_cache_genid); 821 atomic_inc(&flow_cache_genid);
819 write_unlock_bh(&xfrm_policy_lock); 822 write_unlock_bh(&xfrm_policy_lock);
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index f927b7330f02..39b8bf3a9ded 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -63,10 +63,11 @@ static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr,
63 return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_hmask); 63 return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_hmask);
64} 64}
65 65
66static inline unsigned int xfrm_src_hash(xfrm_address_t *addr, 66static inline unsigned int xfrm_src_hash(xfrm_address_t *daddr,
67 xfrm_address_t *saddr,
67 unsigned short family) 68 unsigned short family)
68{ 69{
69 return __xfrm_src_hash(addr, family, xfrm_state_hmask); 70 return __xfrm_src_hash(daddr, saddr, family, xfrm_state_hmask);
70} 71}
71 72
72static inline unsigned int 73static inline unsigned int
@@ -92,7 +93,8 @@ static void xfrm_hash_transfer(struct hlist_head *list,
92 nhashmask); 93 nhashmask);
93 hlist_add_head(&x->bydst, ndsttable+h); 94 hlist_add_head(&x->bydst, ndsttable+h);
94 95
95 h = __xfrm_src_hash(&x->props.saddr, x->props.family, 96 h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr,
97 x->props.family,
96 nhashmask); 98 nhashmask);
97 hlist_add_head(&x->bysrc, nsrctable+h); 99 hlist_add_head(&x->bysrc, nsrctable+h);
98 100
@@ -458,7 +460,7 @@ static struct xfrm_state *__xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi,
458 460
459static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family) 461static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family)
460{ 462{
461 unsigned int h = xfrm_src_hash(saddr, family); 463 unsigned int h = xfrm_src_hash(daddr, saddr, family);
462 struct xfrm_state *x; 464 struct xfrm_state *x;
463 struct hlist_node *entry; 465 struct hlist_node *entry;
464 466
@@ -587,7 +589,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
587 if (km_query(x, tmpl, pol) == 0) { 589 if (km_query(x, tmpl, pol) == 0) {
588 x->km.state = XFRM_STATE_ACQ; 590 x->km.state = XFRM_STATE_ACQ;
589 hlist_add_head(&x->bydst, xfrm_state_bydst+h); 591 hlist_add_head(&x->bydst, xfrm_state_bydst+h);
590 h = xfrm_src_hash(saddr, family); 592 h = xfrm_src_hash(daddr, saddr, family);
591 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); 593 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
592 if (x->id.spi) { 594 if (x->id.spi) {
593 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family); 595 h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family);
@@ -622,7 +624,7 @@ static void __xfrm_state_insert(struct xfrm_state *x)
622 x->props.reqid, x->props.family); 624 x->props.reqid, x->props.family);
623 hlist_add_head(&x->bydst, xfrm_state_bydst+h); 625 hlist_add_head(&x->bydst, xfrm_state_bydst+h);
624 626
625 h = xfrm_src_hash(&x->props.saddr, x->props.family); 627 h = xfrm_src_hash(&x->id.daddr, &x->props.saddr, x->props.family);
626 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); 628 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
627 629
628 if (x->id.spi) { 630 if (x->id.spi) {
@@ -748,7 +750,7 @@ static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 re
748 x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ; 750 x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ;
749 add_timer(&x->timer); 751 add_timer(&x->timer);
750 hlist_add_head(&x->bydst, xfrm_state_bydst+h); 752 hlist_add_head(&x->bydst, xfrm_state_bydst+h);
751 h = xfrm_src_hash(saddr, family); 753 h = xfrm_src_hash(daddr, saddr, family);
752 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); 754 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
753 wake_up(&km_waitq); 755 wake_up(&km_waitq);
754 } 756 }
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index c59a78d2923a..d54b3a70d5df 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -211,6 +211,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
211 case XFRM_MODE_TRANSPORT: 211 case XFRM_MODE_TRANSPORT:
212 case XFRM_MODE_TUNNEL: 212 case XFRM_MODE_TUNNEL:
213 case XFRM_MODE_ROUTEOPTIMIZATION: 213 case XFRM_MODE_ROUTEOPTIMIZATION:
214 case XFRM_MODE_BEET:
214 break; 215 break;
215 216
216 default: 217 default: