Commit 901fb38d authored by David S. Miller's avatar David S. Miller

Merge branch 'ipmr-cleanups'

Nikolay Aleksandrov says:

====================
net: ipmr: cleanups and minor improvements

Since I'll have to work with ipmr, I decided to clean it up and do some
minor improvements. Functionally there're almost no changes except the
SLAB_PANIC removal. Most of the patches just re-design some functions to
be clearer and more concise and try to remove the ifdef web that was
inside. There's more information in each commit. This is the first set,
the end goal is to introduce complete netlink support and control over
the mfc and vif devices.
I've tried to test all of the setsockopt/getsockopt options, and also
made builds with various ipmr kconfig options turned on and off.

v2: change patch 7 to keep SLAB_PANIC and just drop the unnecessary null
check
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 930d3142 a0b47736
...@@ -4,15 +4,13 @@ ...@@ -4,15 +4,13 @@
#include <linux/sockios.h> #include <linux/sockios.h>
#include <linux/types.h> #include <linux/types.h>
/* /* Based on the MROUTING 3.5 defines primarily to keep
* Based on the MROUTING 3.5 defines primarily to keep
* source compatibility with BSD. * source compatibility with BSD.
* *
* See the mrouted code for the original history. * See the mrouted code for the original history.
* *
* Protocol Independent Multicast (PIM) data structures included * Protocol Independent Multicast (PIM) data structures included
* Carlos Picoto (cap@di.fc.ul.pt) * Carlos Picoto (cap@di.fc.ul.pt)
*
*/ */
#define MRT_BASE 200 #define MRT_BASE 200
...@@ -39,9 +37,7 @@ typedef unsigned long vifbitmap_t; /* User mode code depends on this lot */ ...@@ -39,9 +37,7 @@ typedef unsigned long vifbitmap_t; /* User mode code depends on this lot */
typedef unsigned short vifi_t; typedef unsigned short vifi_t;
#define ALL_VIFS ((vifi_t)(-1)) #define ALL_VIFS ((vifi_t)(-1))
/* /* Same idea as select */
* Same idea as select
*/
#define VIFM_SET(n,m) ((m)|=(1<<(n))) #define VIFM_SET(n,m) ((m)|=(1<<(n)))
#define VIFM_CLR(n,m) ((m)&=~(1<<(n))) #define VIFM_CLR(n,m) ((m)&=~(1<<(n)))
...@@ -50,11 +46,9 @@ typedef unsigned short vifi_t; ...@@ -50,11 +46,9 @@ typedef unsigned short vifi_t;
#define VIFM_COPY(mfrom,mto) ((mto)=(mfrom)) #define VIFM_COPY(mfrom,mto) ((mto)=(mfrom))
#define VIFM_SAME(m1,m2) ((m1)==(m2)) #define VIFM_SAME(m1,m2) ((m1)==(m2))
/* /* Passed by mrouted for an MRT_ADD_VIF - again we use the
* Passed by mrouted for an MRT_ADD_VIF - again we use the
* mrouted 3.6 structures for compatibility * mrouted 3.6 structures for compatibility
*/ */
struct vifctl { struct vifctl {
vifi_t vifc_vifi; /* Index of VIF */ vifi_t vifc_vifi; /* Index of VIF */
unsigned char vifc_flags; /* VIFF_ flags */ unsigned char vifc_flags; /* VIFF_ flags */
...@@ -73,10 +67,7 @@ struct vifctl { ...@@ -73,10 +67,7 @@ struct vifctl {
#define VIFF_USE_IFINDEX 0x8 /* use vifc_lcl_ifindex instead of #define VIFF_USE_IFINDEX 0x8 /* use vifc_lcl_ifindex instead of
vifc_lcl_addr to find an interface */ vifc_lcl_addr to find an interface */
/* /* Cache manipulation structures for mrouted and PIMd */
* Cache manipulation structures for mrouted and PIMd
*/
struct mfcctl { struct mfcctl {
struct in_addr mfcc_origin; /* Origin of mcast */ struct in_addr mfcc_origin; /* Origin of mcast */
struct in_addr mfcc_mcastgrp; /* Group in question */ struct in_addr mfcc_mcastgrp; /* Group in question */
...@@ -88,10 +79,7 @@ struct mfcctl { ...@@ -88,10 +79,7 @@ struct mfcctl {
int mfcc_expire; int mfcc_expire;
}; };
/* /* Group count retrieval for mrouted */
* Group count retrieval for mrouted
*/
struct sioc_sg_req { struct sioc_sg_req {
struct in_addr src; struct in_addr src;
struct in_addr grp; struct in_addr grp;
...@@ -100,10 +88,7 @@ struct sioc_sg_req { ...@@ -100,10 +88,7 @@ struct sioc_sg_req {
unsigned long wrong_if; unsigned long wrong_if;
}; };
/* /* To get vif packet counts */
* To get vif packet counts
*/
struct sioc_vif_req { struct sioc_vif_req {
vifi_t vifi; /* Which iface */ vifi_t vifi; /* Which iface */
unsigned long icount; /* In packets */ unsigned long icount; /* In packets */
...@@ -112,11 +97,9 @@ struct sioc_vif_req { ...@@ -112,11 +97,9 @@ struct sioc_vif_req {
unsigned long obytes; /* Out bytes */ unsigned long obytes; /* Out bytes */
}; };
/* /* This is the format the mroute daemon expects to see IGMP control
* This is the format the mroute daemon expects to see IGMP control
* data. Magically happens to be like an IP packet as per the original * data. Magically happens to be like an IP packet as per the original
*/ */
struct igmpmsg { struct igmpmsg {
__u32 unused1,unused2; __u32 unused1,unused2;
unsigned char im_msgtype; /* What is this */ unsigned char im_msgtype; /* What is this */
...@@ -126,21 +109,13 @@ struct igmpmsg { ...@@ -126,21 +109,13 @@ struct igmpmsg {
struct in_addr im_src,im_dst; struct in_addr im_src,im_dst;
}; };
/* /* That's all usermode folks */
* That's all usermode folks
*/
#define MFC_ASSERT_THRESH (3*HZ) /* Maximal freq. of asserts */ #define MFC_ASSERT_THRESH (3*HZ) /* Maximal freq. of asserts */
/* /* Pseudo messages used by mrouted */
* Pseudo messages used by mrouted
*/
#define IGMPMSG_NOCACHE 1 /* Kern cache fill request to mrouted */ #define IGMPMSG_NOCACHE 1 /* Kern cache fill request to mrouted */
#define IGMPMSG_WRONGVIF 2 /* For PIM assert processing (unused) */ #define IGMPMSG_WRONGVIF 2 /* For PIM assert processing (unused) */
#define IGMPMSG_WHOLEPKT 3 /* For PIM Register processing */ #define IGMPMSG_WHOLEPKT 3 /* For PIM Register processing */
#endif /* _UAPI__LINUX_MROUTE_H */ #endif /* _UAPI__LINUX_MROUTE_H */
...@@ -67,10 +67,6 @@ ...@@ -67,10 +67,6 @@
#include <net/fib_rules.h> #include <net/fib_rules.h>
#include <linux/netconf.h> #include <linux/netconf.h>
#if defined(CONFIG_IP_PIMSM_V1) || defined(CONFIG_IP_PIMSM_V2)
#define CONFIG_IP_PIMSM 1
#endif
struct mr_table { struct mr_table {
struct list_head list; struct list_head list;
possible_net_t net; possible_net_t net;
...@@ -84,9 +80,7 @@ struct mr_table { ...@@ -84,9 +80,7 @@ struct mr_table {
atomic_t cache_resolve_queue_len; atomic_t cache_resolve_queue_len;
bool mroute_do_assert; bool mroute_do_assert;
bool mroute_do_pim; bool mroute_do_pim;
#if defined(CONFIG_IP_PIMSM_V1) || defined(CONFIG_IP_PIMSM_V2)
int mroute_reg_vif_num; int mroute_reg_vif_num;
#endif
}; };
struct ipmr_rule { struct ipmr_rule {
...@@ -97,15 +91,18 @@ struct ipmr_result { ...@@ -97,15 +91,18 @@ struct ipmr_result {
struct mr_table *mrt; struct mr_table *mrt;
}; };
static inline bool pimsm_enabled(void)
{
return IS_BUILTIN(CONFIG_IP_PIMSM_V1) || IS_BUILTIN(CONFIG_IP_PIMSM_V2);
}
/* Big lock, protecting vif table, mrt cache and mroute socket state. /* Big lock, protecting vif table, mrt cache and mroute socket state.
* Note that the changes are semaphored via rtnl_lock. * Note that the changes are semaphored via rtnl_lock.
*/ */
static DEFINE_RWLOCK(mrt_lock); static DEFINE_RWLOCK(mrt_lock);
/* /* Multicast router control variables */
* Multicast router control variables
*/
#define VIF_EXISTS(_mrt, _idx) ((_mrt)->vif_table[_idx].dev != NULL) #define VIF_EXISTS(_mrt, _idx) ((_mrt)->vif_table[_idx].dev != NULL)
...@@ -252,8 +249,8 @@ static int __net_init ipmr_rules_init(struct net *net) ...@@ -252,8 +249,8 @@ static int __net_init ipmr_rules_init(struct net *net)
INIT_LIST_HEAD(&net->ipv4.mr_tables); INIT_LIST_HEAD(&net->ipv4.mr_tables);
mrt = ipmr_new_table(net, RT_TABLE_DEFAULT); mrt = ipmr_new_table(net, RT_TABLE_DEFAULT);
if (!mrt) { if (IS_ERR(mrt)) {
err = -ENOMEM; err = PTR_ERR(mrt);
goto err1; goto err1;
} }
...@@ -301,8 +298,13 @@ static int ipmr_fib_lookup(struct net *net, struct flowi4 *flp4, ...@@ -301,8 +298,13 @@ static int ipmr_fib_lookup(struct net *net, struct flowi4 *flp4,
static int __net_init ipmr_rules_init(struct net *net) static int __net_init ipmr_rules_init(struct net *net)
{ {
net->ipv4.mrt = ipmr_new_table(net, RT_TABLE_DEFAULT); struct mr_table *mrt;
return net->ipv4.mrt ? 0 : -ENOMEM;
mrt = ipmr_new_table(net, RT_TABLE_DEFAULT);
if (IS_ERR(mrt))
return PTR_ERR(mrt);
net->ipv4.mrt = mrt;
return 0;
} }
static void __net_exit ipmr_rules_exit(struct net *net) static void __net_exit ipmr_rules_exit(struct net *net)
...@@ -319,13 +321,17 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id) ...@@ -319,13 +321,17 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id)
struct mr_table *mrt; struct mr_table *mrt;
unsigned int i; unsigned int i;
/* "pimreg%u" should not exceed 16 bytes (IFNAMSIZ) */
if (id != RT_TABLE_DEFAULT && id >= 1000000000)
return ERR_PTR(-EINVAL);
mrt = ipmr_get_table(net, id); mrt = ipmr_get_table(net, id);
if (mrt) if (mrt)
return mrt; return mrt;
mrt = kzalloc(sizeof(*mrt), GFP_KERNEL); mrt = kzalloc(sizeof(*mrt), GFP_KERNEL);
if (!mrt) if (!mrt)
return NULL; return ERR_PTR(-ENOMEM);
write_pnet(&mrt->net, net); write_pnet(&mrt->net, net);
mrt->id = id; mrt->id = id;
...@@ -338,9 +344,7 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id) ...@@ -338,9 +344,7 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id)
setup_timer(&mrt->ipmr_expire_timer, ipmr_expire_process, setup_timer(&mrt->ipmr_expire_timer, ipmr_expire_process,
(unsigned long)mrt); (unsigned long)mrt);
#ifdef CONFIG_IP_PIMSM
mrt->mroute_reg_vif_num = -1; mrt->mroute_reg_vif_num = -1;
#endif
#ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES #ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES
list_add_tail_rcu(&mrt->list, &net->ipv4.mr_tables); list_add_tail_rcu(&mrt->list, &net->ipv4.mr_tables);
#endif #endif
...@@ -387,8 +391,24 @@ static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v) ...@@ -387,8 +391,24 @@ static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v)
} }
} }
static /* Initialize ipmr pimreg/tunnel in_device */
struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v) static bool ipmr_init_vif_indev(const struct net_device *dev)
{
struct in_device *in_dev;
ASSERT_RTNL();
in_dev = __in_dev_get_rtnl(dev);
if (!in_dev)
return false;
ipv4_devconf_setall(in_dev);
neigh_parms_data_state_setall(in_dev->arp_parms);
IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0;
return true;
}
static struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v)
{ {
struct net_device *dev; struct net_device *dev;
...@@ -399,7 +419,6 @@ struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v) ...@@ -399,7 +419,6 @@ struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v)
int err; int err;
struct ifreq ifr; struct ifreq ifr;
struct ip_tunnel_parm p; struct ip_tunnel_parm p;
struct in_device *in_dev;
memset(&p, 0, sizeof(p)); memset(&p, 0, sizeof(p));
p.iph.daddr = v->vifc_rmt_addr.s_addr; p.iph.daddr = v->vifc_rmt_addr.s_addr;
...@@ -424,15 +443,8 @@ struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v) ...@@ -424,15 +443,8 @@ struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v)
if (err == 0 && if (err == 0 &&
(dev = __dev_get_by_name(net, p.name)) != NULL) { (dev = __dev_get_by_name(net, p.name)) != NULL) {
dev->flags |= IFF_MULTICAST; dev->flags |= IFF_MULTICAST;
if (!ipmr_init_vif_indev(dev))
in_dev = __in_dev_get_rtnl(dev);
if (!in_dev)
goto failure; goto failure;
ipv4_devconf_setall(in_dev);
neigh_parms_data_state_setall(in_dev->arp_parms);
IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0;
if (dev_open(dev)) if (dev_open(dev))
goto failure; goto failure;
dev_hold(dev); dev_hold(dev);
...@@ -449,8 +461,7 @@ struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v) ...@@ -449,8 +461,7 @@ struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v)
return NULL; return NULL;
} }
#ifdef CONFIG_IP_PIMSM #if defined(CONFIG_IP_PIMSM_V1) || defined(CONFIG_IP_PIMSM_V2)
static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, struct net_device *dev) static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
struct net *net = dev_net(dev); struct net *net = dev_net(dev);
...@@ -500,7 +511,6 @@ static void reg_vif_setup(struct net_device *dev) ...@@ -500,7 +511,6 @@ static void reg_vif_setup(struct net_device *dev)
static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt) static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt)
{ {
struct net_device *dev; struct net_device *dev;
struct in_device *in_dev;
char name[IFNAMSIZ]; char name[IFNAMSIZ];
if (mrt->id == RT_TABLE_DEFAULT) if (mrt->id == RT_TABLE_DEFAULT)
...@@ -520,18 +530,8 @@ static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt) ...@@ -520,18 +530,8 @@ static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt)
return NULL; return NULL;
} }
rcu_read_lock(); if (!ipmr_init_vif_indev(dev))
in_dev = __in_dev_get_rcu(dev);
if (!in_dev) {
rcu_read_unlock();
goto failure; goto failure;
}
ipv4_devconf_setall(in_dev);
neigh_parms_data_state_setall(in_dev->arp_parms);
IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0;
rcu_read_unlock();
if (dev_open(dev)) if (dev_open(dev))
goto failure; goto failure;
...@@ -547,13 +547,56 @@ static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt) ...@@ -547,13 +547,56 @@ static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt)
unregister_netdevice(dev); unregister_netdevice(dev);
return NULL; return NULL;
} }
/* called with rcu_read_lock() */
static int __pim_rcv(struct mr_table *mrt, struct sk_buff *skb,
unsigned int pimlen)
{
struct net_device *reg_dev = NULL;
struct iphdr *encap;
encap = (struct iphdr *)(skb_transport_header(skb) + pimlen);
/* Check that:
* a. packet is really sent to a multicast group
* b. packet is not a NULL-REGISTER
* c. packet is not truncated
*/
if (!ipv4_is_multicast(encap->daddr) ||
encap->tot_len == 0 ||
ntohs(encap->tot_len) + pimlen > skb->len)
return 1;
read_lock(&mrt_lock);
if (mrt->mroute_reg_vif_num >= 0)
reg_dev = mrt->vif_table[mrt->mroute_reg_vif_num].dev;
read_unlock(&mrt_lock);
if (!reg_dev)
return 1;
skb->mac_header = skb->network_header;
skb_pull(skb, (u8 *)encap - skb->data);
skb_reset_network_header(skb);
skb->protocol = htons(ETH_P_IP);
skb->ip_summed = CHECKSUM_NONE;
skb_tunnel_rx(skb, reg_dev, dev_net(reg_dev));
netif_rx(skb);
return NET_RX_SUCCESS;
}
#else
static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt)
{
return NULL;
}
#endif #endif
/** /**
* vif_delete - Delete a VIF entry * vif_delete - Delete a VIF entry
* @notify: Set to 1, if the caller is a notifier_call * @notify: Set to 1, if the caller is a notifier_call
*/ */
static int vif_delete(struct mr_table *mrt, int vifi, int notify, static int vif_delete(struct mr_table *mrt, int vifi, int notify,
struct list_head *head) struct list_head *head)
{ {
...@@ -575,10 +618,8 @@ static int vif_delete(struct mr_table *mrt, int vifi, int notify, ...@@ -575,10 +618,8 @@ static int vif_delete(struct mr_table *mrt, int vifi, int notify,
return -EADDRNOTAVAIL; return -EADDRNOTAVAIL;
} }
#ifdef CONFIG_IP_PIMSM
if (vifi == mrt->mroute_reg_vif_num) if (vifi == mrt->mroute_reg_vif_num)
mrt->mroute_reg_vif_num = -1; mrt->mroute_reg_vif_num = -1;
#endif
if (vifi + 1 == mrt->maxvif) { if (vifi + 1 == mrt->maxvif) {
int tmp; int tmp;
...@@ -625,7 +666,6 @@ static inline void ipmr_cache_free(struct mfc_cache *c) ...@@ -625,7 +666,6 @@ static inline void ipmr_cache_free(struct mfc_cache *c)
/* Destroy an unresolved cache entry, killing queued skbs /* Destroy an unresolved cache entry, killing queued skbs
* and reporting error to netlink readers. * and reporting error to netlink readers.
*/ */
static void ipmr_destroy_unres(struct mr_table *mrt, struct mfc_cache *c) static void ipmr_destroy_unres(struct mr_table *mrt, struct mfc_cache *c)
{ {
struct net *net = read_pnet(&mrt->net); struct net *net = read_pnet(&mrt->net);
...@@ -653,9 +693,7 @@ static void ipmr_destroy_unres(struct mr_table *mrt, struct mfc_cache *c) ...@@ -653,9 +693,7 @@ static void ipmr_destroy_unres(struct mr_table *mrt, struct mfc_cache *c)
ipmr_cache_free(c); ipmr_cache_free(c);
} }
/* Timer process for the unresolved queue. */ /* Timer process for the unresolved queue. */
static void ipmr_expire_process(unsigned long arg) static void ipmr_expire_process(unsigned long arg)
{ {
struct mr_table *mrt = (struct mr_table *)arg; struct mr_table *mrt = (struct mr_table *)arg;
...@@ -695,7 +733,6 @@ static void ipmr_expire_process(unsigned long arg) ...@@ -695,7 +733,6 @@ static void ipmr_expire_process(unsigned long arg)
} }
/* Fill oifs list. It is called under write locked mrt_lock. */ /* Fill oifs list. It is called under write locked mrt_lock. */
static void ipmr_update_thresholds(struct mr_table *mrt, struct mfc_cache *cache, static void ipmr_update_thresholds(struct mr_table *mrt, struct mfc_cache *cache,
unsigned char *ttls) unsigned char *ttls)
{ {
...@@ -731,10 +768,10 @@ static int vif_add(struct net *net, struct mr_table *mrt, ...@@ -731,10 +768,10 @@ static int vif_add(struct net *net, struct mr_table *mrt,
return -EADDRINUSE; return -EADDRINUSE;
switch (vifc->vifc_flags) { switch (vifc->vifc_flags) {
#ifdef CONFIG_IP_PIMSM
case VIFF_REGISTER: case VIFF_REGISTER:
/* if (!pimsm_enabled())
* Special Purpose VIF in PIM return -EINVAL;
/* Special Purpose VIF in PIM
* All the packets will be sent to the daemon * All the packets will be sent to the daemon
*/ */
if (mrt->mroute_reg_vif_num >= 0) if (mrt->mroute_reg_vif_num >= 0)
...@@ -749,7 +786,6 @@ static int vif_add(struct net *net, struct mr_table *mrt, ...@@ -749,7 +786,6 @@ static int vif_add(struct net *net, struct mr_table *mrt,
return err; return err;
} }
break; break;
#endif
case VIFF_TUNNEL: case VIFF_TUNNEL:
dev = ipmr_new_tunnel(net, vifc); dev = ipmr_new_tunnel(net, vifc);
if (!dev) if (!dev)
...@@ -761,7 +797,6 @@ static int vif_add(struct net *net, struct mr_table *mrt, ...@@ -761,7 +797,6 @@ static int vif_add(struct net *net, struct mr_table *mrt,
return err; return err;
} }
break; break;
case VIFF_USE_IFINDEX: case VIFF_USE_IFINDEX:
case 0: case 0:
if (vifc->vifc_flags == VIFF_USE_IFINDEX) { if (vifc->vifc_flags == VIFF_USE_IFINDEX) {
...@@ -815,10 +850,8 @@ static int vif_add(struct net *net, struct mr_table *mrt, ...@@ -815,10 +850,8 @@ static int vif_add(struct net *net, struct mr_table *mrt,
/* And finish update writing critical data */ /* And finish update writing critical data */
write_lock_bh(&mrt_lock); write_lock_bh(&mrt_lock);
v->dev = dev; v->dev = dev;
#ifdef CONFIG_IP_PIMSM
if (v->flags & VIFF_REGISTER) if (v->flags & VIFF_REGISTER)
mrt->mroute_reg_vif_num = vifi; mrt->mroute_reg_vif_num = vifi;
#endif
if (vifi+1 > mrt->maxvif) if (vifi+1 > mrt->maxvif)
mrt->maxvif = vifi+1; mrt->maxvif = vifi+1;
write_unlock_bh(&mrt_lock); write_unlock_bh(&mrt_lock);
...@@ -883,9 +916,7 @@ static struct mfc_cache *ipmr_cache_find_any(struct mr_table *mrt, ...@@ -883,9 +916,7 @@ static struct mfc_cache *ipmr_cache_find_any(struct mr_table *mrt,
return ipmr_cache_find_any_parent(mrt, vifi); return ipmr_cache_find_any_parent(mrt, vifi);
} }
/* /* Allocate a multicast cache entry */
* Allocate a multicast cache entry
*/
static struct mfc_cache *ipmr_cache_alloc(void) static struct mfc_cache *ipmr_cache_alloc(void)
{ {
struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL); struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
...@@ -906,10 +937,7 @@ static struct mfc_cache *ipmr_cache_alloc_unres(void) ...@@ -906,10 +937,7 @@ static struct mfc_cache *ipmr_cache_alloc_unres(void)
return c; return c;
} }
/* /* A cache entry has gone into a resolved state from queued */
* A cache entry has gone into a resolved state from queued
*/
static void ipmr_cache_resolve(struct net *net, struct mr_table *mrt, static void ipmr_cache_resolve(struct net *net, struct mr_table *mrt,
struct mfc_cache *uc, struct mfc_cache *c) struct mfc_cache *uc, struct mfc_cache *c)
{ {
...@@ -917,7 +945,6 @@ static void ipmr_cache_resolve(struct net *net, struct mr_table *mrt, ...@@ -917,7 +945,6 @@ static void ipmr_cache_resolve(struct net *net, struct mr_table *mrt,
struct nlmsgerr *e; struct nlmsgerr *e;
/* Play the pending entries through our router */ /* Play the pending entries through our router */
while ((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) { while ((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) {
if (ip_hdr(skb)->version == 0) { if (ip_hdr(skb)->version == 0) {
struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr)); struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
...@@ -941,34 +968,29 @@ static void ipmr_cache_resolve(struct net *net, struct mr_table *mrt, ...@@ -941,34 +968,29 @@ static void ipmr_cache_resolve(struct net *net, struct mr_table *mrt,
} }
} }
/* /* Bounce a cache query up to mrouted. We could use netlink for this but mrouted
* Bounce a cache query up to mrouted. We could use netlink for this but mrouted
* expects the following bizarre scheme. * expects the following bizarre scheme.
* *
* Called under mrt_lock. * Called under mrt_lock.
*/ */
static int ipmr_cache_report(struct mr_table *mrt, static int ipmr_cache_report(struct mr_table *mrt,
struct sk_buff *pkt, vifi_t vifi, int assert) struct sk_buff *pkt, vifi_t vifi, int assert)
{ {
struct sk_buff *skb;
const int ihl = ip_hdrlen(pkt); const int ihl = ip_hdrlen(pkt);
struct sock *mroute_sk;
struct igmphdr *igmp; struct igmphdr *igmp;
struct igmpmsg *msg; struct igmpmsg *msg;
struct sock *mroute_sk; struct sk_buff *skb;
int ret; int ret;
#ifdef CONFIG_IP_PIMSM
if (assert == IGMPMSG_WHOLEPKT) if (assert == IGMPMSG_WHOLEPKT)
skb = skb_realloc_headroom(pkt, sizeof(struct iphdr)); skb = skb_realloc_headroom(pkt, sizeof(struct iphdr));
else else
#endif
skb = alloc_skb(128, GFP_ATOMIC); skb = alloc_skb(128, GFP_ATOMIC);
if (!skb) if (!skb)
return -ENOBUFS; return -ENOBUFS;
#ifdef CONFIG_IP_PIMSM
if (assert == IGMPMSG_WHOLEPKT) { if (assert == IGMPMSG_WHOLEPKT) {
/* Ugly, but we have no choice with this interface. /* Ugly, but we have no choice with this interface.
* Duplicate old header, fix ihl, length etc. * Duplicate old header, fix ihl, length etc.
...@@ -986,24 +1008,19 @@ static int ipmr_cache_report(struct mr_table *mrt, ...@@ -986,24 +1008,19 @@ static int ipmr_cache_report(struct mr_table *mrt,
ip_hdr(skb)->ihl = sizeof(struct iphdr) >> 2; ip_hdr(skb)->ihl = sizeof(struct iphdr) >> 2;
ip_hdr(skb)->tot_len = htons(ntohs(ip_hdr(pkt)->tot_len) + ip_hdr(skb)->tot_len = htons(ntohs(ip_hdr(pkt)->tot_len) +
sizeof(struct iphdr)); sizeof(struct iphdr));
} else } else {
#endif
{
/* Copy the IP header */ /* Copy the IP header */
skb_set_network_header(skb, skb->len); skb_set_network_header(skb, skb->len);
skb_put(skb, ihl); skb_put(skb, ihl);
skb_copy_to_linear_data(skb, pkt->data, ihl); skb_copy_to_linear_data(skb, pkt->data, ihl);
ip_hdr(skb)->protocol = 0; /* Flag to the kernel this is a route add */ /* Flag to the kernel this is a route add */
ip_hdr(skb)->protocol = 0;
msg = (struct igmpmsg *)skb_network_header(skb); msg = (struct igmpmsg *)skb_network_header(skb);
msg->im_vif = vifi; msg->im_vif = vifi;
skb_dst_set(skb, dst_clone(skb_dst(pkt))); skb_dst_set(skb, dst_clone(skb_dst(pkt)));
/* Add our header */ /* Add our header */
igmp = (struct igmphdr *)skb_put(skb, sizeof(struct igmphdr)); igmp = (struct igmphdr *)skb_put(skb, sizeof(struct igmphdr));
igmp->type = igmp->type = assert;
msg->im_msgtype = assert; msg->im_msgtype = assert;
igmp->code = 0; igmp->code = 0;
ip_hdr(skb)->tot_len = htons(skb->len); /* Fix the length */ ip_hdr(skb)->tot_len = htons(skb->len); /* Fix the length */
...@@ -1019,7 +1036,6 @@ static int ipmr_cache_report(struct mr_table *mrt, ...@@ -1019,7 +1036,6 @@ static int ipmr_cache_report(struct mr_table *mrt,
} }
/* Deliver to mrouted */ /* Deliver to mrouted */
ret = sock_queue_rcv_skb(mroute_sk, skb); ret = sock_queue_rcv_skb(mroute_sk, skb);
rcu_read_unlock(); rcu_read_unlock();
if (ret < 0) { if (ret < 0) {
...@@ -1030,12 +1046,9 @@ static int ipmr_cache_report(struct mr_table *mrt, ...@@ -1030,12 +1046,9 @@ static int ipmr_cache_report(struct mr_table *mrt,
return ret; return ret;
} }
/* /* Queue a packet for resolution. It gets locked cache entry! */
* Queue a packet for resolution. It gets locked cache entry! static int ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi,
*/ struct sk_buff *skb)
static int
ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi, struct sk_buff *skb)
{ {
bool found = false; bool found = false;
int err; int err;
...@@ -1053,7 +1066,6 @@ ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi, struct sk_buff *skb) ...@@ -1053,7 +1066,6 @@ ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi, struct sk_buff *skb)
if (!found) { if (!found) {
/* Create a new entry if allowable */ /* Create a new entry if allowable */
if (atomic_read(&mrt->cache_resolve_queue_len) >= 10 || if (atomic_read(&mrt->cache_resolve_queue_len) >= 10 ||
(c = ipmr_cache_alloc_unres()) == NULL) { (c = ipmr_cache_alloc_unres()) == NULL) {
spin_unlock_bh(&mfc_unres_lock); spin_unlock_bh(&mfc_unres_lock);
...@@ -1063,13 +1075,11 @@ ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi, struct sk_buff *skb) ...@@ -1063,13 +1075,11 @@ ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi, struct sk_buff *skb)
} }
/* Fill in the new cache entry */ /* Fill in the new cache entry */
c->mfc_parent = -1; c->mfc_parent = -1;
c->mfc_origin = iph->saddr; c->mfc_origin = iph->saddr;
c->mfc_mcastgrp = iph->daddr; c->mfc_mcastgrp = iph->daddr;
/* Reflect first query at mrouted. */ /* Reflect first query at mrouted. */
err = ipmr_cache_report(mrt, skb, vifi, IGMPMSG_NOCACHE); err = ipmr_cache_report(mrt, skb, vifi, IGMPMSG_NOCACHE);
if (err < 0) { if (err < 0) {
/* If the report failed throw the cache entry /* If the report failed throw the cache entry
...@@ -1091,7 +1101,6 @@ ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi, struct sk_buff *skb) ...@@ -1091,7 +1101,6 @@ ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi, struct sk_buff *skb)
} }
/* See if we can append the packet */ /* See if we can append the packet */
if (c->mfc_un.unres.unresolved.qlen > 3) { if (c->mfc_un.unres.unresolved.qlen > 3) {
kfree_skb(skb); kfree_skb(skb);
err = -ENOBUFS; err = -ENOBUFS;
...@@ -1104,9 +1113,7 @@ ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi, struct sk_buff *skb) ...@@ -1104,9 +1113,7 @@ ipmr_cache_unresolved(struct mr_table *mrt, vifi_t vifi, struct sk_buff *skb)
return err; return err;
} }
/* /* MFC cache manipulation by user space mroute daemon */
* MFC cache manipulation by user space mroute daemon
*/
static int ipmr_mfc_delete(struct mr_table *mrt, struct mfcctl *mfc, int parent) static int ipmr_mfc_delete(struct mr_table *mrt, struct mfcctl *mfc, int parent)
{ {
...@@ -1177,8 +1184,7 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt, ...@@ -1177,8 +1184,7 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt,
list_add_rcu(&c->list, &mrt->mfc_cache_array[line]); list_add_rcu(&c->list, &mrt->mfc_cache_array[line]);
/* /* Check to see if we resolved a queued list. If so we
* Check to see if we resolved a queued list. If so we
* need to send on the frames and tidy up. * need to send on the frames and tidy up.
*/ */
found = false; found = false;
...@@ -1204,10 +1210,7 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt, ...@@ -1204,10 +1210,7 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt,
return 0; return 0;
} }
/* /* Close the multicast socket, and clear the vif tables etc */
* Close the multicast socket, and clear the vif tables etc
*/
static void mroute_clean_tables(struct mr_table *mrt) static void mroute_clean_tables(struct mr_table *mrt)
{ {
int i; int i;
...@@ -1215,7 +1218,6 @@ static void mroute_clean_tables(struct mr_table *mrt) ...@@ -1215,7 +1218,6 @@ static void mroute_clean_tables(struct mr_table *mrt)
struct mfc_cache *c, *next; struct mfc_cache *c, *next;
/* Shut down all active vif entries */ /* Shut down all active vif entries */
for (i = 0; i < mrt->maxvif; i++) { for (i = 0; i < mrt->maxvif; i++) {
if (!(mrt->vif_table[i].flags & VIFF_STATIC)) if (!(mrt->vif_table[i].flags & VIFF_STATIC))
vif_delete(mrt, i, 0, &list); vif_delete(mrt, i, 0, &list);
...@@ -1223,7 +1225,6 @@ static void mroute_clean_tables(struct mr_table *mrt) ...@@ -1223,7 +1225,6 @@ static void mroute_clean_tables(struct mr_table *mrt)
unregister_netdevice_many(&list); unregister_netdevice_many(&list);
/* Wipe the cache */ /* Wipe the cache */
for (i = 0; i < MFC_LINES; i++) { for (i = 0; i < MFC_LINES; i++) {
list_for_each_entry_safe(c, next, &mrt->mfc_cache_array[i], list) { list_for_each_entry_safe(c, next, &mrt->mfc_cache_array[i], list) {
if (c->mfc_flags & MFC_STATIC) if (c->mfc_flags & MFC_STATIC)
...@@ -1267,45 +1268,51 @@ static void mrtsock_destruct(struct sock *sk) ...@@ -1267,45 +1268,51 @@ static void mrtsock_destruct(struct sock *sk)
rtnl_unlock(); rtnl_unlock();
} }
/* /* Socket options and virtual interface manipulation. The whole
* Socket options and virtual interface manipulation. The whole
* virtual interface system is a complete heap, but unfortunately * virtual interface system is a complete heap, but unfortunately
* that's how BSD mrouted happens to think. Maybe one day with a proper * that's how BSD mrouted happens to think. Maybe one day with a proper
* MOSPF/PIM router set up we can clean this up. * MOSPF/PIM router set up we can clean this up.
*/ */
int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen) int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval,
unsigned int optlen)
{ {
int ret, parent = 0;
struct vifctl vif;
struct mfcctl mfc;
struct net *net = sock_net(sk); struct net *net = sock_net(sk);
int val, ret = 0, parent = 0;
struct mr_table *mrt; struct mr_table *mrt;
struct vifctl vif;
struct mfcctl mfc;
u32 uval;
/* There's one exception to the lock - MRT_DONE which needs to unlock */
rtnl_lock();
if (sk->sk_type != SOCK_RAW || if (sk->sk_type != SOCK_RAW ||
inet_sk(sk)->inet_num != IPPROTO_IGMP) inet_sk(sk)->inet_num != IPPROTO_IGMP) {
return -EOPNOTSUPP; ret = -EOPNOTSUPP;
goto out_unlock;
}
mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT); mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT);
if (!mrt) if (!mrt) {
return -ENOENT; ret = -ENOENT;
goto out_unlock;
}
if (optname != MRT_INIT) { if (optname != MRT_INIT) {
if (sk != rcu_access_pointer(mrt->mroute_sk) && if (sk != rcu_access_pointer(mrt->mroute_sk) &&
!ns_capable(net->user_ns, CAP_NET_ADMIN)) !ns_capable(net->user_ns, CAP_NET_ADMIN)) {
return -EACCES; ret = -EACCES;
goto out_unlock;
}
} }
switch (optname) { switch (optname) {
case MRT_INIT: case MRT_INIT:
if (optlen != sizeof(int)) if (optlen != sizeof(int))
return -EINVAL; ret = -EINVAL;
if (rtnl_dereference(mrt->mroute_sk))
rtnl_lock(); ret = -EADDRINUSE;
if (rtnl_dereference(mrt->mroute_sk)) { if (ret)
rtnl_unlock(); break;
return -EADDRINUSE;
}
ret = ip_ra_control(sk, 1, mrtsock_destruct); ret = ip_ra_control(sk, 1, mrtsock_destruct);
if (ret == 0) { if (ret == 0) {
...@@ -1315,32 +1322,42 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi ...@@ -1315,32 +1322,42 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
NETCONFA_IFINDEX_ALL, NETCONFA_IFINDEX_ALL,
net->ipv4.devconf_all); net->ipv4.devconf_all);
} }
rtnl_unlock(); break;
return ret;
case MRT_DONE: case MRT_DONE:
if (sk != rcu_access_pointer(mrt->mroute_sk)) if (sk != rcu_access_pointer(mrt->mroute_sk)) {
return -EACCES; ret = -EACCES;
return ip_ra_control(sk, 0, NULL); } else {
/* We need to unlock here because mrtsock_destruct takes
* care of rtnl itself and we can't change that due to
* the IP_ROUTER_ALERT setsockopt which runs without it.
*/
rtnl_unlock();
ret = ip_ra_control(sk, 0, NULL);
goto out;
}
break;
case MRT_ADD_VIF: case MRT_ADD_VIF:
case MRT_DEL_VIF: case MRT_DEL_VIF:
if (optlen != sizeof(vif)) if (optlen != sizeof(vif)) {
return -EINVAL; ret = -EINVAL;
if (copy_from_user(&vif, optval, sizeof(vif))) break;
return -EFAULT; }
if (vif.vifc_vifi >= MAXVIFS) if (copy_from_user(&vif, optval, sizeof(vif))) {
return -ENFILE; ret = -EFAULT;
rtnl_lock(); break;
}
if (vif.vifc_vifi >= MAXVIFS) {
ret = -ENFILE;
break;
}
if (optname == MRT_ADD_VIF) { if (optname == MRT_ADD_VIF) {
ret = vif_add(net, mrt, &vif, ret = vif_add(net, mrt, &vif,
sk == rtnl_dereference(mrt->mroute_sk)); sk == rtnl_dereference(mrt->mroute_sk));
} else { } else {
ret = vif_delete(mrt, vif.vifc_vifi, 0, NULL); ret = vif_delete(mrt, vif.vifc_vifi, 0, NULL);
} }
rtnl_unlock(); break;
return ret; /* Manipulate the forwarding caches. These live
/*
* Manipulate the forwarding caches. These live
* in a sort of kernel/user symbiosis. * in a sort of kernel/user symbiosis.
*/ */
case MRT_ADD_MFC: case MRT_ADD_MFC:
...@@ -1348,96 +1365,90 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi ...@@ -1348,96 +1365,90 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
parent = -1; parent = -1;
case MRT_ADD_MFC_PROXY: case MRT_ADD_MFC_PROXY:
case MRT_DEL_MFC_PROXY: case MRT_DEL_MFC_PROXY:
if (optlen != sizeof(mfc)) if (optlen != sizeof(mfc)) {
return -EINVAL; ret = -EINVAL;
if (copy_from_user(&mfc, optval, sizeof(mfc))) break;
return -EFAULT; }
if (copy_from_user(&mfc, optval, sizeof(mfc))) {
ret = -EFAULT;
break;
}
if (parent == 0) if (parent == 0)
parent = mfc.mfcc_parent; parent = mfc.mfcc_parent;
rtnl_lock();
if (optname == MRT_DEL_MFC || optname == MRT_DEL_MFC_PROXY) if (optname == MRT_DEL_MFC || optname == MRT_DEL_MFC_PROXY)
ret = ipmr_mfc_delete(mrt, &mfc, parent); ret = ipmr_mfc_delete(mrt, &mfc, parent);
else else
ret = ipmr_mfc_add(net, mrt, &mfc, ret = ipmr_mfc_add(net, mrt, &mfc,
sk == rtnl_dereference(mrt->mroute_sk), sk == rtnl_dereference(mrt->mroute_sk),
parent); parent);
rtnl_unlock(); break;
return ret; /* Control PIM assert. */
/*
* Control PIM assert.
*/
case MRT_ASSERT: case MRT_ASSERT:
{ if (optlen != sizeof(val)) {
int v; ret = -EINVAL;
if (optlen != sizeof(v)) break;
return -EINVAL; }
if (get_user(v, (int __user *)optval)) if (get_user(val, (int __user *)optval)) {
return -EFAULT; ret = -EFAULT;
mrt->mroute_do_assert = v; break;
return 0;
} }
#ifdef CONFIG_IP_PIMSM mrt->mroute_do_assert = val;
break;
case MRT_PIM: case MRT_PIM:
{ if (!pimsm_enabled()) {
int v; ret = -ENOPROTOOPT;
break;
if (optlen != sizeof(v))
return -EINVAL;
if (get_user(v, (int __user *)optval))
return -EFAULT;
v = !!v;
rtnl_lock();
ret = 0;
if (v != mrt->mroute_do_pim) {
mrt->mroute_do_pim = v;
mrt->mroute_do_assert = v;
} }
rtnl_unlock(); if (optlen != sizeof(val)) {
return ret; ret = -EINVAL;
break;
}
if (get_user(val, (int __user *)optval)) {
ret = -EFAULT;
break;
} }
#endif
#ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES
case MRT_TABLE:
{
u32 v;
if (optlen != sizeof(u32))
return -EINVAL;
if (get_user(v, (u32 __user *)optval))
return -EFAULT;
/* "pimreg%u" should not exceed 16 bytes (IFNAMSIZ) */ val = !!val;
if (v != RT_TABLE_DEFAULT && v >= 1000000000) if (val != mrt->mroute_do_pim) {
return -EINVAL; mrt->mroute_do_pim = val;
mrt->mroute_do_assert = val;
}
break;
case MRT_TABLE:
if (!IS_BUILTIN(CONFIG_IP_MROUTE_MULTIPLE_TABLES)) {
ret = -ENOPROTOOPT;
break;
}
if (optlen != sizeof(uval)) {
ret = -EINVAL;
break;
}
if (get_user(uval, (u32 __user *)optval)) {
ret = -EFAULT;
break;
}
rtnl_lock();
ret = 0;
if (sk == rtnl_dereference(mrt->mroute_sk)) { if (sk == rtnl_dereference(mrt->mroute_sk)) {
ret = -EBUSY; ret = -EBUSY;
} else { } else {
if (!ipmr_new_table(net, v)) mrt = ipmr_new_table(net, uval);
ret = -ENOMEM; if (IS_ERR(mrt))
ret = PTR_ERR(mrt);
else else
raw_sk(sk)->ipmr_table = v; raw_sk(sk)->ipmr_table = uval;
}
rtnl_unlock();
return ret;
} }
#endif break;
/* /* Spurious command, or MRT_VERSION which you cannot set. */
* Spurious command, or MRT_VERSION which you cannot
* set.
*/
default: default:
return -ENOPROTOOPT; ret = -ENOPROTOOPT;
} }
out_unlock:
rtnl_unlock();
out:
return ret;
} }
/* /* Getsock opt support for the multicast routing system. */
* Getsock opt support for the multicast routing system.
*/
int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int __user *optlen) int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int __user *optlen)
{ {
int olr; int olr;
...@@ -1453,39 +1464,35 @@ int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int ...@@ -1453,39 +1464,35 @@ int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int
if (!mrt) if (!mrt)
return -ENOENT; return -ENOENT;
if (optname != MRT_VERSION && switch (optname) {
#ifdef CONFIG_IP_PIMSM case MRT_VERSION:
optname != MRT_PIM && val = 0x0305;
#endif break;
optname != MRT_ASSERT) case MRT_PIM:
if (!pimsm_enabled())
return -ENOPROTOOPT; return -ENOPROTOOPT;
val = mrt->mroute_do_pim;
break;
case MRT_ASSERT:
val = mrt->mroute_do_assert;
break;
default:
return -ENOPROTOOPT;
}
if (get_user(olr, optlen)) if (get_user(olr, optlen))
return -EFAULT; return -EFAULT;
olr = min_t(unsigned int, olr, sizeof(int)); olr = min_t(unsigned int, olr, sizeof(int));
if (olr < 0) if (olr < 0)
return -EINVAL; return -EINVAL;
if (put_user(olr, optlen)) if (put_user(olr, optlen))
return -EFAULT; return -EFAULT;
if (optname == MRT_VERSION)
val = 0x0305;
#ifdef CONFIG_IP_PIMSM
else if (optname == MRT_PIM)
val = mrt->mroute_do_pim;
#endif
else
val = mrt->mroute_do_assert;
if (copy_to_user(optval, &val, olr)) if (copy_to_user(optval, &val, olr))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
/* /* The IP multicast ioctl support routines. */
* The IP multicast ioctl support routines.
*/
int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg) int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
{ {
struct sioc_sg_req sr; struct sioc_sg_req sr;
...@@ -1618,7 +1625,6 @@ int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg) ...@@ -1618,7 +1625,6 @@ int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
} }
#endif #endif
static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr) static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr)
{ {
struct net_device *dev = netdev_notifier_info_to_dev(ptr); struct net_device *dev = netdev_notifier_info_to_dev(ptr);
...@@ -1640,17 +1646,14 @@ static int ipmr_device_event(struct notifier_block *this, unsigned long event, v ...@@ -1640,17 +1646,14 @@ static int ipmr_device_event(struct notifier_block *this, unsigned long event, v
return NOTIFY_DONE; return NOTIFY_DONE;
} }
static struct notifier_block ip_mr_notifier = { static struct notifier_block ip_mr_notifier = {
.notifier_call = ipmr_device_event, .notifier_call = ipmr_device_event,
}; };
/* /* Encapsulate a packet by attaching a valid IPIP header to it.
* Encapsulate a packet by attaching a valid IPIP header to it.
* This avoids tunnel drivers and other mess and gives us the speed so * This avoids tunnel drivers and other mess and gives us the speed so
* important for multicast video. * important for multicast video.
*/ */
static void ip_encap(struct net *net, struct sk_buff *skb, static void ip_encap(struct net *net, struct sk_buff *skb,
__be32 saddr, __be32 daddr) __be32 saddr, __be32 daddr)
{ {
...@@ -1692,9 +1695,7 @@ static inline int ipmr_forward_finish(struct net *net, struct sock *sk, ...@@ -1692,9 +1695,7 @@ static inline int ipmr_forward_finish(struct net *net, struct sock *sk,
return dst_output(net, sk, skb); return dst_output(net, sk, skb);
} }
/* /* Processing handlers for ipmr_forward */
* Processing handlers for ipmr_forward
*/
static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt, static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
struct sk_buff *skb, struct mfc_cache *c, int vifi) struct sk_buff *skb, struct mfc_cache *c, int vifi)
...@@ -1709,7 +1710,6 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt, ...@@ -1709,7 +1710,6 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
if (!vif->dev) if (!vif->dev)
goto out_free; goto out_free;
#ifdef CONFIG_IP_PIMSM
if (vif->flags & VIFF_REGISTER) { if (vif->flags & VIFF_REGISTER) {
vif->pkt_out++; vif->pkt_out++;
vif->bytes_out += skb->len; vif->bytes_out += skb->len;
...@@ -1718,7 +1718,6 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt, ...@@ -1718,7 +1718,6 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
ipmr_cache_report(mrt, skb, vifi, IGMPMSG_WHOLEPKT); ipmr_cache_report(mrt, skb, vifi, IGMPMSG_WHOLEPKT);
goto out_free; goto out_free;
} }
#endif
if (vif->flags & VIFF_TUNNEL) { if (vif->flags & VIFF_TUNNEL) {
rt = ip_route_output_ports(net, &fl4, NULL, rt = ip_route_output_ports(net, &fl4, NULL,
...@@ -1745,7 +1744,6 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt, ...@@ -1745,7 +1744,6 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
* allow to send ICMP, so that packets will disappear * allow to send ICMP, so that packets will disappear
* to blackhole. * to blackhole.
*/ */
IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS); IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS);
ip_rt_put(rt); ip_rt_put(rt);
goto out_free; goto out_free;
...@@ -1777,8 +1775,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt, ...@@ -1777,8 +1775,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
IPCB(skb)->flags |= IPSKB_FORWARDED; IPCB(skb)->flags |= IPSKB_FORWARDED;
/* /* RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
* RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
* not only before forwarding, but after forwarding on all output * not only before forwarding, but after forwarding on all output
* interfaces. It is clear, if mrouter runs a multicasting * interfaces. It is clear, if mrouter runs a multicasting
* program, it should receive packets not depending to what interface * program, it should receive packets not depending to what interface
...@@ -1809,7 +1806,6 @@ static int ipmr_find_vif(struct mr_table *mrt, struct net_device *dev) ...@@ -1809,7 +1806,6 @@ static int ipmr_find_vif(struct mr_table *mrt, struct net_device *dev)
} }
/* "local" means that we should preserve one skb (for local delivery) */ /* "local" means that we should preserve one skb (for local delivery) */
static void ip_mr_forward(struct net *net, struct mr_table *mrt, static void ip_mr_forward(struct net *net, struct mr_table *mrt,
struct sk_buff *skb, struct mfc_cache *cache, struct sk_buff *skb, struct mfc_cache *cache,
int local) int local)
...@@ -1834,9 +1830,7 @@ static void ip_mr_forward(struct net *net, struct mr_table *mrt, ...@@ -1834,9 +1830,7 @@ static void ip_mr_forward(struct net *net, struct mr_table *mrt,
goto forward; goto forward;
} }
/* /* Wrong interface: drop packet and (maybe) send PIM assert. */
* Wrong interface: drop packet and (maybe) send PIM assert.
*/
if (mrt->vif_table[vif].dev != skb->dev) { if (mrt->vif_table[vif].dev != skb->dev) {
if (rt_is_output_route(skb_rtable(skb))) { if (rt_is_output_route(skb_rtable(skb))) {
/* It is our own packet, looped back. /* It is our own packet, looped back.
...@@ -1875,9 +1869,7 @@ static void ip_mr_forward(struct net *net, struct mr_table *mrt, ...@@ -1875,9 +1869,7 @@ static void ip_mr_forward(struct net *net, struct mr_table *mrt,
mrt->vif_table[vif].pkt_in++; mrt->vif_table[vif].pkt_in++;
mrt->vif_table[vif].bytes_in += skb->len; mrt->vif_table[vif].bytes_in += skb->len;
/* /* Forward the frame */
* Forward the frame
*/
if (cache->mfc_origin == htonl(INADDR_ANY) && if (cache->mfc_origin == htonl(INADDR_ANY) &&
cache->mfc_mcastgrp == htonl(INADDR_ANY)) { cache->mfc_mcastgrp == htonl(INADDR_ANY)) {
if (true_vifi >= 0 && if (true_vifi >= 0 &&
...@@ -1951,11 +1943,9 @@ static struct mr_table *ipmr_rt_fib_lookup(struct net *net, struct sk_buff *skb) ...@@ -1951,11 +1943,9 @@ static struct mr_table *ipmr_rt_fib_lookup(struct net *net, struct sk_buff *skb)
return mrt; return mrt;
} }
/* /* Multicast packets for forwarding arrive here
* Multicast packets for forwarding arrive here
* Called with rcu_read_lock(); * Called with rcu_read_lock();
*/ */
int ip_mr_input(struct sk_buff *skb) int ip_mr_input(struct sk_buff *skb)
{ {
struct mfc_cache *cache; struct mfc_cache *cache;
...@@ -2006,9 +1996,7 @@ int ip_mr_input(struct sk_buff *skb) ...@@ -2006,9 +1996,7 @@ int ip_mr_input(struct sk_buff *skb)
vif); vif);
} }
/* /* No usable cache entry */
* No usable cache entry
*/
if (!cache) { if (!cache) {
int vif; int vif;
...@@ -2049,53 +2037,8 @@ int ip_mr_input(struct sk_buff *skb) ...@@ -2049,53 +2037,8 @@ int ip_mr_input(struct sk_buff *skb)
return 0; return 0;
} }
#ifdef CONFIG_IP_PIMSM
/* called with rcu_read_lock() */
static int __pim_rcv(struct mr_table *mrt, struct sk_buff *skb,
unsigned int pimlen)
{
struct net_device *reg_dev = NULL;
struct iphdr *encap;
encap = (struct iphdr *)(skb_transport_header(skb) + pimlen);
/*
* Check that:
* a. packet is really sent to a multicast group
* b. packet is not a NULL-REGISTER
* c. packet is not truncated
*/
if (!ipv4_is_multicast(encap->daddr) ||
encap->tot_len == 0 ||
ntohs(encap->tot_len) + pimlen > skb->len)
return 1;
read_lock(&mrt_lock);
if (mrt->mroute_reg_vif_num >= 0)
reg_dev = mrt->vif_table[mrt->mroute_reg_vif_num].dev;
read_unlock(&mrt_lock);
if (!reg_dev)
return 1;
skb->mac_header = skb->network_header;
skb_pull(skb, (u8 *)encap - skb->data);
skb_reset_network_header(skb);
skb->protocol = htons(ETH_P_IP);
skb->ip_summed = CHECKSUM_NONE;
skb_tunnel_rx(skb, reg_dev, dev_net(reg_dev));
netif_rx(skb);
return NET_RX_SUCCESS;
}
#endif
#ifdef CONFIG_IP_PIMSM_V1 #ifdef CONFIG_IP_PIMSM_V1
/* /* Handle IGMP messages of PIMv1 */
* Handle IGMP messages of PIMv1
*/
int pim_rcv_v1(struct sk_buff *skb) int pim_rcv_v1(struct sk_buff *skb)
{ {
struct igmphdr *pim; struct igmphdr *pim;
...@@ -2420,8 +2363,7 @@ static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -2420,8 +2363,7 @@ static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
} }
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
/* /* The /proc interfaces to multicast routing :
* The /proc interfaces to multicast routing :
* /proc/net/ip_mr_cache & /proc/net/ip_mr_vif * /proc/net/ip_mr_cache & /proc/net/ip_mr_vif
*/ */
struct ipmr_vif_iter { struct ipmr_vif_iter {
...@@ -2706,10 +2648,7 @@ static const struct net_protocol pim_protocol = { ...@@ -2706,10 +2648,7 @@ static const struct net_protocol pim_protocol = {
}; };
#endif #endif
/* Setup for IP multicast routing */
/*
* Setup for IP multicast routing
*/
static int __net_init ipmr_net_init(struct net *net) static int __net_init ipmr_net_init(struct net *net)
{ {
int err; int err;
...@@ -2759,8 +2698,6 @@ int __init ip_mr_init(void) ...@@ -2759,8 +2698,6 @@ int __init ip_mr_init(void)
sizeof(struct mfc_cache), sizeof(struct mfc_cache),
0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC,
NULL); NULL);
if (!mrt_cachep)
return -ENOMEM;
err = register_pernet_subsys(&ipmr_net_ops); err = register_pernet_subsys(&ipmr_net_ops);
if (err) if (err)
......
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