aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_input.c
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2008-04-02 20:22:53 -0400
committerYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2008-04-05 09:33:38 -0400
commit7bc570c8b4f75ddb3fd5dbeb38127cdc4acbcc9c (patch)
treeb688b728c3ea08479f75986d1e9f590fca1f8715 /net/ipv6/ip6_input.c
parent80a9492a33dd7d852465625022d56ff76d62174d (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.c87
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 312out:
265 if (likely(deliver)) { 313 if (likely(deliver)) {
266 ip6_input(skb); 314 ip6_input(skb);
267 return 0; 315 return 0;
268 } 316 }
317discard:
269 /* discard */ 318 /* discard */
270 kfree_skb(skb); 319 kfree_skb(skb);
271 320