aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_input.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ip6_input.c')
-rw-r--r--net/ipv6/ip6_input.c98
1 files changed, 70 insertions, 28 deletions
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 98ab4f459905..4e5c8615832c 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>
@@ -61,11 +62,6 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
61 u32 pkt_len; 62 u32 pkt_len;
62 struct inet6_dev *idev; 63 struct inet6_dev *idev;
63 64
64 if (dev->nd_net != &init_net) {
65 kfree_skb(skb);
66 return 0;
67 }
68
69 if (skb->pkt_type == PACKET_OTHERHOST) { 65 if (skb->pkt_type == PACKET_OTHERHOST) {
70 kfree_skb(skb); 66 kfree_skb(skb);
71 return 0; 67 return 0;
@@ -241,38 +237,84 @@ int ip6_mc_input(struct sk_buff *skb)
241 hdr = ipv6_hdr(skb); 237 hdr = ipv6_hdr(skb);
242 deliver = ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, NULL); 238 deliver = ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, NULL);
243 239
240#ifdef CONFIG_IPV6_MROUTE
244 /* 241 /*
245 * IPv6 multicast router mode isnt currently supported. 242 * IPv6 multicast router mode is now supported ;)
246 */ 243 */
247#if 0 244 if (ipv6_devconf.mc_forwarding &&
248 if (ipv6_config.multicast_route) { 245 likely(!(IP6CB(skb)->flags & IP6SKB_FORWARDED))) {
249 int addr_type; 246 /*
250 247 * Okay, we try to forward - split and duplicate
251 addr_type = ipv6_addr_type(&hdr->daddr); 248 * packets.
252 249 */
253 if (!(addr_type & (IPV6_ADDR_LOOPBACK | IPV6_ADDR_LINKLOCAL))) { 250 struct sk_buff *skb2;
254 struct sk_buff *skb2; 251 struct inet6_skb_parm *opt = IP6CB(skb);
255 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 deliver = 0;
266
267 if (!ipv6_ext_hdr(nexthdr)) {
268 /* BUG */
269 goto out;
270 }
271 offset = ipv6_skip_exthdr(skb, sizeof(*hdr),
272 &nexthdr);
273 if (offset < 0)
274 goto out;
275
276 if (nexthdr != IPPROTO_ICMPV6)
277 goto out;
278
279 if (!pskb_may_pull(skb, (skb_network_header(skb) +
280 offset + 1 - skb->data)))
281 goto out;
282
283 icmp6 = (struct icmp6hdr *)(skb_network_header(skb) + offset);
284
285 switch (icmp6->icmp6_type) {
286 case ICMPV6_MGM_QUERY:
287 case ICMPV6_MGM_REPORT:
288 case ICMPV6_MGM_REDUCTION:
289 case ICMPV6_MLD2_REPORT:
290 deliver = 1;
291 break;
292 }
293 goto out;
294 }
295 /* unknown RA - process it normally */
296 }
256 297
257 dst = skb->dst; 298 if (deliver)
299 skb2 = skb_clone(skb, GFP_ATOMIC);
300 else {
301 skb2 = skb;
302 skb = NULL;
303 }
258 304
259 if (deliver) { 305 if (skb2) {
260 skb2 = skb_clone(skb, GFP_ATOMIC); 306 skb2->dev = skb2->dst->dev;
261 dst_output(skb2); 307 ip6_mr_input(skb2);
262 } else {
263 dst_output(skb);
264 return 0;
265 }
266 } 308 }
267 } 309 }
310out:
268#endif 311#endif
269 312 if (likely(deliver))
270 if (likely(deliver)) {
271 ip6_input(skb); 313 ip6_input(skb);
272 return 0; 314 else {
315 /* discard */
316 kfree_skb(skb);
273 } 317 }
274 /* discard */
275 kfree_skb(skb);
276 318
277 return 0; 319 return 0;
278} 320}