if (in_dev==NULL) {
kfree_skb(skb);
return 0;
}
if (skb_is_nonlinear(skb)) {
if (skb_linearize(skb, GFP_ATOMIC) != 0) {
kfree_skb(skb);
return -ENOMEM;
}
ih = skb->h.igmph;
}
if (len < sizeof(struct igmphdr) || ip_compute_csum((void *)ih,
len)) {
in_dev_put(in_dev);
kfree_skb(skb);
return 0;
}
/*
Checks if packet's ethernet address is a Multicast
ethernet address. If not, packet is dropped
*/
if (skb->pkt_type!=PACKET_MULTICAST) {
in_dev_put(in_dev);
kfree_skb(skb);
return 0;
}
switch (ih->type) {
case IGMP_HOST_MEMBERSHIP_QUERY:
igmp_heard_query(in_dev, ih->code, ih->group);
break;
case IGMP_HOST_MEMBERSHIP_REPORT:
case IGMP_HOST_NEW_MEMBERSHIP_REPORT:
/* Is it our report looped back? */
if (((struct rtable*)skb->dst)->key.iif == 0)
break;
igmp_heard_report(in_dev, ih->group);
break;
case IGMP_PIM:
#ifdef CONFIG_IP_PIMSM_V1
in_dev_put(in_dev);
return pim_rcv_v1(skb);
#endif
case IGMP_DVMRP:
case IGMP_TRACE:
case IGMP_HOST_LEAVE_MESSAGE:
case IGMP_MTRACE:
case IGMP_MTRACE_RESP:
break;
default:
NETDEBUG(printk(KERN_DEBUG "New IGMP type=%d, why we do not
know about it?\n", ih->type));
}
in_dev_put(in_dev);
kfree_skb(skb);
return 0;
}