X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv4%2Fipmr.c;h=ecb5422ea237d0ad811a46fa924ecd01d66720d9;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=ca7e1e57e44b4e95dc062fa86e61753af675e726;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index ca7e1e57e..ecb5422ea 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -28,11 +28,11 @@ * */ -#include #include #include #include #include +#include #include #include #include @@ -49,9 +49,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -73,7 +75,7 @@ static struct sock *mroute_socket; Note that the changes are semaphored via rtnl_lock. */ -static rwlock_t mrt_lock = RW_LOCK_UNLOCKED; +static DEFINE_RWLOCK(mrt_lock); /* * Multicast router control variables @@ -93,7 +95,7 @@ static struct mfc_cache *mfc_unres_queue; /* Queue of unresolved entries */ 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; +static DEFINE_SPINLOCK(mfc_unres_lock); /* We return to original Alan's scheme. Hash table of resolved entries is changed only in process context and protected @@ -103,13 +105,15 @@ static spinlock_t mfc_unres_lock = SPIN_LOCK_UNLOCKED; In this case data path is free of exclusive locks at all. */ -static kmem_cache_t *mrt_cachep; +static struct kmem_cache *mrt_cachep __read_mostly; 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); static int ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm); -static struct inet_protocol pim_protocol; +#ifdef CONFIG_IP_PIMSM_V2 +static struct net_protocol pim_protocol; +#endif static struct timer_list ipmr_expire_timer; @@ -147,7 +151,7 @@ struct net_device *ipmr_new_tunnel(struct vifctl *v) if (err == 0 && (dev = __dev_get_by_name(p.name)) != NULL) { dev->flags |= IFF_MULTICAST; - in_dev = __in_dev_get(dev); + in_dev = __in_dev_get_rtnl(dev); if (in_dev == NULL && (in_dev = inetdev_init(dev)) == NULL) goto failure; in_dev->cnf.rp_filter = 0; @@ -174,8 +178,8 @@ static int reg_vif_num = -1; static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev) { read_lock(&mrt_lock); - ((struct net_device_stats*)dev->priv)->tx_bytes += skb->len; - ((struct net_device_stats*)dev->priv)->tx_packets++; + ((struct net_device_stats*)netdev_priv(dev))->tx_bytes += skb->len; + ((struct net_device_stats*)netdev_priv(dev))->tx_packets++; ipmr_cache_report(skb, reg_vif_num, IGMPMSG_WHOLEPKT); read_unlock(&mrt_lock); kfree_skb(skb); @@ -184,13 +188,13 @@ static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *reg_vif_get_stats(struct net_device *dev) { - return (struct net_device_stats*)dev->priv; + return (struct net_device_stats*)netdev_priv(dev); } static void reg_vif_setup(struct net_device *dev) { dev->type = ARPHRD_PIMREG; - dev->mtu = 1500 - sizeof(struct iphdr) - 8; + dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 8; dev->flags = IFF_NOARP; dev->hard_start_xmit = reg_vif_xmit; dev->get_stats = reg_vif_get_stats; @@ -276,7 +280,7 @@ static int vif_delete(int vifi) dev_set_allmulti(dev, -1); - if ((in_dev = __in_dev_get(dev)) != NULL) { + if ((in_dev = __in_dev_get_rtnl(dev)) != NULL) { in_dev->cnf.mc_forwarding--; ip_rt_multicast_event(in_dev); } @@ -295,6 +299,7 @@ static int vif_delete(int vifi) static void ipmr_destroy_unres(struct mfc_cache *c) { struct sk_buff *skb; + struct nlmsgerr *e; atomic_dec(&cache_resolve_queue_len); @@ -304,8 +309,11 @@ static void ipmr_destroy_unres(struct mfc_cache *c) nlh->nlmsg_type = NLMSG_ERROR; nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr)); skb_trim(skb, nlh->nlmsg_len); - ((struct nlmsgerr*)NLMSG_DATA(nlh))->error = -ETIMEDOUT; - netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT); + e = NLMSG_DATA(nlh); + e->error = -ETIMEDOUT; + memset(&e->msg, 0, sizeof(e->msg)); + + rtnl_unicast(skb, NETLINK_CB(skb).pid); } else kfree_skb(skb); } @@ -357,7 +365,7 @@ out: /* Fill oifs list. It is called under write locked mrt_lock. */ -static void ipmr_update_threshoulds(struct mfc_cache *cache, unsigned char *ttls) +static void ipmr_update_thresholds(struct mfc_cache *cache, unsigned char *ttls) { int vifi; @@ -407,16 +415,16 @@ static int vif_add(struct vifctl *vifc, int mrtsock) return -ENOBUFS; break; case 0: - dev=ip_dev_find(vifc->vifc_lcl_addr.s_addr); + dev = ip_dev_find(vifc->vifc_lcl_addr.s_addr); if (!dev) return -EADDRNOTAVAIL; - __dev_put(dev); + dev_put(dev); break; default: return -EINVAL; } - if ((in_dev = __in_dev_get(dev)) == NULL) + if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) return -EADDRNOTAVAIL; in_dev->cnf.mc_forwarding++; dev_set_allmulti(dev, +1); @@ -454,7 +462,7 @@ static int vif_add(struct vifctl *vifc, int mrtsock) return 0; } -static struct mfc_cache *ipmr_cache_find(__u32 origin, __u32 mcastgrp) +static struct mfc_cache *ipmr_cache_find(__be32 origin, __be32 mcastgrp) { int line=MFC_HASH(mcastgrp,origin); struct mfc_cache *c; @@ -497,6 +505,7 @@ static struct mfc_cache *ipmr_cache_alloc_unres(void) static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c) { struct sk_buff *skb; + struct nlmsgerr *e; /* * Play the pending entries through our router @@ -504,7 +513,6 @@ static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c) while((skb=__skb_dequeue(&uc->mfc_un.unres.unresolved))) { if (skb->nh.iph->version == 0) { - int err; struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr)); if (ipmr_fill_mroute(skb, c, NLMSG_DATA(nlh)) > 0) { @@ -513,9 +521,12 @@ static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c) nlh->nlmsg_type = NLMSG_ERROR; nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr)); skb_trim(skb, nlh->nlmsg_len); - ((struct nlmsgerr*)NLMSG_DATA(nlh))->error = -EMSGSIZE; + e = NLMSG_DATA(nlh); + e->error = -EMSGSIZE; + memset(&e->msg, 0, sizeof(e->msg)); } - err = netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT); + + rtnl_unicast(skb, NETLINK_CB(skb).pid); } else ip_mr_forward(skb, c, 0); } @@ -719,7 +730,7 @@ static int ipmr_mfc_add(struct mfcctl *mfc, int mrtsock) if (c != NULL) { write_lock_bh(&mrt_lock); c->mfc_parent = mfc->mfcc_parent; - ipmr_update_threshoulds(c, mfc->mfcc_ttls); + ipmr_update_thresholds(c, mfc->mfcc_ttls); if (!mrtsock) c->mfc_flags |= MFC_STATIC; write_unlock_bh(&mrt_lock); @@ -736,7 +747,7 @@ static int ipmr_mfc_add(struct mfcctl *mfc, int mrtsock) c->mfc_origin=mfc->mfcc_origin.s_addr; c->mfc_mcastgrp=mfc->mfcc_mcastgrp.s_addr; c->mfc_parent=mfc->mfcc_parent; - ipmr_update_threshoulds(c, mfc->mfcc_ttls); + ipmr_update_thresholds(c, mfc->mfcc_ttls); if (!mrtsock) c->mfc_flags |= MFC_STATIC; @@ -844,7 +855,7 @@ static void mrtsock_destruct(struct sock *sk) * MOSPF/PIM router set up we can clean this up. */ -int ip_mroute_setsockopt(struct sock *sk,int optname,char *optval,int optlen) +int ip_mroute_setsockopt(struct sock *sk,int optname,char __user *optval,int optlen) { int ret; struct vifctl vif; @@ -925,7 +936,7 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char *optval,int optlen) case MRT_ASSERT: { int v; - if(get_user(v,(int *)optval)) + if(get_user(v,(int __user *)optval)) return -EFAULT; mroute_do_assert=(v)?1:0; return 0; @@ -934,7 +945,7 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char *optval,int optlen) case MRT_PIM: { int v, ret; - if(get_user(v,(int *)optval)) + if(get_user(v,(int __user *)optval)) return -EFAULT; v = (v)?1:0; rtnl_lock(); @@ -970,7 +981,7 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char *optval,int optlen) * Getsock opt support for the multicast routing system. */ -int ip_mroute_getsockopt(struct sock *sk,int optname,char *optval,int *optlen) +int ip_mroute_getsockopt(struct sock *sk,int optname,char __user *optval,int __user *optlen) { int olr; int val; @@ -1008,7 +1019,7 @@ int ip_mroute_getsockopt(struct sock *sk,int optname,char *optval,int *optlen) * The IP multicast ioctl support routines. */ -int ipmr_ioctl(struct sock *sk, int cmd, unsigned long arg) +int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg) { struct sioc_sg_req sr; struct sioc_vif_req vr; @@ -1018,7 +1029,7 @@ int ipmr_ioctl(struct sock *sk, int cmd, unsigned long arg) switch(cmd) { case SIOCGETVIFCNT: - if (copy_from_user(&vr,(void *)arg,sizeof(vr))) + if (copy_from_user(&vr,arg,sizeof(vr))) return -EFAULT; if(vr.vifi>=maxvif) return -EINVAL; @@ -1031,14 +1042,14 @@ int ipmr_ioctl(struct sock *sk, int cmd, unsigned long arg) vr.obytes=vif->bytes_out; read_unlock(&mrt_lock); - if (copy_to_user((void *)arg,&vr,sizeof(vr))) + if (copy_to_user(arg,&vr,sizeof(vr))) return -EFAULT; return 0; } read_unlock(&mrt_lock); return -EADDRNOTAVAIL; case SIOCGETSGCNT: - if (copy_from_user(&sr,(void *)arg,sizeof(sr))) + if (copy_from_user(&sr,arg,sizeof(sr))) return -EFAULT; read_lock(&mrt_lock); @@ -1049,7 +1060,7 @@ int ipmr_ioctl(struct sock *sk, int cmd, unsigned long arg) sr.wrong_if = c->mfc_un.res.wrong_if; read_unlock(&mrt_lock); - if (copy_to_user((void *)arg,&sr,sizeof(sr))) + if (copy_to_user(arg,&sr,sizeof(sr))) return -EFAULT; return 0; } @@ -1086,7 +1097,7 @@ static struct notifier_block ip_mr_notifier={ * important for multicast video. */ -static void ip_encap(struct sk_buff *skb, u32 saddr, u32 daddr) +static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr) { struct iphdr *iph = (struct iphdr *)skb_push(skb,sizeof(struct iphdr)); @@ -1105,17 +1116,14 @@ static void ip_encap(struct sk_buff *skb, u32 saddr, u32 daddr) skb->h.ipiph = skb->nh.iph; skb->nh.iph = iph; memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#endif + nf_reset(skb); } static inline int ipmr_forward_finish(struct sk_buff *skb) { struct ip_options * opt = &(IPCB(skb)->opt); - IP_INC_STATS_BH(IpForwDatagrams); + IP_INC_STATS_BH(IPSTATS_MIB_OUTFORWDATAGRAMS); if (unlikely(opt->optlen)) ip_forward_options(skb); @@ -1142,8 +1150,8 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi) if (vif->flags & VIFF_REGISTER) { vif->pkt_out++; vif->bytes_out+=skb->len; - ((struct net_device_stats*)vif->dev->priv)->tx_bytes += skb->len; - ((struct net_device_stats*)vif->dev->priv)->tx_packets++; + ((struct net_device_stats*)netdev_priv(vif->dev))->tx_bytes += skb->len; + ((struct net_device_stats*)netdev_priv(vif->dev))->tx_packets++; ipmr_cache_report(skb, vifi, IGMPMSG_WHOLEPKT); kfree_skb(skb); return; @@ -1172,13 +1180,13 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi) dev = rt->u.dst.dev; - if (skb->len+encap > dst_pmtu(&rt->u.dst) && (ntohs(iph->frag_off) & IP_DF)) { + if (skb->len+encap > dst_mtu(&rt->u.dst) && (ntohs(iph->frag_off) & IP_DF)) { /* Do not fragment multicasts. Alas, IPv4 does not allow to send ICMP, so that packets will disappear to blackhole. */ - IP_INC_STATS_BH(IpFragFails); + IP_INC_STATS_BH(IPSTATS_MIB_FRAGFAILS); ip_rt_put(rt); goto out_free; } @@ -1203,8 +1211,8 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi) if (vif->flags & VIFF_TUNNEL) { ip_encap(skb, vif->local, vif->remote); /* FIXME: extra output firewall step used to be here. --RR */ - ((struct ip_tunnel *)vif->dev->priv)->stat.tx_packets++; - ((struct ip_tunnel *)vif->dev->priv)->stat.tx_bytes+=skb->len; + ((struct ip_tunnel *)netdev_priv(vif->dev))->stat.tx_packets++; + ((struct ip_tunnel *)netdev_priv(vif->dev))->stat.tx_bytes+=skb->len; } IPCB(skb)->flags |= IPSKB_FORWARDED; @@ -1351,6 +1359,7 @@ int ip_mr_input(struct sk_buff *skb) */ read_lock(&mrt_lock); if (mroute_socket) { + nf_reset(skb); raw_rcv(mroute_socket, skb); read_unlock(&mrt_lock); return 0; @@ -1453,18 +1462,14 @@ int pim_rcv_v1(struct sk_buff * skb) skb_pull(skb, (u8*)encap - skb->data); skb->nh.iph = (struct iphdr *)skb->data; skb->dev = reg_dev; - memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); skb->protocol = htons(ETH_P_IP); skb->ip_summed = 0; skb->pkt_type = PACKET_HOST; dst_release(skb->dst); skb->dst = NULL; - ((struct net_device_stats*)reg_dev->priv)->rx_bytes += skb->len; - ((struct net_device_stats*)reg_dev->priv)->rx_packets++; -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#endif + ((struct net_device_stats*)netdev_priv(reg_dev))->rx_bytes += skb->len; + ((struct net_device_stats*)netdev_priv(reg_dev))->rx_packets++; + nf_reset(skb); netif_rx(skb); dev_put(reg_dev); return 0; @@ -1488,7 +1493,7 @@ static int pim_rcv(struct sk_buff * skb) if (pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) || (pim->flags&PIM_NULL_REGISTER) || (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 && - (u16)csum_fold(skb_checksum(skb, 0, skb->len, 0)))) + csum_fold(skb_checksum(skb, 0, skb->len, 0)))) goto drop; /* check if the inner packet is destined to mcast group */ @@ -1512,18 +1517,14 @@ static int pim_rcv(struct sk_buff * skb) skb_pull(skb, (u8*)encap - skb->data); skb->nh.iph = (struct iphdr *)skb->data; skb->dev = reg_dev; - memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); skb->protocol = htons(ETH_P_IP); skb->ip_summed = 0; skb->pkt_type = PACKET_HOST; dst_release(skb->dst); - ((struct net_device_stats*)reg_dev->priv)->rx_bytes += skb->len; - ((struct net_device_stats*)reg_dev->priv)->rx_packets++; + ((struct net_device_stats*)netdev_priv(reg_dev))->rx_bytes += skb->len; + ((struct net_device_stats*)netdev_priv(reg_dev))->rx_packets++; skb->dst = NULL; -#ifdef CONFIG_NETFILTER - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#endif + nf_reset(skb); netif_rx(skb); dev_put(reg_dev); return 0; @@ -1578,6 +1579,7 @@ int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait) cache = ipmr_cache_find(rt->rt_src, rt->rt_dst); if (cache==NULL) { + struct sk_buff *skb2; struct net_device *dev; int vif; @@ -1591,12 +1593,18 @@ int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait) read_unlock(&mrt_lock); return -ENODEV; } - skb->nh.raw = skb_push(skb, sizeof(struct iphdr)); - skb->nh.iph->ihl = sizeof(struct iphdr)>>2; - skb->nh.iph->saddr = rt->rt_src; - skb->nh.iph->daddr = rt->rt_dst; - skb->nh.iph->version = 0; - err = ipmr_cache_unresolved(vif, skb); + skb2 = skb_clone(skb, GFP_ATOMIC); + if (!skb2) { + read_unlock(&mrt_lock); + return -ENOMEM; + } + + skb2->nh.raw = skb_push(skb2, sizeof(struct iphdr)); + skb2->nh.iph->ihl = sizeof(struct iphdr)>>2; + skb2->nh.iph->saddr = rt->rt_src; + skb2->nh.iph->daddr = rt->rt_dst; + skb2->nh.iph->version = 0; + err = ipmr_cache_unresolved(vif, skb2); read_unlock(&mrt_lock); return err; } @@ -1711,7 +1719,7 @@ static struct file_operations ipmr_vif_fops = { .open = ipmr_vif_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = seq_release_private, }; struct ipmr_mfc_iter { @@ -1746,6 +1754,9 @@ static struct mfc_cache *ipmr_mfc_seq_idx(struct ipmr_mfc_iter *it, loff_t pos) static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos) { + struct ipmr_mfc_iter *it = seq->private; + it->cache = NULL; + it->ct = 0; return *pos ? ipmr_mfc_seq_idx(seq->private, *pos - 1) : SEQ_START_TOKEN; } @@ -1855,7 +1866,6 @@ static int ipmr_mfc_open(struct inode *inode, struct file *file) if (rc) goto out_kfree; - memset(s, 0, sizeof(*s)); seq = file->private_data; seq->private = s; out: @@ -1871,12 +1881,12 @@ static struct file_operations ipmr_mfc_fops = { .open = ipmr_mfc_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = seq_release_private, }; #endif #ifdef CONFIG_IP_PIMSM_V2 -static struct inet_protocol pim_protocol = { +static struct net_protocol pim_protocol = { .handler = pim_rcv, }; #endif @@ -1890,11 +1900,8 @@ void __init ip_mr_init(void) { mrt_cachep = kmem_cache_create("ip_mrt_cache", sizeof(struct mfc_cache), - 0, SLAB_HWCACHE_ALIGN, + 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); - if (!mrt_cachep) - panic("cannot allocate ip_mrt_cache"); - init_timer(&ipmr_expire_timer); ipmr_expire_timer.function=ipmr_expire_process; register_netdevice_notifier(&ip_mr_notifier);