blob: d6aa65e2b08f3ea0d5ecfc65e1d6f4b11c5245da [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * IP multicast routing support for mrouted 3.6/3.8
3 *
Alan Cox113aa832008-10-13 19:01:08 -07004 * (c) 1995 Alan Cox, <alan@lxorguk.ukuu.org.uk>
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Linux Consultancy and Custom Driver Development
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 * Fixes:
13 * Michael Chastain : Incorrect size of copying.
14 * Alan Cox : Added the cache manager code
15 * Alan Cox : Fixed the clone/copy bug and device race.
16 * Mike McLagan : Routing by source
17 * Malcolm Beattie : Buffer handling fixes.
18 * Alexey Kuznetsov : Double buffer free and other fixes.
19 * SVR Anand : Fixed several multicast bugs and problems.
20 * Alexey Kuznetsov : Status, optimisations and more.
21 * Brad Parker : Better behaviour on mrouted upcall
22 * overflow.
23 * Carlos Picoto : PIMv1 Support
24 * Pavlin Ivanov Radoslavov: PIMv2 Registers must checksum only PIM header
25 * Relax this requrement to work with older peers.
26 *
27 */
28
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <asm/system.h>
30#include <asm/uaccess.h>
31#include <linux/types.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080032#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/errno.h>
34#include <linux/timer.h>
35#include <linux/mm.h>
36#include <linux/kernel.h>
37#include <linux/fcntl.h>
38#include <linux/stat.h>
39#include <linux/socket.h>
40#include <linux/in.h>
41#include <linux/inet.h>
42#include <linux/netdevice.h>
43#include <linux/inetdevice.h>
44#include <linux/igmp.h>
45#include <linux/proc_fs.h>
46#include <linux/seq_file.h>
47#include <linux/mroute.h>
48#include <linux/init.h>
Kris Katterjohn46f25df2006-01-05 16:35:42 -080049#include <linux/if_ether.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090050#include <linux/slab.h>
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020051#include <net/net_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <net/ip.h>
53#include <net/protocol.h>
54#include <linux/skbuff.h>
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020055#include <net/route.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#include <net/sock.h>
57#include <net/icmp.h>
58#include <net/udp.h>
59#include <net/raw.h>
60#include <linux/notifier.h>
61#include <linux/if_arp.h>
62#include <linux/netfilter_ipv4.h>
63#include <net/ipip.h>
64#include <net/checksum.h>
Arnaldo Carvalho de Melodc5fc572007-03-25 23:06:12 -070065#include <net/netlink.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67#if defined(CONFIG_IP_PIMSM_V1) || defined(CONFIG_IP_PIMSM_V2)
68#define CONFIG_IP_PIMSM 1
69#endif
70
Linus Torvalds1da177e2005-04-16 15:20:36 -070071/* Big lock, protecting vif table, mrt cache and mroute socket state.
72 Note that the changes are semaphored via rtnl_lock.
73 */
74
75static DEFINE_RWLOCK(mrt_lock);
76
77/*
78 * Multicast router control variables
79 */
80
Benjamin Therycf958ae32009-01-22 04:56:16 +000081#define VIF_EXISTS(_net, _idx) ((_net)->ipv4.vif_table[_idx].dev != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
Linus Torvalds1da177e2005-04-16 15:20:36 -070083/* Special spinlock for queue of unresolved entries */
84static DEFINE_SPINLOCK(mfc_unres_lock);
85
86/* We return to original Alan's scheme. Hash table of resolved
87 entries is changed only in process context and protected
88 with weak lock mrt_lock. Queue of unresolved entries is protected
89 with strong spinlock mfc_unres_lock.
90
91 In this case data path is free of exclusive locks at all.
92 */
93
Christoph Lametere18b8902006-12-06 20:33:20 -080094static struct kmem_cache *mrt_cachep __read_mostly;
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
96static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local);
Benjamin Thery4feb88e2009-01-22 04:56:23 +000097static int ipmr_cache_report(struct net *net,
98 struct sk_buff *pkt, vifi_t vifi, int assert);
Linus Torvalds1da177e2005-04-16 15:20:36 -070099static int ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm);
100
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101/* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */
102
Wang Chend6070322008-07-14 20:55:26 -0700103static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v)
104{
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000105 struct net *net = dev_net(dev);
106
Wang Chend6070322008-07-14 20:55:26 -0700107 dev_close(dev);
108
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000109 dev = __dev_get_by_name(net, "tunl0");
Wang Chend6070322008-07-14 20:55:26 -0700110 if (dev) {
Stephen Hemminger5bc3eb72008-11-19 21:52:05 -0800111 const struct net_device_ops *ops = dev->netdev_ops;
Wang Chend6070322008-07-14 20:55:26 -0700112 struct ifreq ifr;
Wang Chend6070322008-07-14 20:55:26 -0700113 struct ip_tunnel_parm p;
114
115 memset(&p, 0, sizeof(p));
116 p.iph.daddr = v->vifc_rmt_addr.s_addr;
117 p.iph.saddr = v->vifc_lcl_addr.s_addr;
118 p.iph.version = 4;
119 p.iph.ihl = 5;
120 p.iph.protocol = IPPROTO_IPIP;
121 sprintf(p.name, "dvmrp%d", v->vifc_vifi);
122 ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
123
Stephen Hemminger5bc3eb72008-11-19 21:52:05 -0800124 if (ops->ndo_do_ioctl) {
125 mm_segment_t oldfs = get_fs();
126
127 set_fs(KERNEL_DS);
128 ops->ndo_do_ioctl(dev, &ifr, SIOCDELTUNNEL);
129 set_fs(oldfs);
130 }
Wang Chend6070322008-07-14 20:55:26 -0700131 }
132}
133
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134static
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000135struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136{
137 struct net_device *dev;
138
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000139 dev = __dev_get_by_name(net, "tunl0");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
141 if (dev) {
Stephen Hemminger5bc3eb72008-11-19 21:52:05 -0800142 const struct net_device_ops *ops = dev->netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 int err;
144 struct ifreq ifr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 struct ip_tunnel_parm p;
146 struct in_device *in_dev;
147
148 memset(&p, 0, sizeof(p));
149 p.iph.daddr = v->vifc_rmt_addr.s_addr;
150 p.iph.saddr = v->vifc_lcl_addr.s_addr;
151 p.iph.version = 4;
152 p.iph.ihl = 5;
153 p.iph.protocol = IPPROTO_IPIP;
154 sprintf(p.name, "dvmrp%d", v->vifc_vifi);
Stephen Hemmingerba93ef72008-01-21 17:28:59 -0800155 ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
Stephen Hemminger5bc3eb72008-11-19 21:52:05 -0800157 if (ops->ndo_do_ioctl) {
158 mm_segment_t oldfs = get_fs();
159
160 set_fs(KERNEL_DS);
161 err = ops->ndo_do_ioctl(dev, &ifr, SIOCADDTUNNEL);
162 set_fs(oldfs);
163 } else
164 err = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
166 dev = NULL;
167
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000168 if (err == 0 &&
169 (dev = __dev_get_by_name(net, p.name)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 dev->flags |= IFF_MULTICAST;
171
Herbert Xue5ed6392005-10-03 14:35:55 -0700172 in_dev = __in_dev_get_rtnl(dev);
Herbert Xu71e27da2007-06-04 23:36:06 -0700173 if (in_dev == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 goto failure;
Herbert Xu71e27da2007-06-04 23:36:06 -0700175
176 ipv4_devconf_setall(in_dev);
177 IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
179 if (dev_open(dev))
180 goto failure;
Wang Chen7dc00c82008-07-14 20:56:34 -0700181 dev_hold(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 }
183 }
184 return dev;
185
186failure:
187 /* allow the register to be completed before unregistering. */
188 rtnl_unlock();
189 rtnl_lock();
190
191 unregister_netdevice(dev);
192 return NULL;
193}
194
195#ifdef CONFIG_IP_PIMSM
196
Stephen Hemminger6fef4c02009-08-31 19:50:41 +0000197static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198{
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000199 struct net *net = dev_net(dev);
200
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 read_lock(&mrt_lock);
Pavel Emelyanovcf3677a2008-05-21 14:17:33 -0700202 dev->stats.tx_bytes += skb->len;
203 dev->stats.tx_packets++;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000204 ipmr_cache_report(net, skb, net->ipv4.mroute_reg_vif_num,
205 IGMPMSG_WHOLEPKT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 read_unlock(&mrt_lock);
207 kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000208 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209}
210
Stephen Hemminger007c3832008-11-20 20:28:35 -0800211static const struct net_device_ops reg_vif_netdev_ops = {
212 .ndo_start_xmit = reg_vif_xmit,
213};
214
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215static void reg_vif_setup(struct net_device *dev)
216{
217 dev->type = ARPHRD_PIMREG;
Kris Katterjohn46f25df2006-01-05 16:35:42 -0800218 dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 dev->flags = IFF_NOARP;
Stephen Hemminger007c3832008-11-20 20:28:35 -0800220 dev->netdev_ops = &reg_vif_netdev_ops,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 dev->destructor = free_netdev;
Tom Goff403dbb92009-06-14 03:16:13 -0700222 dev->features |= NETIF_F_NETNS_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223}
224
Tom Goff403dbb92009-06-14 03:16:13 -0700225static struct net_device *ipmr_reg_vif(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226{
227 struct net_device *dev;
228 struct in_device *in_dev;
229
Pavel Emelyanovcf3677a2008-05-21 14:17:33 -0700230 dev = alloc_netdev(0, "pimreg", reg_vif_setup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231
232 if (dev == NULL)
233 return NULL;
234
Tom Goff403dbb92009-06-14 03:16:13 -0700235 dev_net_set(dev, net);
236
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 if (register_netdevice(dev)) {
238 free_netdev(dev);
239 return NULL;
240 }
241 dev->iflink = 0;
242
Herbert Xu71e27da2007-06-04 23:36:06 -0700243 rcu_read_lock();
244 if ((in_dev = __in_dev_get_rcu(dev)) == NULL) {
245 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 goto failure;
Herbert Xu71e27da2007-06-04 23:36:06 -0700247 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
Herbert Xu71e27da2007-06-04 23:36:06 -0700249 ipv4_devconf_setall(in_dev);
250 IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0;
251 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
253 if (dev_open(dev))
254 goto failure;
255
Wang Chen7dc00c82008-07-14 20:56:34 -0700256 dev_hold(dev);
257
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 return dev;
259
260failure:
261 /* allow the register to be completed before unregistering. */
262 rtnl_unlock();
263 rtnl_lock();
264
265 unregister_netdevice(dev);
266 return NULL;
267}
268#endif
269
270/*
271 * Delete a VIF entry
Wang Chen7dc00c82008-07-14 20:56:34 -0700272 * @notify: Set to 1, if the caller is a notifier_call
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900274
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000275static int vif_delete(struct net *net, int vifi, int notify,
276 struct list_head *head)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277{
278 struct vif_device *v;
279 struct net_device *dev;
280 struct in_device *in_dev;
281
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000282 if (vifi < 0 || vifi >= net->ipv4.maxvif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 return -EADDRNOTAVAIL;
284
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000285 v = &net->ipv4.vif_table[vifi];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
287 write_lock_bh(&mrt_lock);
288 dev = v->dev;
289 v->dev = NULL;
290
291 if (!dev) {
292 write_unlock_bh(&mrt_lock);
293 return -EADDRNOTAVAIL;
294 }
295
296#ifdef CONFIG_IP_PIMSM
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000297 if (vifi == net->ipv4.mroute_reg_vif_num)
298 net->ipv4.mroute_reg_vif_num = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299#endif
300
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000301 if (vifi+1 == net->ipv4.maxvif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 int tmp;
303 for (tmp=vifi-1; tmp>=0; tmp--) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000304 if (VIF_EXISTS(net, tmp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 break;
306 }
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000307 net->ipv4.maxvif = tmp+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 }
309
310 write_unlock_bh(&mrt_lock);
311
312 dev_set_allmulti(dev, -1);
313
Herbert Xue5ed6392005-10-03 14:35:55 -0700314 if ((in_dev = __in_dev_get_rtnl(dev)) != NULL) {
Herbert Xu42f811b2007-06-04 23:34:44 -0700315 IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 ip_rt_multicast_event(in_dev);
317 }
318
Wang Chen7dc00c82008-07-14 20:56:34 -0700319 if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER) && !notify)
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000320 unregister_netdevice_queue(dev, head);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
322 dev_put(dev);
323 return 0;
324}
325
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000326static inline void ipmr_cache_free(struct mfc_cache *c)
327{
328 release_net(mfc_net(c));
329 kmem_cache_free(mrt_cachep, c);
330}
331
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332/* Destroy an unresolved cache entry, killing queued skbs
333 and reporting error to netlink readers.
334 */
335
336static void ipmr_destroy_unres(struct mfc_cache *c)
337{
338 struct sk_buff *skb;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -0700339 struct nlmsgerr *e;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000340 struct net *net = mfc_net(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000342 atomic_dec(&net->ipv4.cache_resolve_queue_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
Jianjun Kongc354e122008-11-03 00:28:02 -0800344 while ((skb = skb_dequeue(&c->mfc_un.unres.unresolved))) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700345 if (ip_hdr(skb)->version == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
347 nlh->nlmsg_type = NLMSG_ERROR;
348 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
349 skb_trim(skb, nlh->nlmsg_len);
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -0700350 e = NLMSG_DATA(nlh);
351 e->error = -ETIMEDOUT;
352 memset(&e->msg, 0, sizeof(e->msg));
Thomas Graf2942e902006-08-15 00:30:25 -0700353
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000354 rtnl_unicast(skb, net, NETLINK_CB(skb).pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 } else
356 kfree_skb(skb);
357 }
358
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000359 ipmr_cache_free(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360}
361
362
Patrick McHardye258beb2010-04-13 05:03:19 +0000363/* Timer process for the unresolved queue. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
Patrick McHardye258beb2010-04-13 05:03:19 +0000365static void ipmr_expire_process(unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366{
Patrick McHardye258beb2010-04-13 05:03:19 +0000367 struct net *net = (struct net *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 unsigned long now;
369 unsigned long expires;
370 struct mfc_cache *c, **cp;
371
372 if (!spin_trylock(&mfc_unres_lock)) {
Patrick McHardye258beb2010-04-13 05:03:19 +0000373 mod_timer(&net->ipv4.ipmr_expire_timer, jiffies+HZ/10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 return;
375 }
376
Patrick McHardye258beb2010-04-13 05:03:19 +0000377 if (net->ipv4.mfc_unres_queue == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 goto out;
379
380 now = jiffies;
381 expires = 10*HZ;
Patrick McHardye258beb2010-04-13 05:03:19 +0000382 cp = &net->ipv4.mfc_unres_queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
384 while ((c=*cp) != NULL) {
385 if (time_after(c->mfc_un.unres.expires, now)) {
386 unsigned long interval = c->mfc_un.unres.expires - now;
387 if (interval < expires)
388 expires = interval;
389 cp = &c->next;
390 continue;
391 }
392
393 *cp = c->next;
394
395 ipmr_destroy_unres(c);
396 }
397
Patrick McHardye258beb2010-04-13 05:03:19 +0000398 if (net->ipv4.mfc_unres_queue != NULL)
399 mod_timer(&net->ipv4.ipmr_expire_timer, jiffies + expires);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400
401out:
402 spin_unlock(&mfc_unres_lock);
403}
404
405/* Fill oifs list. It is called under write locked mrt_lock. */
406
Baruch Evend1b04c02005-07-30 17:41:59 -0700407static void ipmr_update_thresholds(struct mfc_cache *cache, unsigned char *ttls)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408{
409 int vifi;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000410 struct net *net = mfc_net(cache);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411
412 cache->mfc_un.res.minvif = MAXVIFS;
413 cache->mfc_un.res.maxvif = 0;
414 memset(cache->mfc_un.res.ttls, 255, MAXVIFS);
415
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000416 for (vifi = 0; vifi < net->ipv4.maxvif; vifi++) {
417 if (VIF_EXISTS(net, vifi) &&
Benjamin Therycf958ae32009-01-22 04:56:16 +0000418 ttls[vifi] && ttls[vifi] < 255) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 cache->mfc_un.res.ttls[vifi] = ttls[vifi];
420 if (cache->mfc_un.res.minvif > vifi)
421 cache->mfc_un.res.minvif = vifi;
422 if (cache->mfc_un.res.maxvif <= vifi)
423 cache->mfc_un.res.maxvif = vifi + 1;
424 }
425 }
426}
427
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000428static int vif_add(struct net *net, struct vifctl *vifc, int mrtsock)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429{
430 int vifi = vifc->vifc_vifi;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000431 struct vif_device *v = &net->ipv4.vif_table[vifi];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 struct net_device *dev;
433 struct in_device *in_dev;
Wang Chend6070322008-07-14 20:55:26 -0700434 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
436 /* Is vif busy ? */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000437 if (VIF_EXISTS(net, vifi))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 return -EADDRINUSE;
439
440 switch (vifc->vifc_flags) {
441#ifdef CONFIG_IP_PIMSM
442 case VIFF_REGISTER:
443 /*
444 * Special Purpose VIF in PIM
445 * All the packets will be sent to the daemon
446 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000447 if (net->ipv4.mroute_reg_vif_num >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 return -EADDRINUSE;
Tom Goff403dbb92009-06-14 03:16:13 -0700449 dev = ipmr_reg_vif(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 if (!dev)
451 return -ENOBUFS;
Wang Chend6070322008-07-14 20:55:26 -0700452 err = dev_set_allmulti(dev, 1);
453 if (err) {
454 unregister_netdevice(dev);
Wang Chen7dc00c82008-07-14 20:56:34 -0700455 dev_put(dev);
Wang Chend6070322008-07-14 20:55:26 -0700456 return err;
457 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 break;
459#endif
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900460 case VIFF_TUNNEL:
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000461 dev = ipmr_new_tunnel(net, vifc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 if (!dev)
463 return -ENOBUFS;
Wang Chend6070322008-07-14 20:55:26 -0700464 err = dev_set_allmulti(dev, 1);
465 if (err) {
466 ipmr_del_tunnel(dev, vifc);
Wang Chen7dc00c82008-07-14 20:56:34 -0700467 dev_put(dev);
Wang Chend6070322008-07-14 20:55:26 -0700468 return err;
469 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 break;
Ilia Kee5e81f2009-09-16 05:53:07 +0000471
472 case VIFF_USE_IFINDEX:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 case 0:
Ilia Kee5e81f2009-09-16 05:53:07 +0000474 if (vifc->vifc_flags == VIFF_USE_IFINDEX) {
475 dev = dev_get_by_index(net, vifc->vifc_lcl_ifindex);
476 if (dev && dev->ip_ptr == NULL) {
477 dev_put(dev);
478 return -EADDRNOTAVAIL;
479 }
480 } else
481 dev = ip_dev_find(net, vifc->vifc_lcl_addr.s_addr);
482
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 if (!dev)
484 return -EADDRNOTAVAIL;
Wang Chend6070322008-07-14 20:55:26 -0700485 err = dev_set_allmulti(dev, 1);
Wang Chen7dc00c82008-07-14 20:56:34 -0700486 if (err) {
487 dev_put(dev);
Wang Chend6070322008-07-14 20:55:26 -0700488 return err;
Wang Chen7dc00c82008-07-14 20:56:34 -0700489 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 break;
491 default:
492 return -EINVAL;
493 }
494
Dan Carpenterd0490cf2009-11-11 02:03:54 +0000495 if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) {
496 dev_put(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 return -EADDRNOTAVAIL;
Dan Carpenterd0490cf2009-11-11 02:03:54 +0000498 }
Herbert Xu42f811b2007-06-04 23:34:44 -0700499 IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 ip_rt_multicast_event(in_dev);
501
502 /*
503 * Fill in the VIF structures
504 */
Jianjun Kongc354e122008-11-03 00:28:02 -0800505 v->rate_limit = vifc->vifc_rate_limit;
506 v->local = vifc->vifc_lcl_addr.s_addr;
507 v->remote = vifc->vifc_rmt_addr.s_addr;
508 v->flags = vifc->vifc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 if (!mrtsock)
510 v->flags |= VIFF_STATIC;
Jianjun Kongc354e122008-11-03 00:28:02 -0800511 v->threshold = vifc->vifc_threshold;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 v->bytes_in = 0;
513 v->bytes_out = 0;
514 v->pkt_in = 0;
515 v->pkt_out = 0;
516 v->link = dev->ifindex;
517 if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER))
518 v->link = dev->iflink;
519
520 /* And finish update writing critical data */
521 write_lock_bh(&mrt_lock);
Jianjun Kongc354e122008-11-03 00:28:02 -0800522 v->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523#ifdef CONFIG_IP_PIMSM
524 if (v->flags&VIFF_REGISTER)
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000525 net->ipv4.mroute_reg_vif_num = vifi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526#endif
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000527 if (vifi+1 > net->ipv4.maxvif)
528 net->ipv4.maxvif = vifi+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 write_unlock_bh(&mrt_lock);
530 return 0;
531}
532
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000533static struct mfc_cache *ipmr_cache_find(struct net *net,
534 __be32 origin,
535 __be32 mcastgrp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536{
Jianjun Kongc354e122008-11-03 00:28:02 -0800537 int line = MFC_HASH(mcastgrp, origin);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 struct mfc_cache *c;
539
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000540 for (c = net->ipv4.mfc_cache_array[line]; c; c = c->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 if (c->mfc_origin==origin && c->mfc_mcastgrp==mcastgrp)
542 break;
543 }
544 return c;
545}
546
547/*
548 * Allocate a multicast cache entry
549 */
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000550static struct mfc_cache *ipmr_cache_alloc(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551{
Jianjun Kongc354e122008-11-03 00:28:02 -0800552 struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
553 if (c == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 c->mfc_un.res.minvif = MAXVIFS;
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000556 mfc_net_set(c, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 return c;
558}
559
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000560static struct mfc_cache *ipmr_cache_alloc_unres(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561{
Jianjun Kongc354e122008-11-03 00:28:02 -0800562 struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
563 if (c == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 skb_queue_head_init(&c->mfc_un.unres.unresolved);
566 c->mfc_un.unres.expires = jiffies + 10*HZ;
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000567 mfc_net_set(c, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 return c;
569}
570
571/*
572 * A cache entry has gone into a resolved state from queued
573 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900574
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c)
576{
577 struct sk_buff *skb;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -0700578 struct nlmsgerr *e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579
580 /*
581 * Play the pending entries through our router
582 */
583
Jianjun Kongc354e122008-11-03 00:28:02 -0800584 while ((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700585 if (ip_hdr(skb)->version == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
587
588 if (ipmr_fill_mroute(skb, c, NLMSG_DATA(nlh)) > 0) {
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700589 nlh->nlmsg_len = (skb_tail_pointer(skb) -
590 (u8 *)nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 } else {
592 nlh->nlmsg_type = NLMSG_ERROR;
593 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
594 skb_trim(skb, nlh->nlmsg_len);
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -0700595 e = NLMSG_DATA(nlh);
596 e->error = -EMSGSIZE;
597 memset(&e->msg, 0, sizeof(e->msg));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 }
Thomas Graf2942e902006-08-15 00:30:25 -0700599
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000600 rtnl_unicast(skb, mfc_net(c), NETLINK_CB(skb).pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 } else
602 ip_mr_forward(skb, c, 0);
603 }
604}
605
606/*
607 * Bounce a cache query up to mrouted. We could use netlink for this but mrouted
608 * expects the following bizarre scheme.
609 *
610 * Called under mrt_lock.
611 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900612
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000613static int ipmr_cache_report(struct net *net,
614 struct sk_buff *pkt, vifi_t vifi, int assert)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615{
616 struct sk_buff *skb;
Arnaldo Carvalho de Meloc9bdd4b2007-03-12 20:09:15 -0300617 const int ihl = ip_hdrlen(pkt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 struct igmphdr *igmp;
619 struct igmpmsg *msg;
620 int ret;
621
622#ifdef CONFIG_IP_PIMSM
623 if (assert == IGMPMSG_WHOLEPKT)
624 skb = skb_realloc_headroom(pkt, sizeof(struct iphdr));
625 else
626#endif
627 skb = alloc_skb(128, GFP_ATOMIC);
628
Stephen Hemminger132adf52007-03-08 20:44:43 -0800629 if (!skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 return -ENOBUFS;
631
632#ifdef CONFIG_IP_PIMSM
633 if (assert == IGMPMSG_WHOLEPKT) {
634 /* Ugly, but we have no choice with this interface.
635 Duplicate old header, fix ihl, length etc.
636 And all this only to mangle msg->im_msgtype and
637 to set msg->im_mbz to "mbz" :-)
638 */
Arnaldo Carvalho de Melo878c8142007-03-11 22:38:29 -0300639 skb_push(skb, sizeof(struct iphdr));
640 skb_reset_network_header(skb);
Arnaldo Carvalho de Melobadff6d2007-03-13 13:06:52 -0300641 skb_reset_transport_header(skb);
Arnaldo Carvalho de Melo0272ffc2007-03-12 20:05:39 -0300642 msg = (struct igmpmsg *)skb_network_header(skb);
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700643 memcpy(msg, skb_network_header(pkt), sizeof(struct iphdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 msg->im_msgtype = IGMPMSG_WHOLEPKT;
645 msg->im_mbz = 0;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000646 msg->im_vif = net->ipv4.mroute_reg_vif_num;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700647 ip_hdr(skb)->ihl = sizeof(struct iphdr) >> 2;
648 ip_hdr(skb)->tot_len = htons(ntohs(ip_hdr(pkt)->tot_len) +
649 sizeof(struct iphdr));
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900650 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651#endif
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900652 {
653
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 /*
655 * Copy the IP header
656 */
657
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700658 skb->network_header = skb->tail;
Arnaldo Carvalho de Meloddc7b8e2007-03-15 21:42:27 -0300659 skb_put(skb, ihl);
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -0300660 skb_copy_to_linear_data(skb, pkt->data, ihl);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700661 ip_hdr(skb)->protocol = 0; /* Flag to the kernel this is a route add */
662 msg = (struct igmpmsg *)skb_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 msg->im_vif = vifi;
Eric Dumazetadf30902009-06-02 05:19:30 +0000664 skb_dst_set(skb, dst_clone(skb_dst(pkt)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
666 /*
667 * Add our header
668 */
669
Jianjun Kongc354e122008-11-03 00:28:02 -0800670 igmp=(struct igmphdr *)skb_put(skb, sizeof(struct igmphdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 igmp->type =
672 msg->im_msgtype = assert;
673 igmp->code = 0;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700674 ip_hdr(skb)->tot_len = htons(skb->len); /* Fix the length */
Arnaldo Carvalho de Melob0e380b2007-04-10 21:21:55 -0700675 skb->transport_header = skb->network_header;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900676 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000678 if (net->ipv4.mroute_sk == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 kfree_skb(skb);
680 return -EINVAL;
681 }
682
683 /*
684 * Deliver to mrouted
685 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000686 ret = sock_queue_rcv_skb(net->ipv4.mroute_sk, skb);
Benjamin Thery70a269e2009-01-22 04:56:15 +0000687 if (ret < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 if (net_ratelimit())
689 printk(KERN_WARNING "mroute: pending queue full, dropping entries.\n");
690 kfree_skb(skb);
691 }
692
693 return ret;
694}
695
696/*
697 * Queue a packet for resolution. It gets locked cache entry!
698 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900699
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700static int
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000701ipmr_cache_unresolved(struct net *net, vifi_t vifi, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702{
703 int err;
704 struct mfc_cache *c;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700705 const struct iphdr *iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706
707 spin_lock_bh(&mfc_unres_lock);
Patrick McHardye258beb2010-04-13 05:03:19 +0000708 for (c=net->ipv4.mfc_unres_queue; c; c=c->next) {
709 if (c->mfc_mcastgrp == iph->daddr &&
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700710 c->mfc_origin == iph->saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 break;
712 }
713
714 if (c == NULL) {
715 /*
716 * Create a new entry if allowable
717 */
718
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000719 if (atomic_read(&net->ipv4.cache_resolve_queue_len) >= 10 ||
720 (c = ipmr_cache_alloc_unres(net)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 spin_unlock_bh(&mfc_unres_lock);
722
723 kfree_skb(skb);
724 return -ENOBUFS;
725 }
726
727 /*
728 * Fill in the new cache entry
729 */
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700730 c->mfc_parent = -1;
731 c->mfc_origin = iph->saddr;
732 c->mfc_mcastgrp = iph->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733
734 /*
735 * Reflect first query at mrouted.
736 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000737 err = ipmr_cache_report(net, skb, vifi, IGMPMSG_NOCACHE);
738 if (err < 0) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900739 /* If the report failed throw the cache entry
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 out - Brad Parker
741 */
742 spin_unlock_bh(&mfc_unres_lock);
743
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000744 ipmr_cache_free(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 kfree_skb(skb);
746 return err;
747 }
748
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000749 atomic_inc(&net->ipv4.cache_resolve_queue_len);
Patrick McHardye258beb2010-04-13 05:03:19 +0000750 c->next = net->ipv4.mfc_unres_queue;
751 net->ipv4.mfc_unres_queue = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752
Patrick McHardye258beb2010-04-13 05:03:19 +0000753 mod_timer(&net->ipv4.ipmr_expire_timer, c->mfc_un.unres.expires);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 }
755
756 /*
757 * See if we can append the packet
758 */
759 if (c->mfc_un.unres.unresolved.qlen>3) {
760 kfree_skb(skb);
761 err = -ENOBUFS;
762 } else {
Jianjun Kongc354e122008-11-03 00:28:02 -0800763 skb_queue_tail(&c->mfc_un.unres.unresolved, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 err = 0;
765 }
766
767 spin_unlock_bh(&mfc_unres_lock);
768 return err;
769}
770
771/*
772 * MFC cache manipulation by user space mroute daemon
773 */
774
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000775static int ipmr_mfc_delete(struct net *net, struct mfcctl *mfc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776{
777 int line;
778 struct mfc_cache *c, **cp;
779
Jianjun Kongc354e122008-11-03 00:28:02 -0800780 line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000782 for (cp = &net->ipv4.mfc_cache_array[line];
Benjamin Thery2bb8b262009-01-22 04:56:18 +0000783 (c = *cp) != NULL; cp = &c->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
785 c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr) {
786 write_lock_bh(&mrt_lock);
787 *cp = c->next;
788 write_unlock_bh(&mrt_lock);
789
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000790 ipmr_cache_free(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 return 0;
792 }
793 }
794 return -ENOENT;
795}
796
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000797static int ipmr_mfc_add(struct net *net, struct mfcctl *mfc, int mrtsock)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798{
799 int line;
800 struct mfc_cache *uc, *c, **cp;
801
Patrick McHardya50436f22010-03-17 06:04:14 +0000802 if (mfc->mfcc_parent >= MAXVIFS)
803 return -ENFILE;
804
Jianjun Kongc354e122008-11-03 00:28:02 -0800805 line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000807 for (cp = &net->ipv4.mfc_cache_array[line];
Benjamin Thery2bb8b262009-01-22 04:56:18 +0000808 (c = *cp) != NULL; cp = &c->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
810 c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr)
811 break;
812 }
813
814 if (c != NULL) {
815 write_lock_bh(&mrt_lock);
816 c->mfc_parent = mfc->mfcc_parent;
Baruch Evend1b04c02005-07-30 17:41:59 -0700817 ipmr_update_thresholds(c, mfc->mfcc_ttls);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 if (!mrtsock)
819 c->mfc_flags |= MFC_STATIC;
820 write_unlock_bh(&mrt_lock);
821 return 0;
822 }
823
Joe Perchesf97c1e02007-12-16 13:45:43 -0800824 if (!ipv4_is_multicast(mfc->mfcc_mcastgrp.s_addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 return -EINVAL;
826
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000827 c = ipmr_cache_alloc(net);
Jianjun Kongc354e122008-11-03 00:28:02 -0800828 if (c == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 return -ENOMEM;
830
Jianjun Kongc354e122008-11-03 00:28:02 -0800831 c->mfc_origin = mfc->mfcc_origin.s_addr;
832 c->mfc_mcastgrp = mfc->mfcc_mcastgrp.s_addr;
833 c->mfc_parent = mfc->mfcc_parent;
Baruch Evend1b04c02005-07-30 17:41:59 -0700834 ipmr_update_thresholds(c, mfc->mfcc_ttls);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 if (!mrtsock)
836 c->mfc_flags |= MFC_STATIC;
837
838 write_lock_bh(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000839 c->next = net->ipv4.mfc_cache_array[line];
840 net->ipv4.mfc_cache_array[line] = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 write_unlock_bh(&mrt_lock);
842
843 /*
844 * Check to see if we resolved a queued list. If so we
845 * need to send on the frames and tidy up.
846 */
847 spin_lock_bh(&mfc_unres_lock);
Patrick McHardye258beb2010-04-13 05:03:19 +0000848 for (cp = &net->ipv4.mfc_unres_queue; (uc=*cp) != NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 cp = &uc->next) {
Patrick McHardye258beb2010-04-13 05:03:19 +0000850 if (uc->mfc_origin == c->mfc_origin &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 uc->mfc_mcastgrp == c->mfc_mcastgrp) {
852 *cp = uc->next;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000853 atomic_dec(&net->ipv4.cache_resolve_queue_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 break;
855 }
856 }
Patrick McHardye258beb2010-04-13 05:03:19 +0000857 if (net->ipv4.mfc_unres_queue == NULL)
858 del_timer(&net->ipv4.ipmr_expire_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 spin_unlock_bh(&mfc_unres_lock);
860
861 if (uc) {
862 ipmr_cache_resolve(uc, c);
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000863 ipmr_cache_free(uc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 }
865 return 0;
866}
867
868/*
869 * Close the multicast socket, and clear the vif tables etc
870 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900871
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000872static void mroute_clean_tables(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873{
874 int i;
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000875 LIST_HEAD(list);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900876
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 /*
878 * Shut down all active vif entries
879 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000880 for (i = 0; i < net->ipv4.maxvif; i++) {
881 if (!(net->ipv4.vif_table[i].flags&VIFF_STATIC))
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000882 vif_delete(net, i, 0, &list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 }
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000884 unregister_netdevice_many(&list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885
886 /*
887 * Wipe the cache
888 */
Jianjun Kongc354e122008-11-03 00:28:02 -0800889 for (i=0; i<MFC_LINES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 struct mfc_cache *c, **cp;
891
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000892 cp = &net->ipv4.mfc_cache_array[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 while ((c = *cp) != NULL) {
894 if (c->mfc_flags&MFC_STATIC) {
895 cp = &c->next;
896 continue;
897 }
898 write_lock_bh(&mrt_lock);
899 *cp = c->next;
900 write_unlock_bh(&mrt_lock);
901
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000902 ipmr_cache_free(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 }
904 }
905
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000906 if (atomic_read(&net->ipv4.cache_resolve_queue_len) != 0) {
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000907 struct mfc_cache *c, **cp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908
909 spin_lock_bh(&mfc_unres_lock);
Patrick McHardye258beb2010-04-13 05:03:19 +0000910 cp = &net->ipv4.mfc_unres_queue;
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000911 while ((c = *cp) != NULL) {
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000912 *cp = c->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 ipmr_destroy_unres(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 }
915 spin_unlock_bh(&mfc_unres_lock);
916 }
917}
918
919static void mrtsock_destruct(struct sock *sk)
920{
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000921 struct net *net = sock_net(sk);
922
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 rtnl_lock();
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000924 if (sk == net->ipv4.mroute_sk) {
925 IPV4_DEVCONF_ALL(net, MC_FORWARDING)--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926
927 write_lock_bh(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000928 net->ipv4.mroute_sk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 write_unlock_bh(&mrt_lock);
930
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000931 mroute_clean_tables(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 }
933 rtnl_unlock();
934}
935
936/*
937 * Socket options and virtual interface manipulation. The whole
938 * virtual interface system is a complete heap, but unfortunately
939 * that's how BSD mrouted happens to think. Maybe one day with a proper
940 * MOSPF/PIM router set up we can clean this up.
941 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900942
David S. Millerb7058842009-09-30 16:12:20 -0700943int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944{
945 int ret;
946 struct vifctl vif;
947 struct mfcctl mfc;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000948 struct net *net = sock_net(sk);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900949
Stephen Hemminger132adf52007-03-08 20:44:43 -0800950 if (optname != MRT_INIT) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000951 if (sk != net->ipv4.mroute_sk && !capable(CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 return -EACCES;
953 }
954
Stephen Hemminger132adf52007-03-08 20:44:43 -0800955 switch (optname) {
956 case MRT_INIT:
957 if (sk->sk_type != SOCK_RAW ||
Eric Dumazetc720c7e2009-10-15 06:30:45 +0000958 inet_sk(sk)->inet_num != IPPROTO_IGMP)
Stephen Hemminger132adf52007-03-08 20:44:43 -0800959 return -EOPNOTSUPP;
Jianjun Kongc354e122008-11-03 00:28:02 -0800960 if (optlen != sizeof(int))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800961 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962
Stephen Hemminger132adf52007-03-08 20:44:43 -0800963 rtnl_lock();
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000964 if (net->ipv4.mroute_sk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 rtnl_unlock();
Stephen Hemminger132adf52007-03-08 20:44:43 -0800966 return -EADDRINUSE;
967 }
968
969 ret = ip_ra_control(sk, 1, mrtsock_destruct);
970 if (ret == 0) {
971 write_lock_bh(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000972 net->ipv4.mroute_sk = sk;
Stephen Hemminger132adf52007-03-08 20:44:43 -0800973 write_unlock_bh(&mrt_lock);
974
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000975 IPV4_DEVCONF_ALL(net, MC_FORWARDING)++;
Stephen Hemminger132adf52007-03-08 20:44:43 -0800976 }
977 rtnl_unlock();
978 return ret;
979 case MRT_DONE:
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000980 if (sk != net->ipv4.mroute_sk)
Stephen Hemminger132adf52007-03-08 20:44:43 -0800981 return -EACCES;
982 return ip_ra_control(sk, 0, NULL);
983 case MRT_ADD_VIF:
984 case MRT_DEL_VIF:
Jianjun Kongc354e122008-11-03 00:28:02 -0800985 if (optlen != sizeof(vif))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800986 return -EINVAL;
Jianjun Kongc354e122008-11-03 00:28:02 -0800987 if (copy_from_user(&vif, optval, sizeof(vif)))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800988 return -EFAULT;
989 if (vif.vifc_vifi >= MAXVIFS)
990 return -ENFILE;
991 rtnl_lock();
Jianjun Kongc354e122008-11-03 00:28:02 -0800992 if (optname == MRT_ADD_VIF) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000993 ret = vif_add(net, &vif, sk == net->ipv4.mroute_sk);
Stephen Hemminger132adf52007-03-08 20:44:43 -0800994 } else {
Eric Dumazetd17fa6f2009-10-28 05:21:38 +0000995 ret = vif_delete(net, vif.vifc_vifi, 0, NULL);
Stephen Hemminger132adf52007-03-08 20:44:43 -0800996 }
997 rtnl_unlock();
998 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
1000 /*
1001 * Manipulate the forwarding caches. These live
1002 * in a sort of kernel/user symbiosis.
1003 */
Stephen Hemminger132adf52007-03-08 20:44:43 -08001004 case MRT_ADD_MFC:
1005 case MRT_DEL_MFC:
Jianjun Kongc354e122008-11-03 00:28:02 -08001006 if (optlen != sizeof(mfc))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001007 return -EINVAL;
Jianjun Kongc354e122008-11-03 00:28:02 -08001008 if (copy_from_user(&mfc, optval, sizeof(mfc)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001009 return -EFAULT;
1010 rtnl_lock();
Jianjun Kongc354e122008-11-03 00:28:02 -08001011 if (optname == MRT_DEL_MFC)
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001012 ret = ipmr_mfc_delete(net, &mfc);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001013 else
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001014 ret = ipmr_mfc_add(net, &mfc, sk == net->ipv4.mroute_sk);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001015 rtnl_unlock();
1016 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 /*
1018 * Control PIM assert.
1019 */
Stephen Hemminger132adf52007-03-08 20:44:43 -08001020 case MRT_ASSERT:
1021 {
1022 int v;
1023 if (get_user(v,(int __user *)optval))
1024 return -EFAULT;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001025 net->ipv4.mroute_do_assert = (v) ? 1 : 0;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001026 return 0;
1027 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028#ifdef CONFIG_IP_PIMSM
Stephen Hemminger132adf52007-03-08 20:44:43 -08001029 case MRT_PIM:
1030 {
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001031 int v;
1032
Stephen Hemminger132adf52007-03-08 20:44:43 -08001033 if (get_user(v,(int __user *)optval))
1034 return -EFAULT;
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001035 v = (v) ? 1 : 0;
1036
Stephen Hemminger132adf52007-03-08 20:44:43 -08001037 rtnl_lock();
1038 ret = 0;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001039 if (v != net->ipv4.mroute_do_pim) {
1040 net->ipv4.mroute_do_pim = v;
1041 net->ipv4.mroute_do_assert = v;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 }
Stephen Hemminger132adf52007-03-08 20:44:43 -08001043 rtnl_unlock();
1044 return ret;
1045 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046#endif
Stephen Hemminger132adf52007-03-08 20:44:43 -08001047 /*
1048 * Spurious command, or MRT_VERSION which you cannot
1049 * set.
1050 */
1051 default:
1052 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 }
1054}
1055
1056/*
1057 * Getsock opt support for the multicast routing system.
1058 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001059
Jianjun Kongc354e122008-11-03 00:28:02 -08001060int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int __user *optlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061{
1062 int olr;
1063 int val;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001064 struct net *net = sock_net(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
Jianjun Kongc354e122008-11-03 00:28:02 -08001066 if (optname != MRT_VERSION &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067#ifdef CONFIG_IP_PIMSM
1068 optname!=MRT_PIM &&
1069#endif
1070 optname!=MRT_ASSERT)
1071 return -ENOPROTOOPT;
1072
1073 if (get_user(olr, optlen))
1074 return -EFAULT;
1075
1076 olr = min_t(unsigned int, olr, sizeof(int));
1077 if (olr < 0)
1078 return -EINVAL;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001079
Jianjun Kongc354e122008-11-03 00:28:02 -08001080 if (put_user(olr, optlen))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 return -EFAULT;
Jianjun Kongc354e122008-11-03 00:28:02 -08001082 if (optname == MRT_VERSION)
1083 val = 0x0305;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084#ifdef CONFIG_IP_PIMSM
Jianjun Kongc354e122008-11-03 00:28:02 -08001085 else if (optname == MRT_PIM)
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001086 val = net->ipv4.mroute_do_pim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087#endif
1088 else
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001089 val = net->ipv4.mroute_do_assert;
Jianjun Kongc354e122008-11-03 00:28:02 -08001090 if (copy_to_user(optval, &val, olr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 return -EFAULT;
1092 return 0;
1093}
1094
1095/*
1096 * The IP multicast ioctl support routines.
1097 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001098
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
1100{
1101 struct sioc_sg_req sr;
1102 struct sioc_vif_req vr;
1103 struct vif_device *vif;
1104 struct mfc_cache *c;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001105 struct net *net = sock_net(sk);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001106
Stephen Hemminger132adf52007-03-08 20:44:43 -08001107 switch (cmd) {
1108 case SIOCGETVIFCNT:
Jianjun Kongc354e122008-11-03 00:28:02 -08001109 if (copy_from_user(&vr, arg, sizeof(vr)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001110 return -EFAULT;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001111 if (vr.vifi >= net->ipv4.maxvif)
Stephen Hemminger132adf52007-03-08 20:44:43 -08001112 return -EINVAL;
1113 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001114 vif = &net->ipv4.vif_table[vr.vifi];
1115 if (VIF_EXISTS(net, vr.vifi)) {
Jianjun Kongc354e122008-11-03 00:28:02 -08001116 vr.icount = vif->pkt_in;
1117 vr.ocount = vif->pkt_out;
1118 vr.ibytes = vif->bytes_in;
1119 vr.obytes = vif->bytes_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 read_unlock(&mrt_lock);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001121
Jianjun Kongc354e122008-11-03 00:28:02 -08001122 if (copy_to_user(arg, &vr, sizeof(vr)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 return -EFAULT;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001124 return 0;
1125 }
1126 read_unlock(&mrt_lock);
1127 return -EADDRNOTAVAIL;
1128 case SIOCGETSGCNT:
Jianjun Kongc354e122008-11-03 00:28:02 -08001129 if (copy_from_user(&sr, arg, sizeof(sr)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001130 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
Stephen Hemminger132adf52007-03-08 20:44:43 -08001132 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001133 c = ipmr_cache_find(net, sr.src.s_addr, sr.grp.s_addr);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001134 if (c) {
1135 sr.pktcnt = c->mfc_un.res.pkt;
1136 sr.bytecnt = c->mfc_un.res.bytes;
1137 sr.wrong_if = c->mfc_un.res.wrong_if;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 read_unlock(&mrt_lock);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001139
Jianjun Kongc354e122008-11-03 00:28:02 -08001140 if (copy_to_user(arg, &sr, sizeof(sr)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001141 return -EFAULT;
1142 return 0;
1143 }
1144 read_unlock(&mrt_lock);
1145 return -EADDRNOTAVAIL;
1146 default:
1147 return -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 }
1149}
1150
1151
1152static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr)
1153{
Eric W. Biedermane9dc8652007-09-12 13:02:17 +02001154 struct net_device *dev = ptr;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001155 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 struct vif_device *v;
1157 int ct;
Eric Dumazetd17fa6f2009-10-28 05:21:38 +00001158 LIST_HEAD(list);
Eric W. Biedermane9dc8652007-09-12 13:02:17 +02001159
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 if (event != NETDEV_UNREGISTER)
1161 return NOTIFY_DONE;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001162 v = &net->ipv4.vif_table[0];
1163 for (ct = 0; ct < net->ipv4.maxvif; ct++, v++) {
Jianjun Kongc354e122008-11-03 00:28:02 -08001164 if (v->dev == dev)
Eric Dumazetd17fa6f2009-10-28 05:21:38 +00001165 vif_delete(net, ct, 1, &list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 }
Eric Dumazetd17fa6f2009-10-28 05:21:38 +00001167 unregister_netdevice_many(&list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 return NOTIFY_DONE;
1169}
1170
1171
Jianjun Kongc354e122008-11-03 00:28:02 -08001172static struct notifier_block ip_mr_notifier = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 .notifier_call = ipmr_device_event,
1174};
1175
1176/*
1177 * Encapsulate a packet by attaching a valid IPIP header to it.
1178 * This avoids tunnel drivers and other mess and gives us the speed so
1179 * important for multicast video.
1180 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001181
Al Viro114c7842006-09-27 18:39:29 -07001182static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183{
Arnaldo Carvalho de Melo8856dfa2007-03-10 19:40:39 -03001184 struct iphdr *iph;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001185 struct iphdr *old_iph = ip_hdr(skb);
Arnaldo Carvalho de Melo8856dfa2007-03-10 19:40:39 -03001186
1187 skb_push(skb, sizeof(struct iphdr));
Arnaldo Carvalho de Melob0e380b2007-04-10 21:21:55 -07001188 skb->transport_header = skb->network_header;
Arnaldo Carvalho de Melo8856dfa2007-03-10 19:40:39 -03001189 skb_reset_network_header(skb);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001190 iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191
1192 iph->version = 4;
Arnaldo Carvalho de Meloe023dd62007-03-12 20:09:36 -03001193 iph->tos = old_iph->tos;
1194 iph->ttl = old_iph->ttl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 iph->frag_off = 0;
1196 iph->daddr = daddr;
1197 iph->saddr = saddr;
1198 iph->protocol = IPPROTO_IPIP;
1199 iph->ihl = 5;
1200 iph->tot_len = htons(skb->len);
Eric Dumazetadf30902009-06-02 05:19:30 +00001201 ip_select_ident(iph, skb_dst(skb), NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 ip_send_check(iph);
1203
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
1205 nf_reset(skb);
1206}
1207
1208static inline int ipmr_forward_finish(struct sk_buff *skb)
1209{
1210 struct ip_options * opt = &(IPCB(skb)->opt);
1211
Eric Dumazetadf30902009-06-02 05:19:30 +00001212 IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTFORWDATAGRAMS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213
1214 if (unlikely(opt->optlen))
1215 ip_forward_options(skb);
1216
1217 return dst_output(skb);
1218}
1219
1220/*
1221 * Processing handlers for ipmr_forward
1222 */
1223
1224static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi)
1225{
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001226 struct net *net = mfc_net(c);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001227 const struct iphdr *iph = ip_hdr(skb);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001228 struct vif_device *vif = &net->ipv4.vif_table[vifi];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 struct net_device *dev;
1230 struct rtable *rt;
1231 int encap = 0;
1232
1233 if (vif->dev == NULL)
1234 goto out_free;
1235
1236#ifdef CONFIG_IP_PIMSM
1237 if (vif->flags & VIFF_REGISTER) {
1238 vif->pkt_out++;
Jianjun Kongc354e122008-11-03 00:28:02 -08001239 vif->bytes_out += skb->len;
Pavel Emelyanovcf3677a2008-05-21 14:17:33 -07001240 vif->dev->stats.tx_bytes += skb->len;
1241 vif->dev->stats.tx_packets++;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001242 ipmr_cache_report(net, skb, vifi, IGMPMSG_WHOLEPKT);
Ilpo Järvinen69ebbf52009-02-06 23:46:51 -08001243 goto out_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 }
1245#endif
1246
1247 if (vif->flags&VIFF_TUNNEL) {
1248 struct flowi fl = { .oif = vif->link,
1249 .nl_u = { .ip4_u =
1250 { .daddr = vif->remote,
1251 .saddr = vif->local,
1252 .tos = RT_TOS(iph->tos) } },
1253 .proto = IPPROTO_IPIP };
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001254 if (ip_route_output_key(net, &rt, &fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 goto out_free;
1256 encap = sizeof(struct iphdr);
1257 } else {
1258 struct flowi fl = { .oif = vif->link,
1259 .nl_u = { .ip4_u =
1260 { .daddr = iph->daddr,
1261 .tos = RT_TOS(iph->tos) } },
1262 .proto = IPPROTO_IPIP };
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001263 if (ip_route_output_key(net, &rt, &fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 goto out_free;
1265 }
1266
1267 dev = rt->u.dst.dev;
1268
1269 if (skb->len+encap > dst_mtu(&rt->u.dst) && (ntohs(iph->frag_off) & IP_DF)) {
1270 /* Do not fragment multicasts. Alas, IPv4 does not
1271 allow to send ICMP, so that packets will disappear
1272 to blackhole.
1273 */
1274
Pavel Emelyanov7c73a6f2008-07-16 20:20:11 -07001275 IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 ip_rt_put(rt);
1277 goto out_free;
1278 }
1279
1280 encap += LL_RESERVED_SPACE(dev) + rt->u.dst.header_len;
1281
1282 if (skb_cow(skb, encap)) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001283 ip_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 goto out_free;
1285 }
1286
1287 vif->pkt_out++;
Jianjun Kongc354e122008-11-03 00:28:02 -08001288 vif->bytes_out += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289
Eric Dumazetadf30902009-06-02 05:19:30 +00001290 skb_dst_drop(skb);
1291 skb_dst_set(skb, &rt->u.dst);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001292 ip_decrease_ttl(ip_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293
1294 /* FIXME: forward and output firewalls used to be called here.
1295 * What do we do with netfilter? -- RR */
1296 if (vif->flags & VIFF_TUNNEL) {
1297 ip_encap(skb, vif->local, vif->remote);
1298 /* FIXME: extra output firewall step used to be here. --RR */
Pavel Emelyanov2f4c02d2008-05-21 14:16:14 -07001299 vif->dev->stats.tx_packets++;
1300 vif->dev->stats.tx_bytes += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 }
1302
1303 IPCB(skb)->flags |= IPSKB_FORWARDED;
1304
1305 /*
1306 * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
1307 * not only before forwarding, but after forwarding on all output
1308 * interfaces. It is clear, if mrouter runs a multicasting
1309 * program, it should receive packets not depending to what interface
1310 * program is joined.
1311 * If we will not make it, the program will have to join on all
1312 * interfaces. On the other hand, multihoming host (or router, but
1313 * not mrouter) cannot join to more than one interface - it will
1314 * result in receiving multiple packets.
1315 */
Patrick McHardy6e23ae22007-11-19 18:53:30 -08001316 NF_HOOK(PF_INET, NF_INET_FORWARD, skb, skb->dev, dev,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 ipmr_forward_finish);
1318 return;
1319
1320out_free:
1321 kfree_skb(skb);
1322 return;
1323}
1324
1325static int ipmr_find_vif(struct net_device *dev)
1326{
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001327 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 int ct;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001329 for (ct = net->ipv4.maxvif-1; ct >= 0; ct--) {
1330 if (net->ipv4.vif_table[ct].dev == dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 break;
1332 }
1333 return ct;
1334}
1335
1336/* "local" means that we should preserve one skb (for local delivery) */
1337
1338static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local)
1339{
1340 int psend = -1;
1341 int vif, ct;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001342 struct net *net = mfc_net(cache);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343
1344 vif = cache->mfc_parent;
1345 cache->mfc_un.res.pkt++;
1346 cache->mfc_un.res.bytes += skb->len;
1347
1348 /*
1349 * Wrong interface: drop packet and (maybe) send PIM assert.
1350 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001351 if (net->ipv4.vif_table[vif].dev != skb->dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 int true_vifi;
1353
Eric Dumazet511c3f92009-06-02 05:14:27 +00001354 if (skb_rtable(skb)->fl.iif == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 /* It is our own packet, looped back.
1356 Very complicated situation...
1357
1358 The best workaround until routing daemons will be
1359 fixed is not to redistribute packet, if it was
1360 send through wrong interface. It means, that
1361 multicast applications WILL NOT work for
1362 (S,G), which have default multicast route pointing
1363 to wrong oif. In any case, it is not a good
1364 idea to use multicasting applications on router.
1365 */
1366 goto dont_forward;
1367 }
1368
1369 cache->mfc_un.res.wrong_if++;
1370 true_vifi = ipmr_find_vif(skb->dev);
1371
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001372 if (true_vifi >= 0 && net->ipv4.mroute_do_assert &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 /* pimsm uses asserts, when switching from RPT to SPT,
1374 so that we cannot check that packet arrived on an oif.
1375 It is bad, but otherwise we would need to move pretty
1376 large chunk of pimd to kernel. Ough... --ANK
1377 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001378 (net->ipv4.mroute_do_pim ||
Benjamin Thery6f9374a2009-01-22 04:56:20 +00001379 cache->mfc_un.res.ttls[true_vifi] < 255) &&
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001380 time_after(jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) {
1382 cache->mfc_un.res.last_assert = jiffies;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001383 ipmr_cache_report(net, skb, true_vifi, IGMPMSG_WRONGVIF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 }
1385 goto dont_forward;
1386 }
1387
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001388 net->ipv4.vif_table[vif].pkt_in++;
1389 net->ipv4.vif_table[vif].bytes_in += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390
1391 /*
1392 * Forward the frame
1393 */
1394 for (ct = cache->mfc_un.res.maxvif-1; ct >= cache->mfc_un.res.minvif; ct--) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001395 if (ip_hdr(skb)->ttl > cache->mfc_un.res.ttls[ct]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 if (psend != -1) {
1397 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
1398 if (skb2)
1399 ipmr_queue_xmit(skb2, cache, psend);
1400 }
Jianjun Kongc354e122008-11-03 00:28:02 -08001401 psend = ct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 }
1403 }
1404 if (psend != -1) {
1405 if (local) {
1406 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
1407 if (skb2)
1408 ipmr_queue_xmit(skb2, cache, psend);
1409 } else {
1410 ipmr_queue_xmit(skb, cache, psend);
1411 return 0;
1412 }
1413 }
1414
1415dont_forward:
1416 if (!local)
1417 kfree_skb(skb);
1418 return 0;
1419}
1420
1421
1422/*
1423 * Multicast packets for forwarding arrive here
1424 */
1425
1426int ip_mr_input(struct sk_buff *skb)
1427{
1428 struct mfc_cache *cache;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001429 struct net *net = dev_net(skb->dev);
Eric Dumazet511c3f92009-06-02 05:14:27 +00001430 int local = skb_rtable(skb)->rt_flags & RTCF_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431
1432 /* Packet is looped back after forward, it should not be
1433 forwarded second time, but still can be delivered locally.
1434 */
1435 if (IPCB(skb)->flags&IPSKB_FORWARDED)
1436 goto dont_forward;
1437
1438 if (!local) {
1439 if (IPCB(skb)->opt.router_alert) {
1440 if (ip_call_ra_chain(skb))
1441 return 0;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001442 } else if (ip_hdr(skb)->protocol == IPPROTO_IGMP){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 /* IGMPv1 (and broken IGMPv2 implementations sort of
1444 Cisco IOS <= 11.2(8)) do not put router alert
1445 option to IGMP packets destined to routable
1446 groups. It is very bad, because it means
1447 that we can forward NO IGMP messages.
1448 */
1449 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001450 if (net->ipv4.mroute_sk) {
Patrick McHardy2715bcf2005-06-21 14:06:24 -07001451 nf_reset(skb);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001452 raw_rcv(net->ipv4.mroute_sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 read_unlock(&mrt_lock);
1454 return 0;
1455 }
1456 read_unlock(&mrt_lock);
1457 }
1458 }
1459
1460 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001461 cache = ipmr_cache_find(net, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462
1463 /*
1464 * No usable cache entry
1465 */
Jianjun Kongc354e122008-11-03 00:28:02 -08001466 if (cache == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 int vif;
1468
1469 if (local) {
1470 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
1471 ip_local_deliver(skb);
1472 if (skb2 == NULL) {
1473 read_unlock(&mrt_lock);
1474 return -ENOBUFS;
1475 }
1476 skb = skb2;
1477 }
1478
1479 vif = ipmr_find_vif(skb->dev);
1480 if (vif >= 0) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001481 int err = ipmr_cache_unresolved(net, vif, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 read_unlock(&mrt_lock);
1483
1484 return err;
1485 }
1486 read_unlock(&mrt_lock);
1487 kfree_skb(skb);
1488 return -ENODEV;
1489 }
1490
1491 ip_mr_forward(skb, cache, local);
1492
1493 read_unlock(&mrt_lock);
1494
1495 if (local)
1496 return ip_local_deliver(skb);
1497
1498 return 0;
1499
1500dont_forward:
1501 if (local)
1502 return ip_local_deliver(skb);
1503 kfree_skb(skb);
1504 return 0;
1505}
1506
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001507#ifdef CONFIG_IP_PIMSM
1508static int __pim_rcv(struct sk_buff *skb, unsigned int pimlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509{
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001510 struct net_device *reg_dev = NULL;
1511 struct iphdr *encap;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001512 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001514 encap = (struct iphdr *)(skb_transport_header(skb) + pimlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 /*
1516 Check that:
1517 a. packet is really destinted to a multicast group
1518 b. packet is not a NULL-REGISTER
1519 c. packet is not truncated
1520 */
Joe Perchesf97c1e02007-12-16 13:45:43 -08001521 if (!ipv4_is_multicast(encap->daddr) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 encap->tot_len == 0 ||
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001523 ntohs(encap->tot_len) + pimlen > skb->len)
1524 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525
1526 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001527 if (net->ipv4.mroute_reg_vif_num >= 0)
1528 reg_dev = net->ipv4.vif_table[net->ipv4.mroute_reg_vif_num].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529 if (reg_dev)
1530 dev_hold(reg_dev);
1531 read_unlock(&mrt_lock);
1532
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001533 if (reg_dev == NULL)
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001534 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535
Arnaldo Carvalho de Melob0e380b2007-04-10 21:21:55 -07001536 skb->mac_header = skb->network_header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 skb_pull(skb, (u8*)encap - skb->data);
Arnaldo Carvalho de Melo31c77112007-03-10 19:04:55 -03001538 skb_reset_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 skb->dev = reg_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 skb->protocol = htons(ETH_P_IP);
1541 skb->ip_summed = 0;
1542 skb->pkt_type = PACKET_HOST;
Eric Dumazetadf30902009-06-02 05:19:30 +00001543 skb_dst_drop(skb);
Pavel Emelyanovcf3677a2008-05-21 14:17:33 -07001544 reg_dev->stats.rx_bytes += skb->len;
1545 reg_dev->stats.rx_packets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 nf_reset(skb);
1547 netif_rx(skb);
1548 dev_put(reg_dev);
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001549
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 return 0;
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001551}
1552#endif
1553
1554#ifdef CONFIG_IP_PIMSM_V1
1555/*
1556 * Handle IGMP messages of PIMv1
1557 */
1558
1559int pim_rcv_v1(struct sk_buff * skb)
1560{
1561 struct igmphdr *pim;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001562 struct net *net = dev_net(skb->dev);
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001563
1564 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr)))
1565 goto drop;
1566
1567 pim = igmp_hdr(skb);
1568
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001569 if (!net->ipv4.mroute_do_pim ||
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001570 pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER)
1571 goto drop;
1572
1573 if (__pim_rcv(skb, sizeof(*pim))) {
1574drop:
1575 kfree_skb(skb);
1576 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 return 0;
1578}
1579#endif
1580
1581#ifdef CONFIG_IP_PIMSM_V2
1582static int pim_rcv(struct sk_buff * skb)
1583{
1584 struct pimreghdr *pim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001586 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 goto drop;
1588
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001589 pim = (struct pimreghdr *)skb_transport_header(skb);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001590 if (pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 (pim->flags&PIM_NULL_REGISTER) ||
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001592 (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 &&
Al Virod3bc23e2006-11-14 21:24:49 -08001593 csum_fold(skb_checksum(skb, 0, skb->len, 0))))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 goto drop;
1595
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001596 if (__pim_rcv(skb, sizeof(*pim))) {
1597drop:
1598 kfree_skb(skb);
1599 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 return 0;
1601}
1602#endif
1603
1604static int
1605ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm)
1606{
1607 int ct;
1608 struct rtnexthop *nhp;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001609 struct net *net = mfc_net(c);
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001610 u8 *b = skb_tail_pointer(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 struct rtattr *mp_head;
1612
Nicolas Dichtel74381892010-03-25 23:45:35 +00001613 /* If cache is unresolved, don't try to parse IIF and OIF */
1614 if (c->mfc_parent > MAXVIFS)
1615 return -ENOENT;
1616
1617 if (VIF_EXISTS(net, c->mfc_parent))
1618 RTA_PUT(skb, RTA_IIF, 4, &net->ipv4.vif_table[c->mfc_parent].dev->ifindex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619
Jianjun Kongc354e122008-11-03 00:28:02 -08001620 mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621
1622 for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
Nicolas Dichtel74381892010-03-25 23:45:35 +00001623 if (VIF_EXISTS(net, ct) && c->mfc_un.res.ttls[ct] < 255) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4))
1625 goto rtattr_failure;
Jianjun Kongc354e122008-11-03 00:28:02 -08001626 nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 nhp->rtnh_flags = 0;
1628 nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001629 nhp->rtnh_ifindex = net->ipv4.vif_table[ct].dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 nhp->rtnh_len = sizeof(*nhp);
1631 }
1632 }
1633 mp_head->rta_type = RTA_MULTIPATH;
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001634 mp_head->rta_len = skb_tail_pointer(skb) - (u8 *)mp_head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 rtm->rtm_type = RTN_MULTICAST;
1636 return 1;
1637
1638rtattr_failure:
Arnaldo Carvalho de Melodc5fc572007-03-25 23:06:12 -07001639 nlmsg_trim(skb, b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 return -EMSGSIZE;
1641}
1642
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001643int ipmr_get_route(struct net *net,
1644 struct sk_buff *skb, struct rtmsg *rtm, int nowait)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645{
1646 int err;
1647 struct mfc_cache *cache;
Eric Dumazet511c3f92009-06-02 05:14:27 +00001648 struct rtable *rt = skb_rtable(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649
1650 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001651 cache = ipmr_cache_find(net, rt->rt_src, rt->rt_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652
Jianjun Kongc354e122008-11-03 00:28:02 -08001653 if (cache == NULL) {
Alexey Kuznetsov72287492006-07-25 16:45:12 -07001654 struct sk_buff *skb2;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001655 struct iphdr *iph;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656 struct net_device *dev;
1657 int vif;
1658
1659 if (nowait) {
1660 read_unlock(&mrt_lock);
1661 return -EAGAIN;
1662 }
1663
1664 dev = skb->dev;
1665 if (dev == NULL || (vif = ipmr_find_vif(dev)) < 0) {
1666 read_unlock(&mrt_lock);
1667 return -ENODEV;
1668 }
Alexey Kuznetsov72287492006-07-25 16:45:12 -07001669 skb2 = skb_clone(skb, GFP_ATOMIC);
1670 if (!skb2) {
1671 read_unlock(&mrt_lock);
1672 return -ENOMEM;
1673 }
1674
Arnaldo Carvalho de Meloe2d1bca2007-04-10 20:46:21 -07001675 skb_push(skb2, sizeof(struct iphdr));
1676 skb_reset_network_header(skb2);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001677 iph = ip_hdr(skb2);
1678 iph->ihl = sizeof(struct iphdr) >> 2;
1679 iph->saddr = rt->rt_src;
1680 iph->daddr = rt->rt_dst;
1681 iph->version = 0;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001682 err = ipmr_cache_unresolved(net, vif, skb2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 read_unlock(&mrt_lock);
1684 return err;
1685 }
1686
1687 if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY))
1688 cache->mfc_flags |= MFC_NOTIFY;
1689 err = ipmr_fill_mroute(skb, cache, rtm);
1690 read_unlock(&mrt_lock);
1691 return err;
1692}
1693
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001694#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695/*
1696 * The /proc interfaces to multicast routing /proc/ip_mr_cache /proc/ip_mr_vif
1697 */
1698struct ipmr_vif_iter {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001699 struct seq_net_private p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 int ct;
1701};
1702
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001703static struct vif_device *ipmr_vif_seq_idx(struct net *net,
1704 struct ipmr_vif_iter *iter,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 loff_t pos)
1706{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001707 for (iter->ct = 0; iter->ct < net->ipv4.maxvif; ++iter->ct) {
1708 if (!VIF_EXISTS(net, iter->ct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 continue;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001710 if (pos-- == 0)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001711 return &net->ipv4.vif_table[iter->ct];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 }
1713 return NULL;
1714}
1715
1716static void *ipmr_vif_seq_start(struct seq_file *seq, loff_t *pos)
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001717 __acquires(mrt_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001719 struct net *net = seq_file_net(seq);
1720
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 read_lock(&mrt_lock);
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001722 return *pos ? ipmr_vif_seq_idx(net, seq->private, *pos - 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 : SEQ_START_TOKEN;
1724}
1725
1726static void *ipmr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
1727{
1728 struct ipmr_vif_iter *iter = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001729 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730
1731 ++*pos;
1732 if (v == SEQ_START_TOKEN)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001733 return ipmr_vif_seq_idx(net, iter, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001734
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001735 while (++iter->ct < net->ipv4.maxvif) {
1736 if (!VIF_EXISTS(net, iter->ct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 continue;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001738 return &net->ipv4.vif_table[iter->ct];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 }
1740 return NULL;
1741}
1742
1743static void ipmr_vif_seq_stop(struct seq_file *seq, void *v)
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001744 __releases(mrt_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745{
1746 read_unlock(&mrt_lock);
1747}
1748
1749static int ipmr_vif_seq_show(struct seq_file *seq, void *v)
1750{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001751 struct net *net = seq_file_net(seq);
1752
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 if (v == SEQ_START_TOKEN) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001754 seq_puts(seq,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 "Interface BytesIn PktsIn BytesOut PktsOut Flags Local Remote\n");
1756 } else {
1757 const struct vif_device *vif = v;
1758 const char *name = vif->dev ? vif->dev->name : "none";
1759
1760 seq_printf(seq,
1761 "%2Zd %-10s %8ld %7ld %8ld %7ld %05X %08X %08X\n",
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001762 vif - net->ipv4.vif_table,
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001763 name, vif->bytes_in, vif->pkt_in,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 vif->bytes_out, vif->pkt_out,
1765 vif->flags, vif->local, vif->remote);
1766 }
1767 return 0;
1768}
1769
Stephen Hemmingerf6908082007-03-12 14:34:29 -07001770static const struct seq_operations ipmr_vif_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 .start = ipmr_vif_seq_start,
1772 .next = ipmr_vif_seq_next,
1773 .stop = ipmr_vif_seq_stop,
1774 .show = ipmr_vif_seq_show,
1775};
1776
1777static int ipmr_vif_open(struct inode *inode, struct file *file)
1778{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001779 return seq_open_net(inode, file, &ipmr_vif_seq_ops,
1780 sizeof(struct ipmr_vif_iter));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781}
1782
Arjan van de Ven9a321442007-02-12 00:55:35 -08001783static const struct file_operations ipmr_vif_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 .owner = THIS_MODULE,
1785 .open = ipmr_vif_open,
1786 .read = seq_read,
1787 .llseek = seq_lseek,
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001788 .release = seq_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789};
1790
1791struct ipmr_mfc_iter {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001792 struct seq_net_private p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 struct mfc_cache **cache;
1794 int ct;
1795};
1796
1797
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001798static struct mfc_cache *ipmr_mfc_seq_idx(struct net *net,
1799 struct ipmr_mfc_iter *it, loff_t pos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800{
1801 struct mfc_cache *mfc;
1802
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001803 it->cache = net->ipv4.mfc_cache_array;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 read_lock(&mrt_lock);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001805 for (it->ct = 0; it->ct < MFC_LINES; it->ct++)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001806 for (mfc = net->ipv4.mfc_cache_array[it->ct];
Benjamin Thery2bb8b262009-01-22 04:56:18 +00001807 mfc; mfc = mfc->next)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001808 if (pos-- == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 return mfc;
1810 read_unlock(&mrt_lock);
1811
Patrick McHardye258beb2010-04-13 05:03:19 +00001812 it->cache = &net->ipv4.mfc_unres_queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 spin_lock_bh(&mfc_unres_lock);
Patrick McHardye258beb2010-04-13 05:03:19 +00001814 for (mfc = net->ipv4.mfc_unres_queue; mfc; mfc = mfc->next)
1815 if (pos-- == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 return mfc;
1817 spin_unlock_bh(&mfc_unres_lock);
1818
1819 it->cache = NULL;
1820 return NULL;
1821}
1822
1823
1824static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
1825{
1826 struct ipmr_mfc_iter *it = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001827 struct net *net = seq_file_net(seq);
1828
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 it->cache = NULL;
1830 it->ct = 0;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001831 return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 : SEQ_START_TOKEN;
1833}
1834
1835static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
1836{
1837 struct mfc_cache *mfc = v;
1838 struct ipmr_mfc_iter *it = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001839 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840
1841 ++*pos;
1842
1843 if (v == SEQ_START_TOKEN)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001844 return ipmr_mfc_seq_idx(net, seq->private, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845
1846 if (mfc->next)
1847 return mfc->next;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001848
Patrick McHardye258beb2010-04-13 05:03:19 +00001849 if (it->cache == &net->ipv4.mfc_unres_queue)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 goto end_of_list;
1851
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001852 BUG_ON(it->cache != net->ipv4.mfc_cache_array);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853
1854 while (++it->ct < MFC_LINES) {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001855 mfc = net->ipv4.mfc_cache_array[it->ct];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 if (mfc)
1857 return mfc;
1858 }
1859
1860 /* exhausted cache_array, show unresolved */
1861 read_unlock(&mrt_lock);
Patrick McHardye258beb2010-04-13 05:03:19 +00001862 it->cache = &net->ipv4.mfc_unres_queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 it->ct = 0;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001864
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 spin_lock_bh(&mfc_unres_lock);
Patrick McHardye258beb2010-04-13 05:03:19 +00001866 mfc = net->ipv4.mfc_unres_queue;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001867 if (mfc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868 return mfc;
1869
1870 end_of_list:
1871 spin_unlock_bh(&mfc_unres_lock);
1872 it->cache = NULL;
1873
1874 return NULL;
1875}
1876
1877static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
1878{
1879 struct ipmr_mfc_iter *it = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001880 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881
Patrick McHardye258beb2010-04-13 05:03:19 +00001882 if (it->cache == &net->ipv4.mfc_unres_queue)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001883 spin_unlock_bh(&mfc_unres_lock);
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001884 else if (it->cache == net->ipv4.mfc_cache_array)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 read_unlock(&mrt_lock);
1886}
1887
1888static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
1889{
1890 int n;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001891 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892
1893 if (v == SEQ_START_TOKEN) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001894 seq_puts(seq,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 "Group Origin Iif Pkts Bytes Wrong Oifs\n");
1896 } else {
1897 const struct mfc_cache *mfc = v;
1898 const struct ipmr_mfc_iter *it = seq->private;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001899
Benjamin Thery999890b2008-12-03 22:22:16 -08001900 seq_printf(seq, "%08lX %08lX %-3hd",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 (unsigned long) mfc->mfc_mcastgrp,
1902 (unsigned long) mfc->mfc_origin,
Benjamin Thery1ea472e2008-12-03 22:21:47 -08001903 mfc->mfc_parent);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904
Patrick McHardye258beb2010-04-13 05:03:19 +00001905 if (it->cache != &net->ipv4.mfc_unres_queue) {
Benjamin Thery1ea472e2008-12-03 22:21:47 -08001906 seq_printf(seq, " %8lu %8lu %8lu",
1907 mfc->mfc_un.res.pkt,
1908 mfc->mfc_un.res.bytes,
1909 mfc->mfc_un.res.wrong_if);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001910 for (n = mfc->mfc_un.res.minvif;
1911 n < mfc->mfc_un.res.maxvif; n++ ) {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001912 if (VIF_EXISTS(net, n) &&
Benjamin Therycf958ae32009-01-22 04:56:16 +00001913 mfc->mfc_un.res.ttls[n] < 255)
1914 seq_printf(seq,
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001915 " %2d:%-3d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916 n, mfc->mfc_un.res.ttls[n]);
1917 }
Benjamin Thery1ea472e2008-12-03 22:21:47 -08001918 } else {
1919 /* unresolved mfc_caches don't contain
1920 * pkt, bytes and wrong_if values
1921 */
1922 seq_printf(seq, " %8lu %8lu %8lu", 0ul, 0ul, 0ul);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 }
1924 seq_putc(seq, '\n');
1925 }
1926 return 0;
1927}
1928
Stephen Hemmingerf6908082007-03-12 14:34:29 -07001929static const struct seq_operations ipmr_mfc_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930 .start = ipmr_mfc_seq_start,
1931 .next = ipmr_mfc_seq_next,
1932 .stop = ipmr_mfc_seq_stop,
1933 .show = ipmr_mfc_seq_show,
1934};
1935
1936static int ipmr_mfc_open(struct inode *inode, struct file *file)
1937{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001938 return seq_open_net(inode, file, &ipmr_mfc_seq_ops,
1939 sizeof(struct ipmr_mfc_iter));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940}
1941
Arjan van de Ven9a321442007-02-12 00:55:35 -08001942static const struct file_operations ipmr_mfc_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 .owner = THIS_MODULE,
1944 .open = ipmr_mfc_open,
1945 .read = seq_read,
1946 .llseek = seq_lseek,
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001947 .release = seq_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948};
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001949#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950
1951#ifdef CONFIG_IP_PIMSM_V2
Alexey Dobriyan32613092009-09-14 12:21:47 +00001952static const struct net_protocol pim_protocol = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 .handler = pim_rcv,
Tom Goff403dbb92009-06-14 03:16:13 -07001954 .netns_ok = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955};
1956#endif
1957
1958
1959/*
1960 * Setup for IP multicast routing
1961 */
Benjamin Therycf958ae32009-01-22 04:56:16 +00001962static int __net_init ipmr_net_init(struct net *net)
1963{
1964 int err = 0;
1965
1966 net->ipv4.vif_table = kcalloc(MAXVIFS, sizeof(struct vif_device),
1967 GFP_KERNEL);
1968 if (!net->ipv4.vif_table) {
1969 err = -ENOMEM;
1970 goto fail;
1971 }
Benjamin Thery2bb8b262009-01-22 04:56:18 +00001972
1973 /* Forwarding cache */
1974 net->ipv4.mfc_cache_array = kcalloc(MFC_LINES,
1975 sizeof(struct mfc_cache *),
1976 GFP_KERNEL);
1977 if (!net->ipv4.mfc_cache_array) {
1978 err = -ENOMEM;
1979 goto fail_mfc_cache;
1980 }
Benjamin Thery6c5143d2009-01-22 04:56:21 +00001981
Patrick McHardye258beb2010-04-13 05:03:19 +00001982 setup_timer(&net->ipv4.ipmr_expire_timer, ipmr_expire_process,
1983 (unsigned long)net);
1984
Benjamin Thery6c5143d2009-01-22 04:56:21 +00001985#ifdef CONFIG_IP_PIMSM
1986 net->ipv4.mroute_reg_vif_num = -1;
1987#endif
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001988
1989#ifdef CONFIG_PROC_FS
1990 err = -ENOMEM;
1991 if (!proc_net_fops_create(net, "ip_mr_vif", 0, &ipmr_vif_fops))
1992 goto proc_vif_fail;
1993 if (!proc_net_fops_create(net, "ip_mr_cache", 0, &ipmr_mfc_fops))
1994 goto proc_cache_fail;
1995#endif
Benjamin Thery2bb8b262009-01-22 04:56:18 +00001996 return 0;
1997
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001998#ifdef CONFIG_PROC_FS
1999proc_cache_fail:
2000 proc_net_remove(net, "ip_mr_vif");
2001proc_vif_fail:
2002 kfree(net->ipv4.mfc_cache_array);
2003#endif
Benjamin Thery2bb8b262009-01-22 04:56:18 +00002004fail_mfc_cache:
2005 kfree(net->ipv4.vif_table);
Benjamin Therycf958ae32009-01-22 04:56:16 +00002006fail:
2007 return err;
2008}
2009
2010static void __net_exit ipmr_net_exit(struct net *net)
2011{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002012#ifdef CONFIG_PROC_FS
2013 proc_net_remove(net, "ip_mr_cache");
2014 proc_net_remove(net, "ip_mr_vif");
2015#endif
Benjamin Thery2bb8b262009-01-22 04:56:18 +00002016 kfree(net->ipv4.mfc_cache_array);
Benjamin Therycf958ae32009-01-22 04:56:16 +00002017 kfree(net->ipv4.vif_table);
2018}
2019
2020static struct pernet_operations ipmr_net_ops = {
2021 .init = ipmr_net_init,
2022 .exit = ipmr_net_exit,
2023};
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002024
Wang Chen03d2f892008-07-03 12:13:36 +08002025int __init ip_mr_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026{
Wang Chen03d2f892008-07-03 12:13:36 +08002027 int err;
2028
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 mrt_cachep = kmem_cache_create("ip_mrt_cache",
2030 sizeof(struct mfc_cache),
Alexey Dobriyane5d679f332006-08-26 19:25:52 -07002031 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
Paul Mundt20c2df82007-07-20 10:11:58 +09002032 NULL);
Wang Chen03d2f892008-07-03 12:13:36 +08002033 if (!mrt_cachep)
2034 return -ENOMEM;
2035
Benjamin Therycf958ae32009-01-22 04:56:16 +00002036 err = register_pernet_subsys(&ipmr_net_ops);
2037 if (err)
2038 goto reg_pernet_fail;
2039
Wang Chen03d2f892008-07-03 12:13:36 +08002040 err = register_netdevice_notifier(&ip_mr_notifier);
2041 if (err)
2042 goto reg_notif_fail;
Tom Goff403dbb92009-06-14 03:16:13 -07002043#ifdef CONFIG_IP_PIMSM_V2
2044 if (inet_add_protocol(&pim_protocol, IPPROTO_PIM) < 0) {
2045 printk(KERN_ERR "ip_mr_init: can't add PIM protocol\n");
2046 err = -EAGAIN;
2047 goto add_proto_fail;
2048 }
2049#endif
Wang Chen03d2f892008-07-03 12:13:36 +08002050 return 0;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002051
Tom Goff403dbb92009-06-14 03:16:13 -07002052#ifdef CONFIG_IP_PIMSM_V2
2053add_proto_fail:
2054 unregister_netdevice_notifier(&ip_mr_notifier);
2055#endif
Benjamin Theryc3e38892008-11-19 14:07:41 -08002056reg_notif_fail:
Benjamin Therycf958ae32009-01-22 04:56:16 +00002057 unregister_pernet_subsys(&ipmr_net_ops);
2058reg_pernet_fail:
Benjamin Theryc3e38892008-11-19 14:07:41 -08002059 kmem_cache_destroy(mrt_cachep);
Wang Chen03d2f892008-07-03 12:13:36 +08002060 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061}