diff options
author | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2008-04-02 20:22:53 -0400 |
---|---|---|
committer | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2008-04-05 09:33:38 -0400 |
commit | 7bc570c8b4f75ddb3fd5dbeb38127cdc4acbcc9c (patch) | |
tree | b688b728c3ea08479f75986d1e9f590fca1f8715 /net/ipv6/ip6_input.c | |
parent | 80a9492a33dd7d852465625022d56ff76d62174d (diff) |
[IPV6] MROUTE: Support multicast forwarding.
Based on ancient patch by Mickael Hoerdt
<hoerdt@clarinet.u-strasbg.fr>, which is available at
<http://www-r2.u-strasbg.fr/~hoerdt/dev/linux_ipv6_mforwarding/patch-linux-ipv6-mforwarding-0.1a>.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Diffstat (limited to 'net/ipv6/ip6_input.c')
-rw-r--r-- | net/ipv6/ip6_input.c | 87 |
1 files changed, 68 insertions, 19 deletions
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 43a617e2268b..09a3201e408a 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/netdevice.h> | 29 | #include <linux/netdevice.h> |
30 | #include <linux/in6.h> | 30 | #include <linux/in6.h> |
31 | #include <linux/icmpv6.h> | 31 | #include <linux/icmpv6.h> |
32 | #include <linux/mroute6.h> | ||
32 | 33 | ||
33 | #include <linux/netfilter.h> | 34 | #include <linux/netfilter.h> |
34 | #include <linux/netfilter_ipv6.h> | 35 | #include <linux/netfilter_ipv6.h> |
@@ -236,36 +237,84 @@ int ip6_mc_input(struct sk_buff *skb) | |||
236 | hdr = ipv6_hdr(skb); | 237 | hdr = ipv6_hdr(skb); |
237 | deliver = ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, NULL); | 238 | deliver = ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, NULL); |
238 | 239 | ||
240 | #ifdef CONFIG_IPV6_MROUTE | ||
239 | /* | 241 | /* |
240 | * IPv6 multicast router mode isnt currently supported. | 242 | * IPv6 multicast router mode is now supported ;) |
241 | */ | 243 | */ |
242 | #if 0 | 244 | if (ipv6_devconf.mc_forwarding && |
243 | if (ipv6_config.multicast_route) { | 245 | likely(!(IP6CB(skb)->flags & IP6SKB_FORWARDED))) { |
244 | int addr_type; | 246 | /* |
245 | 247 | * Okay, we try to forward - split and duplicate | |
246 | addr_type = ipv6_addr_type(&hdr->daddr); | 248 | * packets. |
247 | 249 | */ | |
248 | if (!(addr_type & (IPV6_ADDR_LOOPBACK | IPV6_ADDR_LINKLOCAL))) { | 250 | struct sk_buff *skb2; |
249 | struct sk_buff *skb2; | 251 | struct inet6_skb_parm *opt = IP6CB(skb); |
250 | struct dst_entry *dst; | 252 | |
253 | /* Check for MLD */ | ||
254 | if (unlikely(opt->ra)) { | ||
255 | /* Check if this is a mld message */ | ||
256 | u8 *ptr = skb_network_header(skb) + opt->ra; | ||
257 | struct icmp6hdr *icmp6; | ||
258 | u8 nexthdr = hdr->nexthdr; | ||
259 | int offset; | ||
260 | |||
261 | /* Check if the value of Router Alert | ||
262 | * is for MLD (0x0000). | ||
263 | */ | ||
264 | if ((ptr[2] | ptr[3]) == 0) { | ||
265 | if (!ipv6_ext_hdr(nexthdr)) { | ||
266 | /* BUG */ | ||
267 | goto discard; | ||
268 | } | ||
269 | offset = ipv6_skip_exthdr(skb, sizeof(*hdr), | ||
270 | &nexthdr); | ||
271 | if (offset < 0) | ||
272 | goto discard; | ||
273 | |||
274 | if (nexthdr != IPPROTO_ICMPV6) | ||
275 | goto discard; | ||
276 | |||
277 | if (!pskb_may_pull(skb, (skb_network_header(skb) + | ||
278 | offset + 1 - skb->data))) | ||
279 | goto discard; | ||
280 | |||
281 | icmp6 = (struct icmp6hdr *)(skb_network_header(skb) + offset); | ||
282 | |||
283 | switch (icmp6->icmp6_type) { | ||
284 | case ICMPV6_MGM_QUERY: | ||
285 | case ICMPV6_MGM_REPORT: | ||
286 | case ICMPV6_MGM_REDUCTION: | ||
287 | case ICMPV6_MLD2_REPORT: | ||
288 | break; | ||
289 | default: | ||
290 | /* Bogus */ | ||
291 | goto discard; | ||
292 | } | ||
293 | deliver = 1; | ||
294 | goto out; | ||
295 | } | ||
296 | /* unknown RA - process it normally */ | ||
297 | } | ||
251 | 298 | ||
252 | dst = skb->dst; | 299 | if (deliver) |
300 | skb2 = skb_clone(skb, GFP_ATOMIC); | ||
301 | else { | ||
302 | skb2 = skb; | ||
303 | skb = NULL; | ||
304 | } | ||
253 | 305 | ||
254 | if (deliver) { | 306 | if (skb2) { |
255 | skb2 = skb_clone(skb, GFP_ATOMIC); | 307 | skb2->dev = skb2->dst->dev; |
256 | dst_output(skb2); | 308 | ip6_mr_input(skb2); |
257 | } else { | ||
258 | dst_output(skb); | ||
259 | return 0; | ||
260 | } | ||
261 | } | 309 | } |
262 | } | 310 | } |
263 | #endif | 311 | #endif |
264 | 312 | out: | |
265 | if (likely(deliver)) { | 313 | if (likely(deliver)) { |
266 | ip6_input(skb); | 314 | ip6_input(skb); |
267 | return 0; | 315 | return 0; |
268 | } | 316 | } |
317 | discard: | ||
269 | /* discard */ | 318 | /* discard */ |
270 | kfree_skb(skb); | 319 | kfree_skb(skb); |
271 | 320 | ||