Commit 36b609df authored by David S. Miller's avatar David S. Miller

Merge bk://kernel.bkbits.net/jmorris/net-2.5

into nuts.ninka.net:/home/davem/src/BK/net-2.5
parents 3cee4c3f 9e9d4917
......@@ -217,7 +217,6 @@ struct pimreghdr
__u32 flags;
};
extern int pim_rcv(struct sk_buff *);
extern int pim_rcv_v1(struct sk_buff *);
struct rtmsg;
......
......@@ -757,9 +757,10 @@ static void igmp_heard_report(struct in_device *in_dev, u32 group)
read_unlock(&in_dev->lock);
}
static void igmp_heard_query(struct in_device *in_dev, struct igmphdr *ih,
static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
int len)
{
struct igmphdr *ih = skb->h.igmph;
struct igmpv3_query *ih3 = (struct igmpv3_query *)ih;
struct ip_mc_list *im;
u32 group = ih->group;
......@@ -790,6 +791,17 @@ static void igmp_heard_query(struct in_device *in_dev, struct igmphdr *ih,
} else if (len < 12) {
return; /* ignore bogus packet; freed by caller */
} else { /* v3 */
if (!pskb_may_pull(skb, sizeof(struct igmpv3_query)))
return;
ih3 = (struct igmpv3_query *) skb->h.raw;
if (ih3->nsrcs) {
if (!pskb_may_pull(skb, sizeof(struct igmpv3_query)
+ ntohs(ih3->nsrcs)*sizeof(__u32)))
return;
ih3 = (struct igmpv3_query *) skb->h.raw;
}
max_delay = IGMPV3_MRC(ih3->code)*(HZ/IGMP_TIMER_SCALE);
if (!max_delay)
max_delay = 1; /* can't mod w/ 0 */
......@@ -838,7 +850,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct igmphdr *ih,
int igmp_rcv(struct sk_buff *skb)
{
/* This basically follows the spec line by line -- see RFC1112 */
struct igmphdr *ih = skb->h.igmph;
struct igmphdr *ih;
struct in_device *in_dev = in_dev_get(skb->dev);
int len = skb->len;
......@@ -847,23 +859,17 @@ int igmp_rcv(struct sk_buff *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)) {
if (!pskb_may_pull(skb, sizeof(struct igmphdr)) ||
(u16)csum_fold(skb_checksum(skb, 0, len, 0))) {
in_dev_put(in_dev);
kfree_skb(skb);
return 0;
}
ih = skb->h.igmph;
switch (ih->type) {
case IGMP_HOST_MEMBERSHIP_QUERY:
igmp_heard_query(in_dev, ih, len);
igmp_heard_query(in_dev, skb, len);
break;
case IGMP_HOST_MEMBERSHIP_REPORT:
case IGMPV2_HOST_MEMBERSHIP_REPORT:
......
......@@ -83,13 +83,13 @@ static int maxvif;
#define VIF_EXISTS(idx) (vif_table[idx].dev != NULL)
int mroute_do_assert; /* Set in PIM assert */
int mroute_do_pim;
static int mroute_do_assert; /* Set in PIM assert */
static int mroute_do_pim;
static struct mfc_cache *mfc_cache_array[MFC_LINES]; /* Forwarding cache */
static struct mfc_cache *mfc_unres_queue; /* Queue of unresolved entries */
atomic_t cache_resolve_queue_len; /* Size of unresolved */
static atomic_t cache_resolve_queue_len; /* Size of unresolved */
/* Special spinlock for queue of unresolved entries */
static spinlock_t mfc_unres_lock = SPIN_LOCK_UNLOCKED;
......@@ -102,7 +102,7 @@ static spinlock_t mfc_unres_lock = SPIN_LOCK_UNLOCKED;
In this case data path is free of exclusive locks at all.
*/
kmem_cache_t *mrt_cachep;
static kmem_cache_t *mrt_cachep;
static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local);
static int ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert);
......@@ -158,6 +158,10 @@ struct net_device *ipmr_new_tunnel(struct vifctl *v)
return dev;
failure:
/* allow the register to be completed before unregistering. */
rtnl_unlock();
rtnl_lock();
unregister_netdevice(dev);
return NULL;
}
......@@ -182,35 +186,23 @@ static struct net_device_stats *reg_vif_get_stats(struct net_device *dev)
return (struct net_device_stats*)dev->priv;
}
static void vif_dev_destructor(struct net_device *dev)
static void reg_vif_setup(struct net_device *dev)
{
kfree(dev);
dev->type = ARPHRD_PIMREG;
dev->mtu = 1500 - sizeof(struct iphdr) - 8;
dev->flags = IFF_NOARP;
dev->hard_start_xmit = reg_vif_xmit;
dev->get_stats = reg_vif_get_stats;
dev->destructor = (void (*)(struct net_device *)) kfree;
}
static
struct net_device *ipmr_reg_vif(struct vifctl *v)
static struct net_device *ipmr_reg_vif(void)
{
struct net_device *dev;
struct in_device *in_dev;
int size;
size = sizeof(*dev) + sizeof(struct net_device_stats);
dev = kmalloc(size, GFP_KERNEL);
if (!dev)
return NULL;
memset(dev, 0, size);
dev->priv = dev + 1;
strcpy(dev->name, "pimreg");
dev->type = ARPHRD_PIMREG;
dev->mtu = 1500 - sizeof(struct iphdr) - 8;
dev->flags = IFF_NOARP;
dev->hard_start_xmit = reg_vif_xmit;
dev->get_stats = reg_vif_get_stats;
dev->destructor = vif_dev_destructor;
dev = alloc_netdev(sizeof(struct net_device_stats), "pimreg",
reg_vif_setup);
if (register_netdevice(dev)) {
kfree(dev);
......@@ -229,6 +221,10 @@ struct net_device *ipmr_reg_vif(struct vifctl *v)
return dev;
failure:
/* allow the register to be completed before unregistering. */
rtnl_unlock();
rtnl_lock();
unregister_netdevice(dev);
return NULL;
}
......@@ -316,7 +312,7 @@ static void ipmr_destroy_unres(struct mfc_cache *c)
/* Single timer process for all the unresolved queue. */
void ipmr_expire_process(unsigned long dummy)
static void ipmr_expire_process(unsigned long dummy)
{
unsigned long now;
unsigned long expires;
......@@ -335,9 +331,8 @@ void ipmr_expire_process(unsigned long dummy)
cp = &mfc_unres_queue;
while ((c=*cp) != NULL) {
long interval = c->mfc_un.unres.expires - now;
if (interval > 0) {
if (time_after(c->mfc_un.unres.expires, now)) {
unsigned long interval = c->mfc_un.unres.expires - now;
if (interval < expires)
expires = interval;
cp = &c->next;
......@@ -397,7 +392,7 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
*/
if (reg_vif_num >= 0)
return -EADDRINUSE;
dev = ipmr_reg_vif(vifc);
dev = ipmr_reg_vif();
if (!dev)
return -ENOBUFS;
break;
......@@ -683,7 +678,7 @@ ipmr_cache_unresolved(vifi_t vifi, struct sk_buff *skb)
* MFC cache manipulation by user space mroute daemon
*/
int ipmr_mfc_delete(struct mfcctl *mfc)
static int ipmr_mfc_delete(struct mfcctl *mfc)
{
int line;
struct mfc_cache *c, **cp;
......@@ -704,7 +699,7 @@ int ipmr_mfc_delete(struct mfcctl *mfc)
return -ENOENT;
}
int ipmr_mfc_add(struct mfcctl *mfc, int mrtsock)
static int ipmr_mfc_add(struct mfcctl *mfc, int mrtsock)
{
int line;
struct mfc_cache *uc, *c, **cp;
......@@ -1078,9 +1073,7 @@ static int ipmr_device_event(struct notifier_block *this, unsigned long event, v
static struct notifier_block ip_mr_notifier={
ipmr_device_event,
NULL,
0
.notifier_call = ipmr_device_event,
};
/*
......@@ -1234,7 +1227,7 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c,
ipmr_forward_finish);
}
int ipmr_find_vif(struct net_device *dev)
static int ipmr_find_vif(struct net_device *dev)
{
int ct;
for (ct=maxvif-1; ct>=0; ct--) {
......@@ -1246,7 +1239,7 @@ int ipmr_find_vif(struct net_device *dev)
/* "local" means that we should preserve one skb (for local delivery) */
int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local)
static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local)
{
int psend = -1;
int vif, ct;
......@@ -1286,7 +1279,8 @@ int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local)
large chunk of pimd to kernel. Ough... --ANK
*/
(mroute_do_pim || cache->mfc_un.res.ttls[true_vifi] < 255) &&
jiffies - cache->mfc_un.res.last_assert > MFC_ASSERT_THRESH) {
time_after(jiffies,
cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) {
cache->mfc_un.res.last_assert = jiffies;
ipmr_cache_report(skb, true_vifi, IGMPMSG_WRONGVIF);
}
......@@ -1406,24 +1400,19 @@ int ip_mr_input(struct sk_buff *skb)
int pim_rcv_v1(struct sk_buff * skb)
{
struct igmphdr *pim = (struct igmphdr*)skb->h.raw;
struct igmphdr *pim;
struct iphdr *encap;
struct net_device *reg_dev = NULL;
if (skb_is_nonlinear(skb)) {
if (skb_linearize(skb, GFP_ATOMIC) != 0) {
kfree_skb(skb);
return -ENOMEM;
}
if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))
goto drop;
pim = (struct igmphdr*)skb->h.raw;
}
if (!mroute_do_pim ||
skb->len < sizeof(*pim) + sizeof(*encap) ||
pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER) {
kfree_skb(skb);
return -EINVAL;
}
pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER)
goto drop;
encap = (struct iphdr*)(skb->h.raw + sizeof(struct igmphdr));
/*
......@@ -1433,11 +1422,9 @@ int pim_rcv_v1(struct sk_buff * skb)
c. packet is not truncated
*/
if (!MULTICAST(encap->daddr) ||
ntohs(encap->tot_len) == 0 ||
ntohs(encap->tot_len) + sizeof(*pim) > skb->len) {
kfree_skb(skb);
return -EINVAL;
}
encap->tot_len == 0 ||
ntohs(encap->tot_len) + sizeof(*pim) > skb->len)
goto drop;
read_lock(&mrt_lock);
if (reg_vif_num >= 0)
......@@ -1446,10 +1433,8 @@ int pim_rcv_v1(struct sk_buff * skb)
dev_hold(reg_dev);
read_unlock(&mrt_lock);
if (reg_dev == NULL) {
kfree_skb(skb);
return -EINVAL;
}
if (reg_dev == NULL)
goto drop;
skb->mac.raw = skb->nh.raw;
skb_pull(skb, (u8*)encap - skb->data);
......@@ -1470,41 +1455,35 @@ int pim_rcv_v1(struct sk_buff * skb)
netif_rx(skb);
dev_put(reg_dev);
return 0;
drop:
kfree_skb(skb);
return 0;
}
#endif
#ifdef CONFIG_IP_PIMSM_V2
int pim_rcv(struct sk_buff * skb)
static int pim_rcv(struct sk_buff * skb)
{
struct pimreghdr *pim = (struct pimreghdr*)skb->h.raw;
struct pimreghdr *pim;
struct iphdr *encap;
struct net_device *reg_dev = NULL;
if (skb_is_nonlinear(skb)) {
if (skb_linearize(skb, GFP_ATOMIC) != 0) {
kfree_skb(skb);
return -ENOMEM;
}
pim = (struct pimreghdr*)skb->h.raw;
}
if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap)))
goto drop;
if (skb->len < sizeof(*pim) + sizeof(*encap) ||
pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) ||
pim = (struct pimreghdr*)skb->h.raw;
if (pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) ||
(pim->flags&PIM_NULL_REGISTER) ||
(ip_compute_csum((void *)pim, sizeof(*pim)) != 0 &&
ip_compute_csum((void *)pim, skb->len))) {
kfree_skb(skb);
return -EINVAL;
}
(u16)csum_fold(skb_checksum(skb, 0, skb->len, 0))))
goto drop;
/* check if the inner packet is destined to mcast group */
encap = (struct iphdr*)(skb->h.raw + sizeof(struct pimreghdr));
if (!MULTICAST(encap->daddr) ||
ntohs(encap->tot_len) == 0 ||
ntohs(encap->tot_len) + sizeof(*pim) > skb->len) {
kfree_skb(skb);
return -EINVAL;
}
encap->tot_len == 0 ||
ntohs(encap->tot_len) + sizeof(*pim) > skb->len)
goto drop;
read_lock(&mrt_lock);
if (reg_vif_num >= 0)
......@@ -1513,10 +1492,8 @@ int pim_rcv(struct sk_buff * skb)
dev_hold(reg_dev);
read_unlock(&mrt_lock);
if (reg_dev == NULL) {
kfree_skb(skb);
return -EINVAL;
}
if (reg_dev == NULL)
goto drop;
skb->mac.raw = skb->nh.raw;
skb_pull(skb, (u8*)encap - skb->data);
......@@ -1537,6 +1514,9 @@ int pim_rcv(struct sk_buff * skb)
netif_rx(skb);
dev_put(reg_dev);
return 0;
drop:
kfree_skb(skb);
return 0;
}
#endif
......
......@@ -713,6 +713,7 @@ void ndisc_recv_ns(struct sk_buff *skb)
struct net_device *dev = skb->dev;
struct inet6_ifaddr *ifp;
struct neighbour *neigh;
int addr_type = ipv6_addr_type(saddr);
if (ipv6_addr_type(&msg->target)&IPV6_ADDR_MULTICAST) {
if (net_ratelimit())
......@@ -720,6 +721,20 @@ void ndisc_recv_ns(struct sk_buff *skb)
return;
}
/*
* RFC2461 7.1.1:
* DAD has to be destined for solicited node multicast address.
*/
if (addr_type == IPV6_ADDR_ANY &&
!(daddr->s6_addr32[0] == htonl(0xff020000) &&
daddr->s6_addr32[1] == htonl(0x00000000) &&
daddr->s6_addr32[2] == htonl(0x00000001) &&
daddr->s6_addr [12] == 0xff )) {
if (net_ratelimit())
printk(KERN_DEBUG "ICMP6 NS: bad DAD packet (wrong destination)\n");
return;
}
if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
if (net_ratelimit())
printk(KERN_WARNING "ICMP NS: invalid ND option, ignored.\n");
......@@ -734,23 +749,20 @@ void ndisc_recv_ns(struct sk_buff *skb)
printk(KERN_WARNING "ICMP NS: bad lladdr length.\n");
return;
}
}
/* XXX: RFC2461 7.1.1:
* If the IP source address is the unspecified address, there
* MUST NOT be source link-layer address option in the message.
*
* NOTE! Linux kernel < 2.4.4 broke this rule.
*/
/* XXX: RFC2461 7.1.1:
* If the IP source address is the unspecified address, the IP
* destination address MUST be a solicited-node multicast address.
* If the IP source address is the unspecified address,
* there MUST NOT be source link-layer address option
* in the message.
*/
if (addr_type == IPV6_ADDR_ANY) {
if (net_ratelimit())
printk(KERN_WARNING "ICMP6 NS: bad DAD packet (link-layer address option)\n");
return;
}
}
if ((ifp = ipv6_get_ifaddr(&msg->target, dev)) != NULL) {
int addr_type = ipv6_addr_type(saddr);
if (ifp->flags & IFA_F_TENTATIVE) {
/* Address is tentative. If the source
is unspecified address, it is someone
......@@ -816,7 +828,6 @@ void ndisc_recv_ns(struct sk_buff *skb)
in6_ifa_put(ifp);
} else if (ipv6_chk_acast_addr(dev, &msg->target)) {
struct inet6_dev *idev = in6_dev_get(dev);
int addr_type = ipv6_addr_type(saddr);
/* anycast */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment