942b6ca596c28872a03a614613a98bd0747a9a04
[openwrt/svn-archive/archive.git] / target / linux / generic / patches-3.8 / 670-ipv6-allow-rejecting-with-source-address-failed-policy.patch
1 --- a/include/net/netns/ipv6.h
2 +++ b/include/net/netns/ipv6.h
3 @@ -54,6 +54,7 @@ struct netns_ipv6 {
4 unsigned long ip6_rt_last_gc;
5 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
6 struct rt6_info *ip6_prohibit_entry;
7 + struct rt6_info *ip6_failed_policy_entry;
8 struct rt6_info *ip6_blk_hole_entry;
9 struct fib6_table *fib6_local_tbl;
10 struct fib_rules_ops *fib6_rules_ops;
11 --- a/include/uapi/linux/fib_rules.h
12 +++ b/include/uapi/linux/fib_rules.h
13 @@ -64,6 +64,10 @@ enum {
14 FR_ACT_BLACKHOLE, /* Drop without notification */
15 FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */
16 FR_ACT_PROHIBIT, /* Drop with EACCES */
17 + FR_ACT_RES9,
18 + FR_ACT_RES10,
19 + FR_ACT_RES11,
20 + FR_ACT_FAILED_POLICY, /* Drop with EPERM */
21 __FR_ACT_MAX,
22 };
23
24 --- a/include/uapi/linux/icmpv6.h
25 +++ b/include/uapi/linux/icmpv6.h
26 @@ -115,6 +115,7 @@ struct icmp6hdr {
27 #define ICMPV6_NOT_NEIGHBOUR 2
28 #define ICMPV6_ADDR_UNREACH 3
29 #define ICMPV6_PORT_UNREACH 4
30 +#define ICMPV6_FAILED_POLICY 5
31
32 /*
33 * Codes for Time Exceeded
34 --- a/include/uapi/linux/rtnetlink.h
35 +++ b/include/uapi/linux/rtnetlink.h
36 @@ -203,6 +203,7 @@ enum {
37 RTN_THROW, /* Not in this table */
38 RTN_NAT, /* Translate this address */
39 RTN_XRESOLVE, /* Use external resolver */
40 + RTN_FAILED_POLICY, /* Failed ingress/egress policy */
41 __RTN_MAX
42 };
43
44 --- a/net/ipv4/fib_rules.c
45 +++ b/net/ipv4/fib_rules.c
46 @@ -84,6 +84,10 @@ static int fib4_rule_action(struct fib_r
47 err = -EACCES;
48 goto errout;
49
50 + case FR_ACT_FAILED_POLICY:
51 + err = -EPERM;
52 + goto errout;
53 +
54 case FR_ACT_BLACKHOLE:
55 default:
56 err = -EINVAL;
57 --- a/net/ipv4/fib_semantics.c
58 +++ b/net/ipv4/fib_semantics.c
59 @@ -138,6 +138,10 @@ const struct fib_prop fib_props[RTN_MAX
60 .error = -EINVAL,
61 .scope = RT_SCOPE_NOWHERE,
62 },
63 + [RTN_FAILED_POLICY] = {
64 + .error = -EPERM,
65 + .scope = RT_SCOPE_UNIVERSE,
66 + },
67 };
68
69 static void rt_fibinfo_free(struct rtable __rcu **rtp)
70 --- a/net/ipv4/fib_trie.c
71 +++ b/net/ipv4/fib_trie.c
72 @@ -2350,6 +2350,7 @@ static const char *const rtn_type_names[
73 [RTN_THROW] = "THROW",
74 [RTN_NAT] = "NAT",
75 [RTN_XRESOLVE] = "XRESOLVE",
76 + [RTN_FAILED_POLICY] = "FAILED_POLICY",
77 };
78
79 static inline const char *rtn_type(char *buf, size_t len, unsigned int t)
80 --- a/net/ipv4/ipmr.c
81 +++ b/net/ipv4/ipmr.c
82 @@ -181,6 +181,7 @@ static int ipmr_rule_action(struct fib_r
83 case FR_ACT_UNREACHABLE:
84 return -ENETUNREACH;
85 case FR_ACT_PROHIBIT:
86 + case FR_ACT_FAILED_POLICY:
87 return -EACCES;
88 case FR_ACT_BLACKHOLE:
89 default:
90 --- a/net/ipv6/fib6_rules.c
91 +++ b/net/ipv6/fib6_rules.c
92 @@ -69,6 +69,9 @@ static int fib6_rule_action(struct fib_r
93 case FR_ACT_PROHIBIT:
94 rt = net->ipv6.ip6_prohibit_entry;
95 goto discard_pkt;
96 + case FR_ACT_FAILED_POLICY:
97 + rt = net->ipv6.ip6_failed_policy_entry;
98 + goto discard_pkt;
99 }
100
101 table = fib6_get_table(net, rule->table);
102 --- a/net/ipv6/ip6mr.c
103 +++ b/net/ipv6/ip6mr.c
104 @@ -166,6 +166,8 @@ static int ip6mr_rule_action(struct fib_
105 return -ENETUNREACH;
106 case FR_ACT_PROHIBIT:
107 return -EACCES;
108 + case FR_ACT_FAILED_POLICY:
109 + return -EPERM;
110 case FR_ACT_BLACKHOLE:
111 default:
112 return -EINVAL;
113 --- a/net/ipv6/route.c
114 +++ b/net/ipv6/route.c
115 @@ -258,6 +258,24 @@ static const struct rt6_info ip6_prohibi
116 .rt6i_ref = ATOMIC_INIT(1),
117 };
118
119 +static int ip6_pkt_failed_policy(struct sk_buff *skb);
120 +static int ip6_pkt_failed_policy_out(struct sk_buff *skb);
121 +
122 +static const struct rt6_info ip6_failed_policy_entry_template = {
123 + .dst = {
124 + .__refcnt = ATOMIC_INIT(1),
125 + .__use = 1,
126 + .obsolete = DST_OBSOLETE_FORCE_CHK,
127 + .error = -EPERM,
128 + .input = ip6_pkt_failed_policy,
129 + .output = ip6_pkt_failed_policy_out,
130 + },
131 + .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
132 + .rt6i_protocol = RTPROT_KERNEL,
133 + .rt6i_metric = ~(u32) 0,
134 + .rt6i_ref = ATOMIC_INIT(1),
135 +};
136 +
137 static const struct rt6_info ip6_blk_hole_entry_template = {
138 .dst = {
139 .__refcnt = ATOMIC_INIT(1),
140 @@ -1516,6 +1534,9 @@ int ip6_route_add(struct fib6_config *cf
141 case RTN_THROW:
142 rt->dst.error = -EAGAIN;
143 break;
144 + case RTN_FAILED_POLICY:
145 + rt->dst.error = -EPERM;
146 + break;
147 default:
148 rt->dst.error = -ENETUNREACH;
149 break;
150 @@ -2110,6 +2131,17 @@ static int ip6_pkt_prohibit_out(struct s
151 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
152 }
153
154 +static int ip6_pkt_failed_policy(struct sk_buff *skb)
155 +{
156 + return ip6_pkt_drop(skb, ICMPV6_FAILED_POLICY, IPSTATS_MIB_INNOROUTES);
157 +}
158 +
159 +static int ip6_pkt_failed_policy_out(struct sk_buff *skb)
160 +{
161 + skb->dev = skb_dst(skb)->dev;
162 + return ip6_pkt_drop(skb, ICMPV6_FAILED_POLICY, IPSTATS_MIB_OUTNOROUTES);
163 +}
164 +
165 #endif
166
167 /*
168 @@ -2321,7 +2353,8 @@ static int rtm_to_fib6_config(struct sk_
169 if (rtm->rtm_type == RTN_UNREACHABLE ||
170 rtm->rtm_type == RTN_BLACKHOLE ||
171 rtm->rtm_type == RTN_PROHIBIT ||
172 - rtm->rtm_type == RTN_THROW)
173 + rtm->rtm_type == RTN_THROW ||
174 + rtm->rtm_type == RTN_FAILED_POLICY)
175 cfg->fc_flags |= RTF_REJECT;
176
177 if (rtm->rtm_type == RTN_LOCAL)
178 @@ -2524,6 +2557,9 @@ static int rt6_fill_node(struct net *net
179 case -EACCES:
180 rtm->rtm_type = RTN_PROHIBIT;
181 break;
182 + case -EPERM:
183 + rtm->rtm_type = RTN_FAILED_POLICY;
184 + break;
185 case -EAGAIN:
186 rtm->rtm_type = RTN_THROW;
187 break;
188 @@ -2775,6 +2811,8 @@ static int ip6_route_dev_notify(struct n
189 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
190 net->ipv6.ip6_prohibit_entry->dst.dev = dev;
191 net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
192 + net->ipv6.ip6_failed_policy_entry->dst.dev = dev;
193 + net->ipv6.ip6_failed_policy_entry->rt6i_idev = in6_dev_get(dev);
194 net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
195 net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
196 #endif
197 @@ -3037,6 +3075,17 @@ static int __net_init ip6_route_net_init
198 net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
199 dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
200 ip6_template_metrics, true);
201 +
202 + net->ipv6.ip6_failed_policy_entry =
203 + kmemdup(&ip6_failed_policy_entry_template,
204 + sizeof(*net->ipv6.ip6_failed_policy_entry), GFP_KERNEL);
205 + if (!net->ipv6.ip6_failed_policy_entry)
206 + goto out_ip6_blk_hole_entry;
207 + net->ipv6.ip6_failed_policy_entry->dst.path =
208 + (struct dst_entry *)net->ipv6.ip6_failed_policy_entry;
209 + net->ipv6.ip6_failed_policy_entry->dst.ops = &net->ipv6.ip6_dst_ops;
210 + dst_init_metrics(&net->ipv6.ip6_failed_policy_entry->dst,
211 + ip6_template_metrics, true);
212 #endif
213
214 net->ipv6.sysctl.flush_delay = 0;
215 @@ -3055,6 +3104,8 @@ out:
216 return ret;
217
218 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
219 +out_ip6_blk_hole_entry:
220 + kfree(net->ipv6.ip6_blk_hole_entry);
221 out_ip6_prohibit_entry:
222 kfree(net->ipv6.ip6_prohibit_entry);
223 out_ip6_null_entry:
224 @@ -3072,6 +3123,7 @@ static void __net_exit ip6_route_net_exi
225 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
226 kfree(net->ipv6.ip6_prohibit_entry);
227 kfree(net->ipv6.ip6_blk_hole_entry);
228 + kfree(net->ipv6.ip6_failed_policy_entry);
229 #endif
230 dst_entries_destroy(&net->ipv6.ip6_dst_ops);
231 }
232 @@ -3168,6 +3220,9 @@ int __init ip6_route_init(void)
233 init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
234 init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
235 init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
236 + init_net.ipv6.ip6_failed_policy_entry->dst.dev = init_net.loopback_dev;
237 + init_net.ipv6.ip6_failed_policy_entry->rt6i_idev =
238 + in6_dev_get(init_net.loopback_dev);
239 #endif
240 ret = fib6_init();
241 if (ret)