diff options
Diffstat (limited to 'net/ipv6/mip6.c')
-rw-r--r-- | net/ipv6/mip6.c | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c index 7b5f89321482..31445d09261e 100644 --- a/net/ipv6/mip6.c +++ b/net/ipv6/mip6.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/config.h> | 25 | #include <linux/config.h> |
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/skbuff.h> | 27 | #include <linux/skbuff.h> |
28 | #include <linux/time.h> | ||
28 | #include <linux/ipv6.h> | 29 | #include <linux/ipv6.h> |
29 | #include <linux/icmpv6.h> | 30 | #include <linux/icmpv6.h> |
30 | #include <net/sock.h> | 31 | #include <net/sock.h> |
@@ -138,6 +139,18 @@ int mip6_mh_filter(struct sock *sk, struct sk_buff *skb) | |||
138 | return 0; | 139 | return 0; |
139 | } | 140 | } |
140 | 141 | ||
142 | struct mip6_report_rate_limiter { | ||
143 | spinlock_t lock; | ||
144 | struct timeval stamp; | ||
145 | int iif; | ||
146 | struct in6_addr src; | ||
147 | struct in6_addr dst; | ||
148 | }; | ||
149 | |||
150 | static struct mip6_report_rate_limiter mip6_report_rl = { | ||
151 | .lock = SPIN_LOCK_UNLOCKED | ||
152 | }; | ||
153 | |||
141 | static int mip6_destopt_input(struct xfrm_state *x, struct sk_buff *skb) | 154 | static int mip6_destopt_input(struct xfrm_state *x, struct sk_buff *skb) |
142 | { | 155 | { |
143 | struct ipv6hdr *iph = skb->nh.ipv6h; | 156 | struct ipv6hdr *iph = skb->nh.ipv6h; |
@@ -189,6 +202,75 @@ static int mip6_destopt_output(struct xfrm_state *x, struct sk_buff *skb) | |||
189 | return 0; | 202 | return 0; |
190 | } | 203 | } |
191 | 204 | ||
205 | static inline int mip6_report_rl_allow(struct timeval *stamp, | ||
206 | struct in6_addr *dst, | ||
207 | struct in6_addr *src, int iif) | ||
208 | { | ||
209 | int allow = 0; | ||
210 | |||
211 | spin_lock_bh(&mip6_report_rl.lock); | ||
212 | if (mip6_report_rl.stamp.tv_sec != stamp->tv_sec || | ||
213 | mip6_report_rl.stamp.tv_usec != stamp->tv_usec || | ||
214 | mip6_report_rl.iif != iif || | ||
215 | !ipv6_addr_equal(&mip6_report_rl.src, src) || | ||
216 | !ipv6_addr_equal(&mip6_report_rl.dst, dst)) { | ||
217 | mip6_report_rl.stamp.tv_sec = stamp->tv_sec; | ||
218 | mip6_report_rl.stamp.tv_usec = stamp->tv_usec; | ||
219 | mip6_report_rl.iif = iif; | ||
220 | ipv6_addr_copy(&mip6_report_rl.src, src); | ||
221 | ipv6_addr_copy(&mip6_report_rl.dst, dst); | ||
222 | allow = 1; | ||
223 | } | ||
224 | spin_unlock_bh(&mip6_report_rl.lock); | ||
225 | return allow; | ||
226 | } | ||
227 | |||
228 | static int mip6_destopt_reject(struct xfrm_state *x, struct sk_buff *skb, struct flowi *fl) | ||
229 | { | ||
230 | struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb; | ||
231 | struct ipv6_destopt_hao *hao = NULL; | ||
232 | struct xfrm_selector sel; | ||
233 | int offset; | ||
234 | struct timeval stamp; | ||
235 | int err = 0; | ||
236 | |||
237 | if (likely(opt->dsthao)) { | ||
238 | offset = ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO); | ||
239 | if (likely(offset >= 0)) | ||
240 | hao = (struct ipv6_destopt_hao *)(skb->nh.raw + offset); | ||
241 | } | ||
242 | |||
243 | skb_get_timestamp(skb, &stamp); | ||
244 | |||
245 | if (!mip6_report_rl_allow(&stamp, &skb->nh.ipv6h->daddr, | ||
246 | hao ? &hao->addr : &skb->nh.ipv6h->saddr, | ||
247 | opt->iif)) | ||
248 | goto out; | ||
249 | |||
250 | memset(&sel, 0, sizeof(sel)); | ||
251 | memcpy(&sel.daddr, (xfrm_address_t *)&skb->nh.ipv6h->daddr, | ||
252 | sizeof(sel.daddr)); | ||
253 | sel.prefixlen_d = 128; | ||
254 | memcpy(&sel.saddr, (xfrm_address_t *)&skb->nh.ipv6h->saddr, | ||
255 | sizeof(sel.saddr)); | ||
256 | sel.prefixlen_s = 128; | ||
257 | sel.family = AF_INET6; | ||
258 | sel.proto = fl->proto; | ||
259 | sel.dport = xfrm_flowi_dport(fl); | ||
260 | if (sel.dport) | ||
261 | sel.dport_mask = ~((__u16)0); | ||
262 | sel.sport = xfrm_flowi_sport(fl); | ||
263 | if (sel.sport) | ||
264 | sel.sport_mask = ~((__u16)0); | ||
265 | sel.ifindex = fl->oif; | ||
266 | |||
267 | err = km_report(IPPROTO_DSTOPTS, &sel, | ||
268 | (hao ? (xfrm_address_t *)&hao->addr : NULL)); | ||
269 | |||
270 | out: | ||
271 | return err; | ||
272 | } | ||
273 | |||
192 | static int mip6_destopt_offset(struct xfrm_state *x, struct sk_buff *skb, | 274 | static int mip6_destopt_offset(struct xfrm_state *x, struct sk_buff *skb, |
193 | u8 **nexthdr) | 275 | u8 **nexthdr) |
194 | { | 276 | { |
@@ -273,6 +355,7 @@ static struct xfrm_type mip6_destopt_type = | |||
273 | .destructor = mip6_destopt_destroy, | 355 | .destructor = mip6_destopt_destroy, |
274 | .input = mip6_destopt_input, | 356 | .input = mip6_destopt_input, |
275 | .output = mip6_destopt_output, | 357 | .output = mip6_destopt_output, |
358 | .reject = mip6_destopt_reject, | ||
276 | .hdr_offset = mip6_destopt_offset, | 359 | .hdr_offset = mip6_destopt_offset, |
277 | .local_addr = mip6_xfrm_addr, | 360 | .local_addr = mip6_xfrm_addr, |
278 | }; | 361 | }; |