blob: 99508d66a64227fd532718486fa9eed924963e26 [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>
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020050#include <net/net_namespace.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#include <net/ip.h>
52#include <net/protocol.h>
53#include <linux/skbuff.h>
Arnaldo Carvalho de Melo14c85022005-12-27 02:43:12 -020054#include <net/route.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070055#include <net/sock.h>
56#include <net/icmp.h>
57#include <net/udp.h>
58#include <net/raw.h>
59#include <linux/notifier.h>
60#include <linux/if_arp.h>
61#include <linux/netfilter_ipv4.h>
62#include <net/ipip.h>
63#include <net/checksum.h>
Arnaldo Carvalho de Melodc5fc572007-03-25 23:06:12 -070064#include <net/netlink.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66#if defined(CONFIG_IP_PIMSM_V1) || defined(CONFIG_IP_PIMSM_V2)
67#define CONFIG_IP_PIMSM 1
68#endif
69
Linus Torvalds1da177e2005-04-16 15:20:36 -070070/* Big lock, protecting vif table, mrt cache and mroute socket state.
71 Note that the changes are semaphored via rtnl_lock.
72 */
73
74static DEFINE_RWLOCK(mrt_lock);
75
76/*
77 * Multicast router control variables
78 */
79
Benjamin Therycf958ae32009-01-22 04:56:16 +000080#define VIF_EXISTS(_net, _idx) ((_net)->ipv4.vif_table[_idx].dev != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
Linus Torvalds1da177e2005-04-16 15:20:36 -070082static struct mfc_cache *mfc_unres_queue; /* Queue of unresolved entries */
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
84/* Special spinlock for queue of unresolved entries */
85static DEFINE_SPINLOCK(mfc_unres_lock);
86
87/* We return to original Alan's scheme. Hash table of resolved
88 entries is changed only in process context and protected
89 with weak lock mrt_lock. Queue of unresolved entries is protected
90 with strong spinlock mfc_unres_lock.
91
92 In this case data path is free of exclusive locks at all.
93 */
94
Christoph Lametere18b8902006-12-06 20:33:20 -080095static struct kmem_cache *mrt_cachep __read_mostly;
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
97static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local);
Benjamin Thery4feb88e2009-01-22 04:56:23 +000098static int ipmr_cache_report(struct net *net,
99 struct sk_buff *pkt, vifi_t vifi, int assert);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100static int ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm);
101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102static struct timer_list ipmr_expire_timer;
103
104/* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */
105
Wang Chend6070322008-07-14 20:55:26 -0700106static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v)
107{
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000108 struct net *net = dev_net(dev);
109
Wang Chend6070322008-07-14 20:55:26 -0700110 dev_close(dev);
111
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000112 dev = __dev_get_by_name(net, "tunl0");
Wang Chend6070322008-07-14 20:55:26 -0700113 if (dev) {
Stephen Hemminger5bc3eb72008-11-19 21:52:05 -0800114 const struct net_device_ops *ops = dev->netdev_ops;
Wang Chend6070322008-07-14 20:55:26 -0700115 struct ifreq ifr;
Wang Chend6070322008-07-14 20:55:26 -0700116 struct ip_tunnel_parm p;
117
118 memset(&p, 0, sizeof(p));
119 p.iph.daddr = v->vifc_rmt_addr.s_addr;
120 p.iph.saddr = v->vifc_lcl_addr.s_addr;
121 p.iph.version = 4;
122 p.iph.ihl = 5;
123 p.iph.protocol = IPPROTO_IPIP;
124 sprintf(p.name, "dvmrp%d", v->vifc_vifi);
125 ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
126
Stephen Hemminger5bc3eb72008-11-19 21:52:05 -0800127 if (ops->ndo_do_ioctl) {
128 mm_segment_t oldfs = get_fs();
129
130 set_fs(KERNEL_DS);
131 ops->ndo_do_ioctl(dev, &ifr, SIOCDELTUNNEL);
132 set_fs(oldfs);
133 }
Wang Chend6070322008-07-14 20:55:26 -0700134 }
135}
136
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137static
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000138struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139{
140 struct net_device *dev;
141
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000142 dev = __dev_get_by_name(net, "tunl0");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144 if (dev) {
Stephen Hemminger5bc3eb72008-11-19 21:52:05 -0800145 const struct net_device_ops *ops = dev->netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 int err;
147 struct ifreq ifr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 struct ip_tunnel_parm p;
149 struct in_device *in_dev;
150
151 memset(&p, 0, sizeof(p));
152 p.iph.daddr = v->vifc_rmt_addr.s_addr;
153 p.iph.saddr = v->vifc_lcl_addr.s_addr;
154 p.iph.version = 4;
155 p.iph.ihl = 5;
156 p.iph.protocol = IPPROTO_IPIP;
157 sprintf(p.name, "dvmrp%d", v->vifc_vifi);
Stephen Hemmingerba93ef72008-01-21 17:28:59 -0800158 ifr.ifr_ifru.ifru_data = (__force void __user *)&p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159
Stephen Hemminger5bc3eb72008-11-19 21:52:05 -0800160 if (ops->ndo_do_ioctl) {
161 mm_segment_t oldfs = get_fs();
162
163 set_fs(KERNEL_DS);
164 err = ops->ndo_do_ioctl(dev, &ifr, SIOCADDTUNNEL);
165 set_fs(oldfs);
166 } else
167 err = -EOPNOTSUPP;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
169 dev = NULL;
170
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000171 if (err == 0 &&
172 (dev = __dev_get_by_name(net, p.name)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 dev->flags |= IFF_MULTICAST;
174
Herbert Xue5ed6392005-10-03 14:35:55 -0700175 in_dev = __in_dev_get_rtnl(dev);
Herbert Xu71e27da2007-06-04 23:36:06 -0700176 if (in_dev == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 goto failure;
Herbert Xu71e27da2007-06-04 23:36:06 -0700178
179 ipv4_devconf_setall(in_dev);
180 IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
182 if (dev_open(dev))
183 goto failure;
Wang Chen7dc00c82008-07-14 20:56:34 -0700184 dev_hold(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 }
186 }
187 return dev;
188
189failure:
190 /* allow the register to be completed before unregistering. */
191 rtnl_unlock();
192 rtnl_lock();
193
194 unregister_netdevice(dev);
195 return NULL;
196}
197
198#ifdef CONFIG_IP_PIMSM
199
Stephen Hemminger6fef4c02009-08-31 19:50:41 +0000200static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, struct net_device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201{
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000202 struct net *net = dev_net(dev);
203
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 read_lock(&mrt_lock);
Pavel Emelyanovcf3677a2008-05-21 14:17:33 -0700205 dev->stats.tx_bytes += skb->len;
206 dev->stats.tx_packets++;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000207 ipmr_cache_report(net, skb, net->ipv4.mroute_reg_vif_num,
208 IGMPMSG_WHOLEPKT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 read_unlock(&mrt_lock);
210 kfree_skb(skb);
Patrick McHardy6ed10652009-06-23 06:03:08 +0000211 return NETDEV_TX_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212}
213
Stephen Hemminger007c3832008-11-20 20:28:35 -0800214static const struct net_device_ops reg_vif_netdev_ops = {
215 .ndo_start_xmit = reg_vif_xmit,
216};
217
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218static void reg_vif_setup(struct net_device *dev)
219{
220 dev->type = ARPHRD_PIMREG;
Kris Katterjohn46f25df2006-01-05 16:35:42 -0800221 dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 dev->flags = IFF_NOARP;
Stephen Hemminger007c3832008-11-20 20:28:35 -0800223 dev->netdev_ops = &reg_vif_netdev_ops,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 dev->destructor = free_netdev;
Tom Goff403dbb92009-06-14 03:16:13 -0700225 dev->features |= NETIF_F_NETNS_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226}
227
Tom Goff403dbb92009-06-14 03:16:13 -0700228static struct net_device *ipmr_reg_vif(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229{
230 struct net_device *dev;
231 struct in_device *in_dev;
232
Pavel Emelyanovcf3677a2008-05-21 14:17:33 -0700233 dev = alloc_netdev(0, "pimreg", reg_vif_setup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
235 if (dev == NULL)
236 return NULL;
237
Tom Goff403dbb92009-06-14 03:16:13 -0700238 dev_net_set(dev, net);
239
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 if (register_netdevice(dev)) {
241 free_netdev(dev);
242 return NULL;
243 }
244 dev->iflink = 0;
245
Herbert Xu71e27da2007-06-04 23:36:06 -0700246 rcu_read_lock();
247 if ((in_dev = __in_dev_get_rcu(dev)) == NULL) {
248 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 goto failure;
Herbert Xu71e27da2007-06-04 23:36:06 -0700250 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251
Herbert Xu71e27da2007-06-04 23:36:06 -0700252 ipv4_devconf_setall(in_dev);
253 IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0;
254 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
256 if (dev_open(dev))
257 goto failure;
258
Wang Chen7dc00c82008-07-14 20:56:34 -0700259 dev_hold(dev);
260
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 return dev;
262
263failure:
264 /* allow the register to be completed before unregistering. */
265 rtnl_unlock();
266 rtnl_lock();
267
268 unregister_netdevice(dev);
269 return NULL;
270}
271#endif
272
273/*
274 * Delete a VIF entry
Wang Chen7dc00c82008-07-14 20:56:34 -0700275 * @notify: Set to 1, if the caller is a notifier_call
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900277
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000278static int vif_delete(struct net *net, int vifi, int notify)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279{
280 struct vif_device *v;
281 struct net_device *dev;
282 struct in_device *in_dev;
283
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000284 if (vifi < 0 || vifi >= net->ipv4.maxvif)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 return -EADDRNOTAVAIL;
286
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000287 v = &net->ipv4.vif_table[vifi];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
289 write_lock_bh(&mrt_lock);
290 dev = v->dev;
291 v->dev = NULL;
292
293 if (!dev) {
294 write_unlock_bh(&mrt_lock);
295 return -EADDRNOTAVAIL;
296 }
297
298#ifdef CONFIG_IP_PIMSM
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000299 if (vifi == net->ipv4.mroute_reg_vif_num)
300 net->ipv4.mroute_reg_vif_num = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301#endif
302
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000303 if (vifi+1 == net->ipv4.maxvif) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 int tmp;
305 for (tmp=vifi-1; tmp>=0; tmp--) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000306 if (VIF_EXISTS(net, tmp))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 break;
308 }
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000309 net->ipv4.maxvif = tmp+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 }
311
312 write_unlock_bh(&mrt_lock);
313
314 dev_set_allmulti(dev, -1);
315
Herbert Xue5ed6392005-10-03 14:35:55 -0700316 if ((in_dev = __in_dev_get_rtnl(dev)) != NULL) {
Herbert Xu42f811b2007-06-04 23:34:44 -0700317 IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 ip_rt_multicast_event(in_dev);
319 }
320
Wang Chen7dc00c82008-07-14 20:56:34 -0700321 if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER) && !notify)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 unregister_netdevice(dev);
323
324 dev_put(dev);
325 return 0;
326}
327
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000328static inline void ipmr_cache_free(struct mfc_cache *c)
329{
330 release_net(mfc_net(c));
331 kmem_cache_free(mrt_cachep, c);
332}
333
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334/* Destroy an unresolved cache entry, killing queued skbs
335 and reporting error to netlink readers.
336 */
337
338static void ipmr_destroy_unres(struct mfc_cache *c)
339{
340 struct sk_buff *skb;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -0700341 struct nlmsgerr *e;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000342 struct net *net = mfc_net(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000344 atomic_dec(&net->ipv4.cache_resolve_queue_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
Jianjun Kongc354e122008-11-03 00:28:02 -0800346 while ((skb = skb_dequeue(&c->mfc_un.unres.unresolved))) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700347 if (ip_hdr(skb)->version == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
349 nlh->nlmsg_type = NLMSG_ERROR;
350 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
351 skb_trim(skb, nlh->nlmsg_len);
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -0700352 e = NLMSG_DATA(nlh);
353 e->error = -ETIMEDOUT;
354 memset(&e->msg, 0, sizeof(e->msg));
Thomas Graf2942e902006-08-15 00:30:25 -0700355
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000356 rtnl_unicast(skb, net, NETLINK_CB(skb).pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 } else
358 kfree_skb(skb);
359 }
360
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000361 ipmr_cache_free(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362}
363
364
365/* Single timer process for all the unresolved queue. */
366
367static void ipmr_expire_process(unsigned long dummy)
368{
369 unsigned long now;
370 unsigned long expires;
371 struct mfc_cache *c, **cp;
372
373 if (!spin_trylock(&mfc_unres_lock)) {
374 mod_timer(&ipmr_expire_timer, jiffies+HZ/10);
375 return;
376 }
377
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000378 if (mfc_unres_queue == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 goto out;
380
381 now = jiffies;
382 expires = 10*HZ;
383 cp = &mfc_unres_queue;
384
385 while ((c=*cp) != NULL) {
386 if (time_after(c->mfc_un.unres.expires, now)) {
387 unsigned long interval = c->mfc_un.unres.expires - now;
388 if (interval < expires)
389 expires = interval;
390 cp = &c->next;
391 continue;
392 }
393
394 *cp = c->next;
395
396 ipmr_destroy_unres(c);
397 }
398
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000399 if (mfc_unres_queue != NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 mod_timer(&ipmr_expire_timer, jiffies + expires);
401
402out:
403 spin_unlock(&mfc_unres_lock);
404}
405
406/* Fill oifs list. It is called under write locked mrt_lock. */
407
Baruch Evend1b04c02005-07-30 17:41:59 -0700408static void ipmr_update_thresholds(struct mfc_cache *cache, unsigned char *ttls)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409{
410 int vifi;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000411 struct net *net = mfc_net(cache);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412
413 cache->mfc_un.res.minvif = MAXVIFS;
414 cache->mfc_un.res.maxvif = 0;
415 memset(cache->mfc_un.res.ttls, 255, MAXVIFS);
416
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000417 for (vifi = 0; vifi < net->ipv4.maxvif; vifi++) {
418 if (VIF_EXISTS(net, vifi) &&
Benjamin Therycf958ae32009-01-22 04:56:16 +0000419 ttls[vifi] && ttls[vifi] < 255) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 cache->mfc_un.res.ttls[vifi] = ttls[vifi];
421 if (cache->mfc_un.res.minvif > vifi)
422 cache->mfc_un.res.minvif = vifi;
423 if (cache->mfc_un.res.maxvif <= vifi)
424 cache->mfc_un.res.maxvif = vifi + 1;
425 }
426 }
427}
428
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000429static int vif_add(struct net *net, struct vifctl *vifc, int mrtsock)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430{
431 int vifi = vifc->vifc_vifi;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000432 struct vif_device *v = &net->ipv4.vif_table[vifi];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 struct net_device *dev;
434 struct in_device *in_dev;
Wang Chend6070322008-07-14 20:55:26 -0700435 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
437 /* Is vif busy ? */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000438 if (VIF_EXISTS(net, vifi))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 return -EADDRINUSE;
440
441 switch (vifc->vifc_flags) {
442#ifdef CONFIG_IP_PIMSM
443 case VIFF_REGISTER:
444 /*
445 * Special Purpose VIF in PIM
446 * All the packets will be sent to the daemon
447 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000448 if (net->ipv4.mroute_reg_vif_num >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 return -EADDRINUSE;
Tom Goff403dbb92009-06-14 03:16:13 -0700450 dev = ipmr_reg_vif(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 if (!dev)
452 return -ENOBUFS;
Wang Chend6070322008-07-14 20:55:26 -0700453 err = dev_set_allmulti(dev, 1);
454 if (err) {
455 unregister_netdevice(dev);
Wang Chen7dc00c82008-07-14 20:56:34 -0700456 dev_put(dev);
Wang Chend6070322008-07-14 20:55:26 -0700457 return err;
458 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 break;
460#endif
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900461 case VIFF_TUNNEL:
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000462 dev = ipmr_new_tunnel(net, vifc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 if (!dev)
464 return -ENOBUFS;
Wang Chend6070322008-07-14 20:55:26 -0700465 err = dev_set_allmulti(dev, 1);
466 if (err) {
467 ipmr_del_tunnel(dev, vifc);
Wang Chen7dc00c82008-07-14 20:56:34 -0700468 dev_put(dev);
Wang Chend6070322008-07-14 20:55:26 -0700469 return err;
470 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 break;
472 case 0:
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000473 dev = ip_dev_find(net, vifc->vifc_lcl_addr.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 if (!dev)
475 return -EADDRNOTAVAIL;
Wang Chend6070322008-07-14 20:55:26 -0700476 err = dev_set_allmulti(dev, 1);
Wang Chen7dc00c82008-07-14 20:56:34 -0700477 if (err) {
478 dev_put(dev);
Wang Chend6070322008-07-14 20:55:26 -0700479 return err;
Wang Chen7dc00c82008-07-14 20:56:34 -0700480 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 break;
482 default:
483 return -EINVAL;
484 }
485
Dan Carpenterd0490cf2009-11-11 02:03:54 +0000486 if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) {
487 dev_put(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 return -EADDRNOTAVAIL;
Dan Carpenterd0490cf2009-11-11 02:03:54 +0000489 }
Herbert Xu42f811b2007-06-04 23:34:44 -0700490 IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 ip_rt_multicast_event(in_dev);
492
493 /*
494 * Fill in the VIF structures
495 */
Jianjun Kongc354e122008-11-03 00:28:02 -0800496 v->rate_limit = vifc->vifc_rate_limit;
497 v->local = vifc->vifc_lcl_addr.s_addr;
498 v->remote = vifc->vifc_rmt_addr.s_addr;
499 v->flags = vifc->vifc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 if (!mrtsock)
501 v->flags |= VIFF_STATIC;
Jianjun Kongc354e122008-11-03 00:28:02 -0800502 v->threshold = vifc->vifc_threshold;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 v->bytes_in = 0;
504 v->bytes_out = 0;
505 v->pkt_in = 0;
506 v->pkt_out = 0;
507 v->link = dev->ifindex;
508 if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER))
509 v->link = dev->iflink;
510
511 /* And finish update writing critical data */
512 write_lock_bh(&mrt_lock);
Jianjun Kongc354e122008-11-03 00:28:02 -0800513 v->dev = dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514#ifdef CONFIG_IP_PIMSM
515 if (v->flags&VIFF_REGISTER)
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000516 net->ipv4.mroute_reg_vif_num = vifi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517#endif
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000518 if (vifi+1 > net->ipv4.maxvif)
519 net->ipv4.maxvif = vifi+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 write_unlock_bh(&mrt_lock);
521 return 0;
522}
523
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000524static struct mfc_cache *ipmr_cache_find(struct net *net,
525 __be32 origin,
526 __be32 mcastgrp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527{
Jianjun Kongc354e122008-11-03 00:28:02 -0800528 int line = MFC_HASH(mcastgrp, origin);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 struct mfc_cache *c;
530
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000531 for (c = net->ipv4.mfc_cache_array[line]; c; c = c->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 if (c->mfc_origin==origin && c->mfc_mcastgrp==mcastgrp)
533 break;
534 }
535 return c;
536}
537
538/*
539 * Allocate a multicast cache entry
540 */
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000541static struct mfc_cache *ipmr_cache_alloc(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542{
Jianjun Kongc354e122008-11-03 00:28:02 -0800543 struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL);
544 if (c == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 c->mfc_un.res.minvif = MAXVIFS;
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000547 mfc_net_set(c, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 return c;
549}
550
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000551static struct mfc_cache *ipmr_cache_alloc_unres(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552{
Jianjun Kongc354e122008-11-03 00:28:02 -0800553 struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC);
554 if (c == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 skb_queue_head_init(&c->mfc_un.unres.unresolved);
557 c->mfc_un.unres.expires = jiffies + 10*HZ;
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000558 mfc_net_set(c, net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 return c;
560}
561
562/*
563 * A cache entry has gone into a resolved state from queued
564 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900565
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c)
567{
568 struct sk_buff *skb;
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -0700569 struct nlmsgerr *e;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
571 /*
572 * Play the pending entries through our router
573 */
574
Jianjun Kongc354e122008-11-03 00:28:02 -0800575 while ((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700576 if (ip_hdr(skb)->version == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr));
578
579 if (ipmr_fill_mroute(skb, c, NLMSG_DATA(nlh)) > 0) {
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700580 nlh->nlmsg_len = (skb_tail_pointer(skb) -
581 (u8 *)nlh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 } else {
583 nlh->nlmsg_type = NLMSG_ERROR;
584 nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
585 skb_trim(skb, nlh->nlmsg_len);
Patrick McHardy9ef1d4c2005-06-28 12:55:30 -0700586 e = NLMSG_DATA(nlh);
587 e->error = -EMSGSIZE;
588 memset(&e->msg, 0, sizeof(e->msg));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 }
Thomas Graf2942e902006-08-15 00:30:25 -0700590
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000591 rtnl_unicast(skb, mfc_net(c), NETLINK_CB(skb).pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 } else
593 ip_mr_forward(skb, c, 0);
594 }
595}
596
597/*
598 * Bounce a cache query up to mrouted. We could use netlink for this but mrouted
599 * expects the following bizarre scheme.
600 *
601 * Called under mrt_lock.
602 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900603
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000604static int ipmr_cache_report(struct net *net,
605 struct sk_buff *pkt, vifi_t vifi, int assert)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606{
607 struct sk_buff *skb;
Arnaldo Carvalho de Meloc9bdd4b2007-03-12 20:09:15 -0300608 const int ihl = ip_hdrlen(pkt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 struct igmphdr *igmp;
610 struct igmpmsg *msg;
611 int ret;
612
613#ifdef CONFIG_IP_PIMSM
614 if (assert == IGMPMSG_WHOLEPKT)
615 skb = skb_realloc_headroom(pkt, sizeof(struct iphdr));
616 else
617#endif
618 skb = alloc_skb(128, GFP_ATOMIC);
619
Stephen Hemminger132adf52007-03-08 20:44:43 -0800620 if (!skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 return -ENOBUFS;
622
623#ifdef CONFIG_IP_PIMSM
624 if (assert == IGMPMSG_WHOLEPKT) {
625 /* Ugly, but we have no choice with this interface.
626 Duplicate old header, fix ihl, length etc.
627 And all this only to mangle msg->im_msgtype and
628 to set msg->im_mbz to "mbz" :-)
629 */
Arnaldo Carvalho de Melo878c8142007-03-11 22:38:29 -0300630 skb_push(skb, sizeof(struct iphdr));
631 skb_reset_network_header(skb);
Arnaldo Carvalho de Melobadff6d2007-03-13 13:06:52 -0300632 skb_reset_transport_header(skb);
Arnaldo Carvalho de Melo0272ffc2007-03-12 20:05:39 -0300633 msg = (struct igmpmsg *)skb_network_header(skb);
Arnaldo Carvalho de Melod56f90a2007-04-10 20:50:43 -0700634 memcpy(msg, skb_network_header(pkt), sizeof(struct iphdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 msg->im_msgtype = IGMPMSG_WHOLEPKT;
636 msg->im_mbz = 0;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000637 msg->im_vif = net->ipv4.mroute_reg_vif_num;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700638 ip_hdr(skb)->ihl = sizeof(struct iphdr) >> 2;
639 ip_hdr(skb)->tot_len = htons(ntohs(ip_hdr(pkt)->tot_len) +
640 sizeof(struct iphdr));
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900641 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642#endif
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900643 {
644
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 /*
646 * Copy the IP header
647 */
648
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -0700649 skb->network_header = skb->tail;
Arnaldo Carvalho de Meloddc7b8e2007-03-15 21:42:27 -0300650 skb_put(skb, ihl);
Arnaldo Carvalho de Melo27d7ff42007-03-31 11:55:19 -0300651 skb_copy_to_linear_data(skb, pkt->data, ihl);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700652 ip_hdr(skb)->protocol = 0; /* Flag to the kernel this is a route add */
653 msg = (struct igmpmsg *)skb_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 msg->im_vif = vifi;
Eric Dumazetadf30902009-06-02 05:19:30 +0000655 skb_dst_set(skb, dst_clone(skb_dst(pkt)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
657 /*
658 * Add our header
659 */
660
Jianjun Kongc354e122008-11-03 00:28:02 -0800661 igmp=(struct igmphdr *)skb_put(skb, sizeof(struct igmphdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 igmp->type =
663 msg->im_msgtype = assert;
664 igmp->code = 0;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700665 ip_hdr(skb)->tot_len = htons(skb->len); /* Fix the length */
Arnaldo Carvalho de Melob0e380b2007-04-10 21:21:55 -0700666 skb->transport_header = skb->network_header;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900667 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000669 if (net->ipv4.mroute_sk == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 kfree_skb(skb);
671 return -EINVAL;
672 }
673
674 /*
675 * Deliver to mrouted
676 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000677 ret = sock_queue_rcv_skb(net->ipv4.mroute_sk, skb);
Benjamin Thery70a269e2009-01-22 04:56:15 +0000678 if (ret < 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 if (net_ratelimit())
680 printk(KERN_WARNING "mroute: pending queue full, dropping entries.\n");
681 kfree_skb(skb);
682 }
683
684 return ret;
685}
686
687/*
688 * Queue a packet for resolution. It gets locked cache entry!
689 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900690
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691static int
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000692ipmr_cache_unresolved(struct net *net, vifi_t vifi, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693{
694 int err;
695 struct mfc_cache *c;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700696 const struct iphdr *iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
698 spin_lock_bh(&mfc_unres_lock);
699 for (c=mfc_unres_queue; c; c=c->next) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000700 if (net_eq(mfc_net(c), net) &&
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000701 c->mfc_mcastgrp == iph->daddr &&
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700702 c->mfc_origin == iph->saddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 break;
704 }
705
706 if (c == NULL) {
707 /*
708 * Create a new entry if allowable
709 */
710
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000711 if (atomic_read(&net->ipv4.cache_resolve_queue_len) >= 10 ||
712 (c = ipmr_cache_alloc_unres(net)) == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 spin_unlock_bh(&mfc_unres_lock);
714
715 kfree_skb(skb);
716 return -ENOBUFS;
717 }
718
719 /*
720 * Fill in the new cache entry
721 */
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -0700722 c->mfc_parent = -1;
723 c->mfc_origin = iph->saddr;
724 c->mfc_mcastgrp = iph->daddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
726 /*
727 * Reflect first query at mrouted.
728 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000729 err = ipmr_cache_report(net, skb, vifi, IGMPMSG_NOCACHE);
730 if (err < 0) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900731 /* If the report failed throw the cache entry
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 out - Brad Parker
733 */
734 spin_unlock_bh(&mfc_unres_lock);
735
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000736 ipmr_cache_free(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 kfree_skb(skb);
738 return err;
739 }
740
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000741 atomic_inc(&net->ipv4.cache_resolve_queue_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 c->next = mfc_unres_queue;
743 mfc_unres_queue = c;
744
745 mod_timer(&ipmr_expire_timer, c->mfc_un.unres.expires);
746 }
747
748 /*
749 * See if we can append the packet
750 */
751 if (c->mfc_un.unres.unresolved.qlen>3) {
752 kfree_skb(skb);
753 err = -ENOBUFS;
754 } else {
Jianjun Kongc354e122008-11-03 00:28:02 -0800755 skb_queue_tail(&c->mfc_un.unres.unresolved, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 err = 0;
757 }
758
759 spin_unlock_bh(&mfc_unres_lock);
760 return err;
761}
762
763/*
764 * MFC cache manipulation by user space mroute daemon
765 */
766
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000767static int ipmr_mfc_delete(struct net *net, struct mfcctl *mfc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768{
769 int line;
770 struct mfc_cache *c, **cp;
771
Jianjun Kongc354e122008-11-03 00:28:02 -0800772 line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000774 for (cp = &net->ipv4.mfc_cache_array[line];
Benjamin Thery2bb8b262009-01-22 04:56:18 +0000775 (c = *cp) != NULL; cp = &c->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
777 c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr) {
778 write_lock_bh(&mrt_lock);
779 *cp = c->next;
780 write_unlock_bh(&mrt_lock);
781
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000782 ipmr_cache_free(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 return 0;
784 }
785 }
786 return -ENOENT;
787}
788
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000789static int ipmr_mfc_add(struct net *net, struct mfcctl *mfc, int mrtsock)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790{
791 int line;
792 struct mfc_cache *uc, *c, **cp;
793
Jianjun Kongc354e122008-11-03 00:28:02 -0800794 line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000796 for (cp = &net->ipv4.mfc_cache_array[line];
Benjamin Thery2bb8b262009-01-22 04:56:18 +0000797 (c = *cp) != NULL; cp = &c->next) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 if (c->mfc_origin == mfc->mfcc_origin.s_addr &&
799 c->mfc_mcastgrp == mfc->mfcc_mcastgrp.s_addr)
800 break;
801 }
802
803 if (c != NULL) {
804 write_lock_bh(&mrt_lock);
805 c->mfc_parent = mfc->mfcc_parent;
Baruch Evend1b04c02005-07-30 17:41:59 -0700806 ipmr_update_thresholds(c, mfc->mfcc_ttls);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 if (!mrtsock)
808 c->mfc_flags |= MFC_STATIC;
809 write_unlock_bh(&mrt_lock);
810 return 0;
811 }
812
Joe Perchesf97c1e02007-12-16 13:45:43 -0800813 if (!ipv4_is_multicast(mfc->mfcc_mcastgrp.s_addr))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 return -EINVAL;
815
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000816 c = ipmr_cache_alloc(net);
Jianjun Kongc354e122008-11-03 00:28:02 -0800817 if (c == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 return -ENOMEM;
819
Jianjun Kongc354e122008-11-03 00:28:02 -0800820 c->mfc_origin = mfc->mfcc_origin.s_addr;
821 c->mfc_mcastgrp = mfc->mfcc_mcastgrp.s_addr;
822 c->mfc_parent = mfc->mfcc_parent;
Baruch Evend1b04c02005-07-30 17:41:59 -0700823 ipmr_update_thresholds(c, mfc->mfcc_ttls);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 if (!mrtsock)
825 c->mfc_flags |= MFC_STATIC;
826
827 write_lock_bh(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000828 c->next = net->ipv4.mfc_cache_array[line];
829 net->ipv4.mfc_cache_array[line] = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 write_unlock_bh(&mrt_lock);
831
832 /*
833 * Check to see if we resolved a queued list. If so we
834 * need to send on the frames and tidy up.
835 */
836 spin_lock_bh(&mfc_unres_lock);
837 for (cp = &mfc_unres_queue; (uc=*cp) != NULL;
838 cp = &uc->next) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000839 if (net_eq(mfc_net(uc), net) &&
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000840 uc->mfc_origin == c->mfc_origin &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 uc->mfc_mcastgrp == c->mfc_mcastgrp) {
842 *cp = uc->next;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000843 atomic_dec(&net->ipv4.cache_resolve_queue_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 break;
845 }
846 }
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000847 if (mfc_unres_queue == NULL)
848 del_timer(&ipmr_expire_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 spin_unlock_bh(&mfc_unres_lock);
850
851 if (uc) {
852 ipmr_cache_resolve(uc, c);
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000853 ipmr_cache_free(uc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 }
855 return 0;
856}
857
858/*
859 * Close the multicast socket, and clear the vif tables etc
860 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900861
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000862static void mroute_clean_tables(struct net *net)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863{
864 int i;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900865
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 /*
867 * Shut down all active vif entries
868 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000869 for (i = 0; i < net->ipv4.maxvif; i++) {
870 if (!(net->ipv4.vif_table[i].flags&VIFF_STATIC))
871 vif_delete(net, i, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 }
873
874 /*
875 * Wipe the cache
876 */
Jianjun Kongc354e122008-11-03 00:28:02 -0800877 for (i=0; i<MFC_LINES; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 struct mfc_cache *c, **cp;
879
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000880 cp = &net->ipv4.mfc_cache_array[i];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 while ((c = *cp) != NULL) {
882 if (c->mfc_flags&MFC_STATIC) {
883 cp = &c->next;
884 continue;
885 }
886 write_lock_bh(&mrt_lock);
887 *cp = c->next;
888 write_unlock_bh(&mrt_lock);
889
Benjamin Thery5c0a66f2009-01-22 04:56:17 +0000890 ipmr_cache_free(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 }
892 }
893
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000894 if (atomic_read(&net->ipv4.cache_resolve_queue_len) != 0) {
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000895 struct mfc_cache *c, **cp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896
897 spin_lock_bh(&mfc_unres_lock);
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000898 cp = &mfc_unres_queue;
899 while ((c = *cp) != NULL) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000900 if (!net_eq(mfc_net(c), net)) {
Benjamin Thery1e8fb3b2009-01-22 04:56:19 +0000901 cp = &c->next;
902 continue;
903 }
904 *cp = c->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905
906 ipmr_destroy_unres(c);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 }
908 spin_unlock_bh(&mfc_unres_lock);
909 }
910}
911
912static void mrtsock_destruct(struct sock *sk)
913{
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000914 struct net *net = sock_net(sk);
915
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 rtnl_lock();
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000917 if (sk == net->ipv4.mroute_sk) {
918 IPV4_DEVCONF_ALL(net, MC_FORWARDING)--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919
920 write_lock_bh(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000921 net->ipv4.mroute_sk = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 write_unlock_bh(&mrt_lock);
923
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000924 mroute_clean_tables(net);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 }
926 rtnl_unlock();
927}
928
929/*
930 * Socket options and virtual interface manipulation. The whole
931 * virtual interface system is a complete heap, but unfortunately
932 * that's how BSD mrouted happens to think. Maybe one day with a proper
933 * MOSPF/PIM router set up we can clean this up.
934 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900935
David S. Millerb7058842009-09-30 16:12:20 -0700936int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937{
938 int ret;
939 struct vifctl vif;
940 struct mfcctl mfc;
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000941 struct net *net = sock_net(sk);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900942
Stephen Hemminger132adf52007-03-08 20:44:43 -0800943 if (optname != MRT_INIT) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000944 if (sk != net->ipv4.mroute_sk && !capable(CAP_NET_ADMIN))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 return -EACCES;
946 }
947
Stephen Hemminger132adf52007-03-08 20:44:43 -0800948 switch (optname) {
949 case MRT_INIT:
950 if (sk->sk_type != SOCK_RAW ||
951 inet_sk(sk)->num != IPPROTO_IGMP)
952 return -EOPNOTSUPP;
Jianjun Kongc354e122008-11-03 00:28:02 -0800953 if (optlen != sizeof(int))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800954 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955
Stephen Hemminger132adf52007-03-08 20:44:43 -0800956 rtnl_lock();
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000957 if (net->ipv4.mroute_sk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 rtnl_unlock();
Stephen Hemminger132adf52007-03-08 20:44:43 -0800959 return -EADDRINUSE;
960 }
961
962 ret = ip_ra_control(sk, 1, mrtsock_destruct);
963 if (ret == 0) {
964 write_lock_bh(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000965 net->ipv4.mroute_sk = sk;
Stephen Hemminger132adf52007-03-08 20:44:43 -0800966 write_unlock_bh(&mrt_lock);
967
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000968 IPV4_DEVCONF_ALL(net, MC_FORWARDING)++;
Stephen Hemminger132adf52007-03-08 20:44:43 -0800969 }
970 rtnl_unlock();
971 return ret;
972 case MRT_DONE:
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000973 if (sk != net->ipv4.mroute_sk)
Stephen Hemminger132adf52007-03-08 20:44:43 -0800974 return -EACCES;
975 return ip_ra_control(sk, 0, NULL);
976 case MRT_ADD_VIF:
977 case MRT_DEL_VIF:
Jianjun Kongc354e122008-11-03 00:28:02 -0800978 if (optlen != sizeof(vif))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800979 return -EINVAL;
Jianjun Kongc354e122008-11-03 00:28:02 -0800980 if (copy_from_user(&vif, optval, sizeof(vif)))
Stephen Hemminger132adf52007-03-08 20:44:43 -0800981 return -EFAULT;
982 if (vif.vifc_vifi >= MAXVIFS)
983 return -ENFILE;
984 rtnl_lock();
Jianjun Kongc354e122008-11-03 00:28:02 -0800985 if (optname == MRT_ADD_VIF) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000986 ret = vif_add(net, &vif, sk == net->ipv4.mroute_sk);
Stephen Hemminger132adf52007-03-08 20:44:43 -0800987 } else {
Benjamin Thery4feb88e2009-01-22 04:56:23 +0000988 ret = vif_delete(net, vif.vifc_vifi, 0);
Stephen Hemminger132adf52007-03-08 20:44:43 -0800989 }
990 rtnl_unlock();
991 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
993 /*
994 * Manipulate the forwarding caches. These live
995 * in a sort of kernel/user symbiosis.
996 */
Stephen Hemminger132adf52007-03-08 20:44:43 -0800997 case MRT_ADD_MFC:
998 case MRT_DEL_MFC:
Jianjun Kongc354e122008-11-03 00:28:02 -0800999 if (optlen != sizeof(mfc))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001000 return -EINVAL;
Jianjun Kongc354e122008-11-03 00:28:02 -08001001 if (copy_from_user(&mfc, optval, sizeof(mfc)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001002 return -EFAULT;
1003 rtnl_lock();
Jianjun Kongc354e122008-11-03 00:28:02 -08001004 if (optname == MRT_DEL_MFC)
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001005 ret = ipmr_mfc_delete(net, &mfc);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001006 else
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001007 ret = ipmr_mfc_add(net, &mfc, sk == net->ipv4.mroute_sk);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001008 rtnl_unlock();
1009 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 /*
1011 * Control PIM assert.
1012 */
Stephen Hemminger132adf52007-03-08 20:44:43 -08001013 case MRT_ASSERT:
1014 {
1015 int v;
1016 if (get_user(v,(int __user *)optval))
1017 return -EFAULT;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001018 net->ipv4.mroute_do_assert = (v) ? 1 : 0;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001019 return 0;
1020 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021#ifdef CONFIG_IP_PIMSM
Stephen Hemminger132adf52007-03-08 20:44:43 -08001022 case MRT_PIM:
1023 {
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001024 int v;
1025
Stephen Hemminger132adf52007-03-08 20:44:43 -08001026 if (get_user(v,(int __user *)optval))
1027 return -EFAULT;
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001028 v = (v) ? 1 : 0;
1029
Stephen Hemminger132adf52007-03-08 20:44:43 -08001030 rtnl_lock();
1031 ret = 0;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001032 if (v != net->ipv4.mroute_do_pim) {
1033 net->ipv4.mroute_do_pim = v;
1034 net->ipv4.mroute_do_assert = v;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 }
Stephen Hemminger132adf52007-03-08 20:44:43 -08001036 rtnl_unlock();
1037 return ret;
1038 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039#endif
Stephen Hemminger132adf52007-03-08 20:44:43 -08001040 /*
1041 * Spurious command, or MRT_VERSION which you cannot
1042 * set.
1043 */
1044 default:
1045 return -ENOPROTOOPT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 }
1047}
1048
1049/*
1050 * Getsock opt support for the multicast routing system.
1051 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001052
Jianjun Kongc354e122008-11-03 00:28:02 -08001053int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int __user *optlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054{
1055 int olr;
1056 int val;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001057 struct net *net = sock_net(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058
Jianjun Kongc354e122008-11-03 00:28:02 -08001059 if (optname != MRT_VERSION &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060#ifdef CONFIG_IP_PIMSM
1061 optname!=MRT_PIM &&
1062#endif
1063 optname!=MRT_ASSERT)
1064 return -ENOPROTOOPT;
1065
1066 if (get_user(olr, optlen))
1067 return -EFAULT;
1068
1069 olr = min_t(unsigned int, olr, sizeof(int));
1070 if (olr < 0)
1071 return -EINVAL;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001072
Jianjun Kongc354e122008-11-03 00:28:02 -08001073 if (put_user(olr, optlen))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 return -EFAULT;
Jianjun Kongc354e122008-11-03 00:28:02 -08001075 if (optname == MRT_VERSION)
1076 val = 0x0305;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077#ifdef CONFIG_IP_PIMSM
Jianjun Kongc354e122008-11-03 00:28:02 -08001078 else if (optname == MRT_PIM)
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001079 val = net->ipv4.mroute_do_pim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080#endif
1081 else
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001082 val = net->ipv4.mroute_do_assert;
Jianjun Kongc354e122008-11-03 00:28:02 -08001083 if (copy_to_user(optval, &val, olr))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 return -EFAULT;
1085 return 0;
1086}
1087
1088/*
1089 * The IP multicast ioctl support routines.
1090 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001091
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg)
1093{
1094 struct sioc_sg_req sr;
1095 struct sioc_vif_req vr;
1096 struct vif_device *vif;
1097 struct mfc_cache *c;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001098 struct net *net = sock_net(sk);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001099
Stephen Hemminger132adf52007-03-08 20:44:43 -08001100 switch (cmd) {
1101 case SIOCGETVIFCNT:
Jianjun Kongc354e122008-11-03 00:28:02 -08001102 if (copy_from_user(&vr, arg, sizeof(vr)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001103 return -EFAULT;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001104 if (vr.vifi >= net->ipv4.maxvif)
Stephen Hemminger132adf52007-03-08 20:44:43 -08001105 return -EINVAL;
1106 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001107 vif = &net->ipv4.vif_table[vr.vifi];
1108 if (VIF_EXISTS(net, vr.vifi)) {
Jianjun Kongc354e122008-11-03 00:28:02 -08001109 vr.icount = vif->pkt_in;
1110 vr.ocount = vif->pkt_out;
1111 vr.ibytes = vif->bytes_in;
1112 vr.obytes = vif->bytes_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 read_unlock(&mrt_lock);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001114
Jianjun Kongc354e122008-11-03 00:28:02 -08001115 if (copy_to_user(arg, &vr, sizeof(vr)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 return -EFAULT;
Stephen Hemminger132adf52007-03-08 20:44:43 -08001117 return 0;
1118 }
1119 read_unlock(&mrt_lock);
1120 return -EADDRNOTAVAIL;
1121 case SIOCGETSGCNT:
Jianjun Kongc354e122008-11-03 00:28:02 -08001122 if (copy_from_user(&sr, arg, sizeof(sr)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001123 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124
Stephen Hemminger132adf52007-03-08 20:44:43 -08001125 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001126 c = ipmr_cache_find(net, sr.src.s_addr, sr.grp.s_addr);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001127 if (c) {
1128 sr.pktcnt = c->mfc_un.res.pkt;
1129 sr.bytecnt = c->mfc_un.res.bytes;
1130 sr.wrong_if = c->mfc_un.res.wrong_if;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 read_unlock(&mrt_lock);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001132
Jianjun Kongc354e122008-11-03 00:28:02 -08001133 if (copy_to_user(arg, &sr, sizeof(sr)))
Stephen Hemminger132adf52007-03-08 20:44:43 -08001134 return -EFAULT;
1135 return 0;
1136 }
1137 read_unlock(&mrt_lock);
1138 return -EADDRNOTAVAIL;
1139 default:
1140 return -ENOIOCTLCMD;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 }
1142}
1143
1144
1145static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr)
1146{
Eric W. Biedermane9dc8652007-09-12 13:02:17 +02001147 struct net_device *dev = ptr;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001148 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 struct vif_device *v;
1150 int ct;
Eric W. Biedermane9dc8652007-09-12 13:02:17 +02001151
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001152 if (!net_eq(dev_net(dev), net))
Eric W. Biedermane9dc8652007-09-12 13:02:17 +02001153 return NOTIFY_DONE;
1154
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 if (event != NETDEV_UNREGISTER)
1156 return NOTIFY_DONE;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001157 v = &net->ipv4.vif_table[0];
1158 for (ct = 0; ct < net->ipv4.maxvif; ct++, v++) {
Jianjun Kongc354e122008-11-03 00:28:02 -08001159 if (v->dev == dev)
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001160 vif_delete(net, ct, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 }
1162 return NOTIFY_DONE;
1163}
1164
1165
Jianjun Kongc354e122008-11-03 00:28:02 -08001166static struct notifier_block ip_mr_notifier = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 .notifier_call = ipmr_device_event,
1168};
1169
1170/*
1171 * Encapsulate a packet by attaching a valid IPIP header to it.
1172 * This avoids tunnel drivers and other mess and gives us the speed so
1173 * important for multicast video.
1174 */
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001175
Al Viro114c7842006-09-27 18:39:29 -07001176static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177{
Arnaldo Carvalho de Melo8856dfa2007-03-10 19:40:39 -03001178 struct iphdr *iph;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001179 struct iphdr *old_iph = ip_hdr(skb);
Arnaldo Carvalho de Melo8856dfa2007-03-10 19:40:39 -03001180
1181 skb_push(skb, sizeof(struct iphdr));
Arnaldo Carvalho de Melob0e380b2007-04-10 21:21:55 -07001182 skb->transport_header = skb->network_header;
Arnaldo Carvalho de Melo8856dfa2007-03-10 19:40:39 -03001183 skb_reset_network_header(skb);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001184 iph = ip_hdr(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185
1186 iph->version = 4;
Arnaldo Carvalho de Meloe023dd62007-03-12 20:09:36 -03001187 iph->tos = old_iph->tos;
1188 iph->ttl = old_iph->ttl;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 iph->frag_off = 0;
1190 iph->daddr = daddr;
1191 iph->saddr = saddr;
1192 iph->protocol = IPPROTO_IPIP;
1193 iph->ihl = 5;
1194 iph->tot_len = htons(skb->len);
Eric Dumazetadf30902009-06-02 05:19:30 +00001195 ip_select_ident(iph, skb_dst(skb), NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 ip_send_check(iph);
1197
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
1199 nf_reset(skb);
1200}
1201
1202static inline int ipmr_forward_finish(struct sk_buff *skb)
1203{
1204 struct ip_options * opt = &(IPCB(skb)->opt);
1205
Eric Dumazetadf30902009-06-02 05:19:30 +00001206 IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTFORWDATAGRAMS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207
1208 if (unlikely(opt->optlen))
1209 ip_forward_options(skb);
1210
1211 return dst_output(skb);
1212}
1213
1214/*
1215 * Processing handlers for ipmr_forward
1216 */
1217
1218static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi)
1219{
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001220 struct net *net = mfc_net(c);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001221 const struct iphdr *iph = ip_hdr(skb);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001222 struct vif_device *vif = &net->ipv4.vif_table[vifi];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 struct net_device *dev;
1224 struct rtable *rt;
1225 int encap = 0;
1226
1227 if (vif->dev == NULL)
1228 goto out_free;
1229
1230#ifdef CONFIG_IP_PIMSM
1231 if (vif->flags & VIFF_REGISTER) {
1232 vif->pkt_out++;
Jianjun Kongc354e122008-11-03 00:28:02 -08001233 vif->bytes_out += skb->len;
Pavel Emelyanovcf3677a2008-05-21 14:17:33 -07001234 vif->dev->stats.tx_bytes += skb->len;
1235 vif->dev->stats.tx_packets++;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001236 ipmr_cache_report(net, skb, vifi, IGMPMSG_WHOLEPKT);
Ilpo Järvinen69ebbf52009-02-06 23:46:51 -08001237 goto out_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 }
1239#endif
1240
1241 if (vif->flags&VIFF_TUNNEL) {
1242 struct flowi fl = { .oif = vif->link,
1243 .nl_u = { .ip4_u =
1244 { .daddr = vif->remote,
1245 .saddr = vif->local,
1246 .tos = RT_TOS(iph->tos) } },
1247 .proto = IPPROTO_IPIP };
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001248 if (ip_route_output_key(net, &rt, &fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 goto out_free;
1250 encap = sizeof(struct iphdr);
1251 } else {
1252 struct flowi fl = { .oif = vif->link,
1253 .nl_u = { .ip4_u =
1254 { .daddr = iph->daddr,
1255 .tos = RT_TOS(iph->tos) } },
1256 .proto = IPPROTO_IPIP };
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001257 if (ip_route_output_key(net, &rt, &fl))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 goto out_free;
1259 }
1260
1261 dev = rt->u.dst.dev;
1262
1263 if (skb->len+encap > dst_mtu(&rt->u.dst) && (ntohs(iph->frag_off) & IP_DF)) {
1264 /* Do not fragment multicasts. Alas, IPv4 does not
1265 allow to send ICMP, so that packets will disappear
1266 to blackhole.
1267 */
1268
Pavel Emelyanov7c73a6f2008-07-16 20:20:11 -07001269 IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 ip_rt_put(rt);
1271 goto out_free;
1272 }
1273
1274 encap += LL_RESERVED_SPACE(dev) + rt->u.dst.header_len;
1275
1276 if (skb_cow(skb, encap)) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001277 ip_rt_put(rt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 goto out_free;
1279 }
1280
1281 vif->pkt_out++;
Jianjun Kongc354e122008-11-03 00:28:02 -08001282 vif->bytes_out += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283
Eric Dumazetadf30902009-06-02 05:19:30 +00001284 skb_dst_drop(skb);
1285 skb_dst_set(skb, &rt->u.dst);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001286 ip_decrease_ttl(ip_hdr(skb));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287
1288 /* FIXME: forward and output firewalls used to be called here.
1289 * What do we do with netfilter? -- RR */
1290 if (vif->flags & VIFF_TUNNEL) {
1291 ip_encap(skb, vif->local, vif->remote);
1292 /* FIXME: extra output firewall step used to be here. --RR */
Pavel Emelyanov2f4c02d2008-05-21 14:16:14 -07001293 vif->dev->stats.tx_packets++;
1294 vif->dev->stats.tx_bytes += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 }
1296
1297 IPCB(skb)->flags |= IPSKB_FORWARDED;
1298
1299 /*
1300 * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
1301 * not only before forwarding, but after forwarding on all output
1302 * interfaces. It is clear, if mrouter runs a multicasting
1303 * program, it should receive packets not depending to what interface
1304 * program is joined.
1305 * If we will not make it, the program will have to join on all
1306 * interfaces. On the other hand, multihoming host (or router, but
1307 * not mrouter) cannot join to more than one interface - it will
1308 * result in receiving multiple packets.
1309 */
Patrick McHardy6e23ae22007-11-19 18:53:30 -08001310 NF_HOOK(PF_INET, NF_INET_FORWARD, skb, skb->dev, dev,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 ipmr_forward_finish);
1312 return;
1313
1314out_free:
1315 kfree_skb(skb);
1316 return;
1317}
1318
1319static int ipmr_find_vif(struct net_device *dev)
1320{
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001321 struct net *net = dev_net(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 int ct;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001323 for (ct = net->ipv4.maxvif-1; ct >= 0; ct--) {
1324 if (net->ipv4.vif_table[ct].dev == dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 break;
1326 }
1327 return ct;
1328}
1329
1330/* "local" means that we should preserve one skb (for local delivery) */
1331
1332static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local)
1333{
1334 int psend = -1;
1335 int vif, ct;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001336 struct net *net = mfc_net(cache);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337
1338 vif = cache->mfc_parent;
1339 cache->mfc_un.res.pkt++;
1340 cache->mfc_un.res.bytes += skb->len;
1341
1342 /*
1343 * Wrong interface: drop packet and (maybe) send PIM assert.
1344 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001345 if (net->ipv4.vif_table[vif].dev != skb->dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 int true_vifi;
1347
Eric Dumazet511c3f92009-06-02 05:14:27 +00001348 if (skb_rtable(skb)->fl.iif == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 /* It is our own packet, looped back.
1350 Very complicated situation...
1351
1352 The best workaround until routing daemons will be
1353 fixed is not to redistribute packet, if it was
1354 send through wrong interface. It means, that
1355 multicast applications WILL NOT work for
1356 (S,G), which have default multicast route pointing
1357 to wrong oif. In any case, it is not a good
1358 idea to use multicasting applications on router.
1359 */
1360 goto dont_forward;
1361 }
1362
1363 cache->mfc_un.res.wrong_if++;
1364 true_vifi = ipmr_find_vif(skb->dev);
1365
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001366 if (true_vifi >= 0 && net->ipv4.mroute_do_assert &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 /* pimsm uses asserts, when switching from RPT to SPT,
1368 so that we cannot check that packet arrived on an oif.
1369 It is bad, but otherwise we would need to move pretty
1370 large chunk of pimd to kernel. Ough... --ANK
1371 */
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001372 (net->ipv4.mroute_do_pim ||
Benjamin Thery6f9374a2009-01-22 04:56:20 +00001373 cache->mfc_un.res.ttls[true_vifi] < 255) &&
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001374 time_after(jiffies,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) {
1376 cache->mfc_un.res.last_assert = jiffies;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001377 ipmr_cache_report(net, skb, true_vifi, IGMPMSG_WRONGVIF);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 }
1379 goto dont_forward;
1380 }
1381
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001382 net->ipv4.vif_table[vif].pkt_in++;
1383 net->ipv4.vif_table[vif].bytes_in += skb->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384
1385 /*
1386 * Forward the frame
1387 */
1388 for (ct = cache->mfc_un.res.maxvif-1; ct >= cache->mfc_un.res.minvif; ct--) {
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001389 if (ip_hdr(skb)->ttl > cache->mfc_un.res.ttls[ct]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 if (psend != -1) {
1391 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
1392 if (skb2)
1393 ipmr_queue_xmit(skb2, cache, psend);
1394 }
Jianjun Kongc354e122008-11-03 00:28:02 -08001395 psend = ct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 }
1397 }
1398 if (psend != -1) {
1399 if (local) {
1400 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
1401 if (skb2)
1402 ipmr_queue_xmit(skb2, cache, psend);
1403 } else {
1404 ipmr_queue_xmit(skb, cache, psend);
1405 return 0;
1406 }
1407 }
1408
1409dont_forward:
1410 if (!local)
1411 kfree_skb(skb);
1412 return 0;
1413}
1414
1415
1416/*
1417 * Multicast packets for forwarding arrive here
1418 */
1419
1420int ip_mr_input(struct sk_buff *skb)
1421{
1422 struct mfc_cache *cache;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001423 struct net *net = dev_net(skb->dev);
Eric Dumazet511c3f92009-06-02 05:14:27 +00001424 int local = skb_rtable(skb)->rt_flags & RTCF_LOCAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425
1426 /* Packet is looped back after forward, it should not be
1427 forwarded second time, but still can be delivered locally.
1428 */
1429 if (IPCB(skb)->flags&IPSKB_FORWARDED)
1430 goto dont_forward;
1431
1432 if (!local) {
1433 if (IPCB(skb)->opt.router_alert) {
1434 if (ip_call_ra_chain(skb))
1435 return 0;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001436 } else if (ip_hdr(skb)->protocol == IPPROTO_IGMP){
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 /* IGMPv1 (and broken IGMPv2 implementations sort of
1438 Cisco IOS <= 11.2(8)) do not put router alert
1439 option to IGMP packets destined to routable
1440 groups. It is very bad, because it means
1441 that we can forward NO IGMP messages.
1442 */
1443 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001444 if (net->ipv4.mroute_sk) {
Patrick McHardy2715bcf2005-06-21 14:06:24 -07001445 nf_reset(skb);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001446 raw_rcv(net->ipv4.mroute_sk, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 read_unlock(&mrt_lock);
1448 return 0;
1449 }
1450 read_unlock(&mrt_lock);
1451 }
1452 }
1453
1454 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001455 cache = ipmr_cache_find(net, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456
1457 /*
1458 * No usable cache entry
1459 */
Jianjun Kongc354e122008-11-03 00:28:02 -08001460 if (cache == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 int vif;
1462
1463 if (local) {
1464 struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
1465 ip_local_deliver(skb);
1466 if (skb2 == NULL) {
1467 read_unlock(&mrt_lock);
1468 return -ENOBUFS;
1469 }
1470 skb = skb2;
1471 }
1472
1473 vif = ipmr_find_vif(skb->dev);
1474 if (vif >= 0) {
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001475 int err = ipmr_cache_unresolved(net, vif, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 read_unlock(&mrt_lock);
1477
1478 return err;
1479 }
1480 read_unlock(&mrt_lock);
1481 kfree_skb(skb);
1482 return -ENODEV;
1483 }
1484
1485 ip_mr_forward(skb, cache, local);
1486
1487 read_unlock(&mrt_lock);
1488
1489 if (local)
1490 return ip_local_deliver(skb);
1491
1492 return 0;
1493
1494dont_forward:
1495 if (local)
1496 return ip_local_deliver(skb);
1497 kfree_skb(skb);
1498 return 0;
1499}
1500
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001501#ifdef CONFIG_IP_PIMSM
1502static int __pim_rcv(struct sk_buff *skb, unsigned int pimlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503{
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001504 struct net_device *reg_dev = NULL;
1505 struct iphdr *encap;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001506 struct net *net = dev_net(skb->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001508 encap = (struct iphdr *)(skb_transport_header(skb) + pimlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 /*
1510 Check that:
1511 a. packet is really destinted to a multicast group
1512 b. packet is not a NULL-REGISTER
1513 c. packet is not truncated
1514 */
Joe Perchesf97c1e02007-12-16 13:45:43 -08001515 if (!ipv4_is_multicast(encap->daddr) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 encap->tot_len == 0 ||
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001517 ntohs(encap->tot_len) + pimlen > skb->len)
1518 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519
1520 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001521 if (net->ipv4.mroute_reg_vif_num >= 0)
1522 reg_dev = net->ipv4.vif_table[net->ipv4.mroute_reg_vif_num].dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 if (reg_dev)
1524 dev_hold(reg_dev);
1525 read_unlock(&mrt_lock);
1526
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001527 if (reg_dev == NULL)
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001528 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529
Arnaldo Carvalho de Melob0e380b2007-04-10 21:21:55 -07001530 skb->mac_header = skb->network_header;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 skb_pull(skb, (u8*)encap - skb->data);
Arnaldo Carvalho de Melo31c77112007-03-10 19:04:55 -03001532 skb_reset_network_header(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 skb->dev = reg_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 skb->protocol = htons(ETH_P_IP);
1535 skb->ip_summed = 0;
1536 skb->pkt_type = PACKET_HOST;
Eric Dumazetadf30902009-06-02 05:19:30 +00001537 skb_dst_drop(skb);
Pavel Emelyanovcf3677a2008-05-21 14:17:33 -07001538 reg_dev->stats.rx_bytes += skb->len;
1539 reg_dev->stats.rx_packets++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 nf_reset(skb);
1541 netif_rx(skb);
1542 dev_put(reg_dev);
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001543
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 return 0;
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001545}
1546#endif
1547
1548#ifdef CONFIG_IP_PIMSM_V1
1549/*
1550 * Handle IGMP messages of PIMv1
1551 */
1552
1553int pim_rcv_v1(struct sk_buff * skb)
1554{
1555 struct igmphdr *pim;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001556 struct net *net = dev_net(skb->dev);
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001557
1558 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr)))
1559 goto drop;
1560
1561 pim = igmp_hdr(skb);
1562
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001563 if (!net->ipv4.mroute_do_pim ||
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001564 pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER)
1565 goto drop;
1566
1567 if (__pim_rcv(skb, sizeof(*pim))) {
1568drop:
1569 kfree_skb(skb);
1570 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 return 0;
1572}
1573#endif
1574
1575#ifdef CONFIG_IP_PIMSM_V2
1576static int pim_rcv(struct sk_buff * skb)
1577{
1578 struct pimreghdr *pim;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001580 if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 goto drop;
1582
Arnaldo Carvalho de Melo9c702202007-04-25 18:04:18 -07001583 pim = (struct pimreghdr *)skb_transport_header(skb);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001584 if (pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 (pim->flags&PIM_NULL_REGISTER) ||
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001586 (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 &&
Al Virod3bc23e2006-11-14 21:24:49 -08001587 csum_fold(skb_checksum(skb, 0, skb->len, 0))))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 goto drop;
1589
Ilpo Järvinenb1879202008-12-16 01:15:11 -08001590 if (__pim_rcv(skb, sizeof(*pim))) {
1591drop:
1592 kfree_skb(skb);
1593 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 return 0;
1595}
1596#endif
1597
1598static int
1599ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm)
1600{
1601 int ct;
1602 struct rtnexthop *nhp;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001603 struct net *net = mfc_net(c);
1604 struct net_device *dev = net->ipv4.vif_table[c->mfc_parent].dev;
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001605 u8 *b = skb_tail_pointer(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 struct rtattr *mp_head;
1607
1608 if (dev)
1609 RTA_PUT(skb, RTA_IIF, 4, &dev->ifindex);
1610
Jianjun Kongc354e122008-11-03 00:28:02 -08001611 mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612
1613 for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
1614 if (c->mfc_un.res.ttls[ct] < 255) {
1615 if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4))
1616 goto rtattr_failure;
Jianjun Kongc354e122008-11-03 00:28:02 -08001617 nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 nhp->rtnh_flags = 0;
1619 nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001620 nhp->rtnh_ifindex = net->ipv4.vif_table[ct].dev->ifindex;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 nhp->rtnh_len = sizeof(*nhp);
1622 }
1623 }
1624 mp_head->rta_type = RTA_MULTIPATH;
Arnaldo Carvalho de Melo27a884d2007-04-19 20:29:13 -07001625 mp_head->rta_len = skb_tail_pointer(skb) - (u8 *)mp_head;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 rtm->rtm_type = RTN_MULTICAST;
1627 return 1;
1628
1629rtattr_failure:
Arnaldo Carvalho de Melodc5fc572007-03-25 23:06:12 -07001630 nlmsg_trim(skb, b);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 return -EMSGSIZE;
1632}
1633
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001634int ipmr_get_route(struct net *net,
1635 struct sk_buff *skb, struct rtmsg *rtm, int nowait)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636{
1637 int err;
1638 struct mfc_cache *cache;
Eric Dumazet511c3f92009-06-02 05:14:27 +00001639 struct rtable *rt = skb_rtable(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640
1641 read_lock(&mrt_lock);
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001642 cache = ipmr_cache_find(net, rt->rt_src, rt->rt_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643
Jianjun Kongc354e122008-11-03 00:28:02 -08001644 if (cache == NULL) {
Alexey Kuznetsov72287492006-07-25 16:45:12 -07001645 struct sk_buff *skb2;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001646 struct iphdr *iph;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 struct net_device *dev;
1648 int vif;
1649
1650 if (nowait) {
1651 read_unlock(&mrt_lock);
1652 return -EAGAIN;
1653 }
1654
1655 dev = skb->dev;
1656 if (dev == NULL || (vif = ipmr_find_vif(dev)) < 0) {
1657 read_unlock(&mrt_lock);
1658 return -ENODEV;
1659 }
Alexey Kuznetsov72287492006-07-25 16:45:12 -07001660 skb2 = skb_clone(skb, GFP_ATOMIC);
1661 if (!skb2) {
1662 read_unlock(&mrt_lock);
1663 return -ENOMEM;
1664 }
1665
Arnaldo Carvalho de Meloe2d1bca2007-04-10 20:46:21 -07001666 skb_push(skb2, sizeof(struct iphdr));
1667 skb_reset_network_header(skb2);
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07001668 iph = ip_hdr(skb2);
1669 iph->ihl = sizeof(struct iphdr) >> 2;
1670 iph->saddr = rt->rt_src;
1671 iph->daddr = rt->rt_dst;
1672 iph->version = 0;
Benjamin Thery4feb88e2009-01-22 04:56:23 +00001673 err = ipmr_cache_unresolved(net, vif, skb2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 read_unlock(&mrt_lock);
1675 return err;
1676 }
1677
1678 if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY))
1679 cache->mfc_flags |= MFC_NOTIFY;
1680 err = ipmr_fill_mroute(skb, cache, rtm);
1681 read_unlock(&mrt_lock);
1682 return err;
1683}
1684
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001685#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686/*
1687 * The /proc interfaces to multicast routing /proc/ip_mr_cache /proc/ip_mr_vif
1688 */
1689struct ipmr_vif_iter {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001690 struct seq_net_private p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 int ct;
1692};
1693
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001694static struct vif_device *ipmr_vif_seq_idx(struct net *net,
1695 struct ipmr_vif_iter *iter,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 loff_t pos)
1697{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001698 for (iter->ct = 0; iter->ct < net->ipv4.maxvif; ++iter->ct) {
1699 if (!VIF_EXISTS(net, iter->ct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 continue;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001701 if (pos-- == 0)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001702 return &net->ipv4.vif_table[iter->ct];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 }
1704 return NULL;
1705}
1706
1707static void *ipmr_vif_seq_start(struct seq_file *seq, loff_t *pos)
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001708 __acquires(mrt_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001710 struct net *net = seq_file_net(seq);
1711
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712 read_lock(&mrt_lock);
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001713 return *pos ? ipmr_vif_seq_idx(net, seq->private, *pos - 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 : SEQ_START_TOKEN;
1715}
1716
1717static void *ipmr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
1718{
1719 struct ipmr_vif_iter *iter = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001720 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721
1722 ++*pos;
1723 if (v == SEQ_START_TOKEN)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001724 return ipmr_vif_seq_idx(net, iter, 0);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001725
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001726 while (++iter->ct < net->ipv4.maxvif) {
1727 if (!VIF_EXISTS(net, iter->ct))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 continue;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001729 return &net->ipv4.vif_table[iter->ct];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 }
1731 return NULL;
1732}
1733
1734static void ipmr_vif_seq_stop(struct seq_file *seq, void *v)
Stephen Hemmingerba93ef72008-01-21 17:28:59 -08001735 __releases(mrt_lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736{
1737 read_unlock(&mrt_lock);
1738}
1739
1740static int ipmr_vif_seq_show(struct seq_file *seq, void *v)
1741{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001742 struct net *net = seq_file_net(seq);
1743
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 if (v == SEQ_START_TOKEN) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001745 seq_puts(seq,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 "Interface BytesIn PktsIn BytesOut PktsOut Flags Local Remote\n");
1747 } else {
1748 const struct vif_device *vif = v;
1749 const char *name = vif->dev ? vif->dev->name : "none";
1750
1751 seq_printf(seq,
1752 "%2Zd %-10s %8ld %7ld %8ld %7ld %05X %08X %08X\n",
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001753 vif - net->ipv4.vif_table,
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001754 name, vif->bytes_in, vif->pkt_in,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 vif->bytes_out, vif->pkt_out,
1756 vif->flags, vif->local, vif->remote);
1757 }
1758 return 0;
1759}
1760
Stephen Hemmingerf6908082007-03-12 14:34:29 -07001761static const struct seq_operations ipmr_vif_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 .start = ipmr_vif_seq_start,
1763 .next = ipmr_vif_seq_next,
1764 .stop = ipmr_vif_seq_stop,
1765 .show = ipmr_vif_seq_show,
1766};
1767
1768static int ipmr_vif_open(struct inode *inode, struct file *file)
1769{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001770 return seq_open_net(inode, file, &ipmr_vif_seq_ops,
1771 sizeof(struct ipmr_vif_iter));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772}
1773
Arjan van de Ven9a321442007-02-12 00:55:35 -08001774static const struct file_operations ipmr_vif_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775 .owner = THIS_MODULE,
1776 .open = ipmr_vif_open,
1777 .read = seq_read,
1778 .llseek = seq_lseek,
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001779 .release = seq_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780};
1781
1782struct ipmr_mfc_iter {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001783 struct seq_net_private p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 struct mfc_cache **cache;
1785 int ct;
1786};
1787
1788
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001789static struct mfc_cache *ipmr_mfc_seq_idx(struct net *net,
1790 struct ipmr_mfc_iter *it, loff_t pos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791{
1792 struct mfc_cache *mfc;
1793
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001794 it->cache = net->ipv4.mfc_cache_array;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 read_lock(&mrt_lock);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001796 for (it->ct = 0; it->ct < MFC_LINES; it->ct++)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001797 for (mfc = net->ipv4.mfc_cache_array[it->ct];
Benjamin Thery2bb8b262009-01-22 04:56:18 +00001798 mfc; mfc = mfc->next)
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001799 if (pos-- == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 return mfc;
1801 read_unlock(&mrt_lock);
1802
1803 it->cache = &mfc_unres_queue;
1804 spin_lock_bh(&mfc_unres_lock);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001805 for (mfc = mfc_unres_queue; mfc; mfc = mfc->next)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001806 if (net_eq(mfc_net(mfc), net) &&
1807 pos-- == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 return mfc;
1809 spin_unlock_bh(&mfc_unres_lock);
1810
1811 it->cache = NULL;
1812 return NULL;
1813}
1814
1815
1816static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos)
1817{
1818 struct ipmr_mfc_iter *it = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001819 struct net *net = seq_file_net(seq);
1820
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 it->cache = NULL;
1822 it->ct = 0;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001823 return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 : SEQ_START_TOKEN;
1825}
1826
1827static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
1828{
1829 struct mfc_cache *mfc = v;
1830 struct ipmr_mfc_iter *it = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001831 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832
1833 ++*pos;
1834
1835 if (v == SEQ_START_TOKEN)
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001836 return ipmr_mfc_seq_idx(net, seq->private, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837
1838 if (mfc->next)
1839 return mfc->next;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001840
1841 if (it->cache == &mfc_unres_queue)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 goto end_of_list;
1843
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001844 BUG_ON(it->cache != net->ipv4.mfc_cache_array);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845
1846 while (++it->ct < MFC_LINES) {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001847 mfc = net->ipv4.mfc_cache_array[it->ct];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 if (mfc)
1849 return mfc;
1850 }
1851
1852 /* exhausted cache_array, show unresolved */
1853 read_unlock(&mrt_lock);
1854 it->cache = &mfc_unres_queue;
1855 it->ct = 0;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001856
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 spin_lock_bh(&mfc_unres_lock);
1858 mfc = mfc_unres_queue;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001859 while (mfc && !net_eq(mfc_net(mfc), net))
1860 mfc = mfc->next;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001861 if (mfc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 return mfc;
1863
1864 end_of_list:
1865 spin_unlock_bh(&mfc_unres_lock);
1866 it->cache = NULL;
1867
1868 return NULL;
1869}
1870
1871static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v)
1872{
1873 struct ipmr_mfc_iter *it = seq->private;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001874 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875
1876 if (it->cache == &mfc_unres_queue)
1877 spin_unlock_bh(&mfc_unres_lock);
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001878 else if (it->cache == net->ipv4.mfc_cache_array)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 read_unlock(&mrt_lock);
1880}
1881
1882static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
1883{
1884 int n;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001885 struct net *net = seq_file_net(seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886
1887 if (v == SEQ_START_TOKEN) {
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001888 seq_puts(seq,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 "Group Origin Iif Pkts Bytes Wrong Oifs\n");
1890 } else {
1891 const struct mfc_cache *mfc = v;
1892 const struct ipmr_mfc_iter *it = seq->private;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001893
Benjamin Thery999890b2008-12-03 22:22:16 -08001894 seq_printf(seq, "%08lX %08lX %-3hd",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 (unsigned long) mfc->mfc_mcastgrp,
1896 (unsigned long) mfc->mfc_origin,
Benjamin Thery1ea472e2008-12-03 22:21:47 -08001897 mfc->mfc_parent);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898
1899 if (it->cache != &mfc_unres_queue) {
Benjamin Thery1ea472e2008-12-03 22:21:47 -08001900 seq_printf(seq, " %8lu %8lu %8lu",
1901 mfc->mfc_un.res.pkt,
1902 mfc->mfc_un.res.bytes,
1903 mfc->mfc_un.res.wrong_if);
Stephen Hemminger132adf52007-03-08 20:44:43 -08001904 for (n = mfc->mfc_un.res.minvif;
1905 n < mfc->mfc_un.res.maxvif; n++ ) {
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001906 if (VIF_EXISTS(net, n) &&
Benjamin Therycf958ae32009-01-22 04:56:16 +00001907 mfc->mfc_un.res.ttls[n] < 255)
1908 seq_printf(seq,
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001909 " %2d:%-3d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 n, mfc->mfc_un.res.ttls[n]);
1911 }
Benjamin Thery1ea472e2008-12-03 22:21:47 -08001912 } else {
1913 /* unresolved mfc_caches don't contain
1914 * pkt, bytes and wrong_if values
1915 */
1916 seq_printf(seq, " %8lu %8lu %8lu", 0ul, 0ul, 0ul);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 }
1918 seq_putc(seq, '\n');
1919 }
1920 return 0;
1921}
1922
Stephen Hemmingerf6908082007-03-12 14:34:29 -07001923static const struct seq_operations ipmr_mfc_seq_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924 .start = ipmr_mfc_seq_start,
1925 .next = ipmr_mfc_seq_next,
1926 .stop = ipmr_mfc_seq_stop,
1927 .show = ipmr_mfc_seq_show,
1928};
1929
1930static int ipmr_mfc_open(struct inode *inode, struct file *file)
1931{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001932 return seq_open_net(inode, file, &ipmr_mfc_seq_ops,
1933 sizeof(struct ipmr_mfc_iter));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934}
1935
Arjan van de Ven9a321442007-02-12 00:55:35 -08001936static const struct file_operations ipmr_mfc_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937 .owner = THIS_MODULE,
1938 .open = ipmr_mfc_open,
1939 .read = seq_read,
1940 .llseek = seq_lseek,
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001941 .release = seq_release_net,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942};
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001943#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944
1945#ifdef CONFIG_IP_PIMSM_V2
Alexey Dobriyan32613092009-09-14 12:21:47 +00001946static const struct net_protocol pim_protocol = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 .handler = pim_rcv,
Tom Goff403dbb92009-06-14 03:16:13 -07001948 .netns_ok = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949};
1950#endif
1951
1952
1953/*
1954 * Setup for IP multicast routing
1955 */
Benjamin Therycf958ae32009-01-22 04:56:16 +00001956static int __net_init ipmr_net_init(struct net *net)
1957{
1958 int err = 0;
1959
1960 net->ipv4.vif_table = kcalloc(MAXVIFS, sizeof(struct vif_device),
1961 GFP_KERNEL);
1962 if (!net->ipv4.vif_table) {
1963 err = -ENOMEM;
1964 goto fail;
1965 }
Benjamin Thery2bb8b262009-01-22 04:56:18 +00001966
1967 /* Forwarding cache */
1968 net->ipv4.mfc_cache_array = kcalloc(MFC_LINES,
1969 sizeof(struct mfc_cache *),
1970 GFP_KERNEL);
1971 if (!net->ipv4.mfc_cache_array) {
1972 err = -ENOMEM;
1973 goto fail_mfc_cache;
1974 }
Benjamin Thery6c5143d2009-01-22 04:56:21 +00001975
1976#ifdef CONFIG_IP_PIMSM
1977 net->ipv4.mroute_reg_vif_num = -1;
1978#endif
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001979
1980#ifdef CONFIG_PROC_FS
1981 err = -ENOMEM;
1982 if (!proc_net_fops_create(net, "ip_mr_vif", 0, &ipmr_vif_fops))
1983 goto proc_vif_fail;
1984 if (!proc_net_fops_create(net, "ip_mr_cache", 0, &ipmr_mfc_fops))
1985 goto proc_cache_fail;
1986#endif
Benjamin Thery2bb8b262009-01-22 04:56:18 +00001987 return 0;
1988
Benjamin Theryf6bb4512009-01-22 04:56:22 +00001989#ifdef CONFIG_PROC_FS
1990proc_cache_fail:
1991 proc_net_remove(net, "ip_mr_vif");
1992proc_vif_fail:
1993 kfree(net->ipv4.mfc_cache_array);
1994#endif
Benjamin Thery2bb8b262009-01-22 04:56:18 +00001995fail_mfc_cache:
1996 kfree(net->ipv4.vif_table);
Benjamin Therycf958ae32009-01-22 04:56:16 +00001997fail:
1998 return err;
1999}
2000
2001static void __net_exit ipmr_net_exit(struct net *net)
2002{
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002003#ifdef CONFIG_PROC_FS
2004 proc_net_remove(net, "ip_mr_cache");
2005 proc_net_remove(net, "ip_mr_vif");
2006#endif
Benjamin Thery2bb8b262009-01-22 04:56:18 +00002007 kfree(net->ipv4.mfc_cache_array);
Benjamin Therycf958ae32009-01-22 04:56:16 +00002008 kfree(net->ipv4.vif_table);
2009}
2010
2011static struct pernet_operations ipmr_net_ops = {
2012 .init = ipmr_net_init,
2013 .exit = ipmr_net_exit,
2014};
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002015
Wang Chen03d2f892008-07-03 12:13:36 +08002016int __init ip_mr_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017{
Wang Chen03d2f892008-07-03 12:13:36 +08002018 int err;
2019
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 mrt_cachep = kmem_cache_create("ip_mrt_cache",
2021 sizeof(struct mfc_cache),
Alexey Dobriyane5d679f2006-08-26 19:25:52 -07002022 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
Paul Mundt20c2df82007-07-20 10:11:58 +09002023 NULL);
Wang Chen03d2f892008-07-03 12:13:36 +08002024 if (!mrt_cachep)
2025 return -ENOMEM;
2026
Benjamin Therycf958ae32009-01-22 04:56:16 +00002027 err = register_pernet_subsys(&ipmr_net_ops);
2028 if (err)
2029 goto reg_pernet_fail;
2030
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -08002031 setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0);
Wang Chen03d2f892008-07-03 12:13:36 +08002032 err = register_netdevice_notifier(&ip_mr_notifier);
2033 if (err)
2034 goto reg_notif_fail;
Tom Goff403dbb92009-06-14 03:16:13 -07002035#ifdef CONFIG_IP_PIMSM_V2
2036 if (inet_add_protocol(&pim_protocol, IPPROTO_PIM) < 0) {
2037 printk(KERN_ERR "ip_mr_init: can't add PIM protocol\n");
2038 err = -EAGAIN;
2039 goto add_proto_fail;
2040 }
2041#endif
Wang Chen03d2f892008-07-03 12:13:36 +08002042 return 0;
Benjamin Theryf6bb4512009-01-22 04:56:22 +00002043
Tom Goff403dbb92009-06-14 03:16:13 -07002044#ifdef CONFIG_IP_PIMSM_V2
2045add_proto_fail:
2046 unregister_netdevice_notifier(&ip_mr_notifier);
2047#endif
Benjamin Theryc3e38892008-11-19 14:07:41 -08002048reg_notif_fail:
2049 del_timer(&ipmr_expire_timer);
Benjamin Therycf958ae32009-01-22 04:56:16 +00002050 unregister_pernet_subsys(&ipmr_net_ops);
2051reg_pernet_fail:
Benjamin Theryc3e38892008-11-19 14:07:41 -08002052 kmem_cache_destroy(mrt_cachep);
Wang Chen03d2f892008-07-03 12:13:36 +08002053 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054}