diff options
Diffstat (limited to 'net/ipv4/ipmr.c')
-rw-r--r-- | net/ipv4/ipmr.c | 123 |
1 files changed, 89 insertions, 34 deletions
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 11700a4dcd95..033c712c3a5d 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c | |||
@@ -9,8 +9,6 @@ | |||
9 | * as published by the Free Software Foundation; either version | 9 | * as published by the Free Software Foundation; either version |
10 | * 2 of the License, or (at your option) any later version. | 10 | * 2 of the License, or (at your option) any later version. |
11 | * | 11 | * |
12 | * Version: $Id: ipmr.c,v 1.65 2001/10/31 21:55:54 davem Exp $ | ||
13 | * | ||
14 | * Fixes: | 12 | * Fixes: |
15 | * Michael Chastain : Incorrect size of copying. | 13 | * Michael Chastain : Incorrect size of copying. |
16 | * Alan Cox : Added the cache manager code | 14 | * Alan Cox : Added the cache manager code |
@@ -120,6 +118,31 @@ static struct timer_list ipmr_expire_timer; | |||
120 | 118 | ||
121 | /* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */ | 119 | /* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */ |
122 | 120 | ||
121 | static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v) | ||
122 | { | ||
123 | dev_close(dev); | ||
124 | |||
125 | dev = __dev_get_by_name(&init_net, "tunl0"); | ||
126 | if (dev) { | ||
127 | struct ifreq ifr; | ||
128 | mm_segment_t oldfs; | ||
129 | struct ip_tunnel_parm p; | ||
130 | |||
131 | memset(&p, 0, sizeof(p)); | ||
132 | p.iph.daddr = v->vifc_rmt_addr.s_addr; | ||
133 | p.iph.saddr = v->vifc_lcl_addr.s_addr; | ||
134 | p.iph.version = 4; | ||
135 | p.iph.ihl = 5; | ||
136 | p.iph.protocol = IPPROTO_IPIP; | ||
137 | sprintf(p.name, "dvmrp%d", v->vifc_vifi); | ||
138 | ifr.ifr_ifru.ifru_data = (__force void __user *)&p; | ||
139 | |||
140 | oldfs = get_fs(); set_fs(KERNEL_DS); | ||
141 | dev->do_ioctl(dev, &ifr, SIOCDELTUNNEL); | ||
142 | set_fs(oldfs); | ||
143 | } | ||
144 | } | ||
145 | |||
123 | static | 146 | static |
124 | struct net_device *ipmr_new_tunnel(struct vifctl *v) | 147 | struct net_device *ipmr_new_tunnel(struct vifctl *v) |
125 | { | 148 | { |
@@ -161,6 +184,7 @@ struct net_device *ipmr_new_tunnel(struct vifctl *v) | |||
161 | 184 | ||
162 | if (dev_open(dev)) | 185 | if (dev_open(dev)) |
163 | goto failure; | 186 | goto failure; |
187 | dev_hold(dev); | ||
164 | } | 188 | } |
165 | } | 189 | } |
166 | return dev; | 190 | return dev; |
@@ -181,26 +205,20 @@ static int reg_vif_num = -1; | |||
181 | static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev) | 205 | static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev) |
182 | { | 206 | { |
183 | read_lock(&mrt_lock); | 207 | read_lock(&mrt_lock); |
184 | ((struct net_device_stats*)netdev_priv(dev))->tx_bytes += skb->len; | 208 | dev->stats.tx_bytes += skb->len; |
185 | ((struct net_device_stats*)netdev_priv(dev))->tx_packets++; | 209 | dev->stats.tx_packets++; |
186 | ipmr_cache_report(skb, reg_vif_num, IGMPMSG_WHOLEPKT); | 210 | ipmr_cache_report(skb, reg_vif_num, IGMPMSG_WHOLEPKT); |
187 | read_unlock(&mrt_lock); | 211 | read_unlock(&mrt_lock); |
188 | kfree_skb(skb); | 212 | kfree_skb(skb); |
189 | return 0; | 213 | return 0; |
190 | } | 214 | } |
191 | 215 | ||
192 | static struct net_device_stats *reg_vif_get_stats(struct net_device *dev) | ||
193 | { | ||
194 | return (struct net_device_stats*)netdev_priv(dev); | ||
195 | } | ||
196 | |||
197 | static void reg_vif_setup(struct net_device *dev) | 216 | static void reg_vif_setup(struct net_device *dev) |
198 | { | 217 | { |
199 | dev->type = ARPHRD_PIMREG; | 218 | dev->type = ARPHRD_PIMREG; |
200 | dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 8; | 219 | dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 8; |
201 | dev->flags = IFF_NOARP; | 220 | dev->flags = IFF_NOARP; |
202 | dev->hard_start_xmit = reg_vif_xmit; | 221 | dev->hard_start_xmit = reg_vif_xmit; |
203 | dev->get_stats = reg_vif_get_stats; | ||
204 | dev->destructor = free_netdev; | 222 | dev->destructor = free_netdev; |
205 | } | 223 | } |
206 | 224 | ||
@@ -209,8 +227,7 @@ static struct net_device *ipmr_reg_vif(void) | |||
209 | struct net_device *dev; | 227 | struct net_device *dev; |
210 | struct in_device *in_dev; | 228 | struct in_device *in_dev; |
211 | 229 | ||
212 | dev = alloc_netdev(sizeof(struct net_device_stats), "pimreg", | 230 | dev = alloc_netdev(0, "pimreg", reg_vif_setup); |
213 | reg_vif_setup); | ||
214 | 231 | ||
215 | if (dev == NULL) | 232 | if (dev == NULL) |
216 | return NULL; | 233 | return NULL; |
@@ -234,6 +251,8 @@ static struct net_device *ipmr_reg_vif(void) | |||
234 | if (dev_open(dev)) | 251 | if (dev_open(dev)) |
235 | goto failure; | 252 | goto failure; |
236 | 253 | ||
254 | dev_hold(dev); | ||
255 | |||
237 | return dev; | 256 | return dev; |
238 | 257 | ||
239 | failure: | 258 | failure: |
@@ -248,9 +267,10 @@ failure: | |||
248 | 267 | ||
249 | /* | 268 | /* |
250 | * Delete a VIF entry | 269 | * Delete a VIF entry |
270 | * @notify: Set to 1, if the caller is a notifier_call | ||
251 | */ | 271 | */ |
252 | 272 | ||
253 | static int vif_delete(int vifi) | 273 | static int vif_delete(int vifi, int notify) |
254 | { | 274 | { |
255 | struct vif_device *v; | 275 | struct vif_device *v; |
256 | struct net_device *dev; | 276 | struct net_device *dev; |
@@ -293,7 +313,7 @@ static int vif_delete(int vifi) | |||
293 | ip_rt_multicast_event(in_dev); | 313 | ip_rt_multicast_event(in_dev); |
294 | } | 314 | } |
295 | 315 | ||
296 | if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER)) | 316 | if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER) && !notify) |
297 | unregister_netdevice(dev); | 317 | unregister_netdevice(dev); |
298 | 318 | ||
299 | dev_put(dev); | 319 | dev_put(dev); |
@@ -398,6 +418,7 @@ static int vif_add(struct vifctl *vifc, int mrtsock) | |||
398 | struct vif_device *v = &vif_table[vifi]; | 418 | struct vif_device *v = &vif_table[vifi]; |
399 | struct net_device *dev; | 419 | struct net_device *dev; |
400 | struct in_device *in_dev; | 420 | struct in_device *in_dev; |
421 | int err; | ||
401 | 422 | ||
402 | /* Is vif busy ? */ | 423 | /* Is vif busy ? */ |
403 | if (VIF_EXISTS(vifi)) | 424 | if (VIF_EXISTS(vifi)) |
@@ -415,18 +436,34 @@ static int vif_add(struct vifctl *vifc, int mrtsock) | |||
415 | dev = ipmr_reg_vif(); | 436 | dev = ipmr_reg_vif(); |
416 | if (!dev) | 437 | if (!dev) |
417 | return -ENOBUFS; | 438 | return -ENOBUFS; |
439 | err = dev_set_allmulti(dev, 1); | ||
440 | if (err) { | ||
441 | unregister_netdevice(dev); | ||
442 | dev_put(dev); | ||
443 | return err; | ||
444 | } | ||
418 | break; | 445 | break; |
419 | #endif | 446 | #endif |
420 | case VIFF_TUNNEL: | 447 | case VIFF_TUNNEL: |
421 | dev = ipmr_new_tunnel(vifc); | 448 | dev = ipmr_new_tunnel(vifc); |
422 | if (!dev) | 449 | if (!dev) |
423 | return -ENOBUFS; | 450 | return -ENOBUFS; |
451 | err = dev_set_allmulti(dev, 1); | ||
452 | if (err) { | ||
453 | ipmr_del_tunnel(dev, vifc); | ||
454 | dev_put(dev); | ||
455 | return err; | ||
456 | } | ||
424 | break; | 457 | break; |
425 | case 0: | 458 | case 0: |
426 | dev = ip_dev_find(&init_net, vifc->vifc_lcl_addr.s_addr); | 459 | dev = ip_dev_find(&init_net, vifc->vifc_lcl_addr.s_addr); |
427 | if (!dev) | 460 | if (!dev) |
428 | return -EADDRNOTAVAIL; | 461 | return -EADDRNOTAVAIL; |
429 | dev_put(dev); | 462 | err = dev_set_allmulti(dev, 1); |
463 | if (err) { | ||
464 | dev_put(dev); | ||
465 | return err; | ||
466 | } | ||
430 | break; | 467 | break; |
431 | default: | 468 | default: |
432 | return -EINVAL; | 469 | return -EINVAL; |
@@ -435,7 +472,6 @@ static int vif_add(struct vifctl *vifc, int mrtsock) | |||
435 | if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) | 472 | if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) |
436 | return -EADDRNOTAVAIL; | 473 | return -EADDRNOTAVAIL; |
437 | IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++; | 474 | IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++; |
438 | dev_set_allmulti(dev, +1); | ||
439 | ip_rt_multicast_event(in_dev); | 475 | ip_rt_multicast_event(in_dev); |
440 | 476 | ||
441 | /* | 477 | /* |
@@ -458,7 +494,6 @@ static int vif_add(struct vifctl *vifc, int mrtsock) | |||
458 | 494 | ||
459 | /* And finish update writing critical data */ | 495 | /* And finish update writing critical data */ |
460 | write_lock_bh(&mrt_lock); | 496 | write_lock_bh(&mrt_lock); |
461 | dev_hold(dev); | ||
462 | v->dev=dev; | 497 | v->dev=dev; |
463 | #ifdef CONFIG_IP_PIMSM | 498 | #ifdef CONFIG_IP_PIMSM |
464 | if (v->flags&VIFF_REGISTER) | 499 | if (v->flags&VIFF_REGISTER) |
@@ -805,7 +840,7 @@ static void mroute_clean_tables(struct sock *sk) | |||
805 | */ | 840 | */ |
806 | for (i=0; i<maxvif; i++) { | 841 | for (i=0; i<maxvif; i++) { |
807 | if (!(vif_table[i].flags&VIFF_STATIC)) | 842 | if (!(vif_table[i].flags&VIFF_STATIC)) |
808 | vif_delete(i); | 843 | vif_delete(i, 0); |
809 | } | 844 | } |
810 | 845 | ||
811 | /* | 846 | /* |
@@ -918,7 +953,7 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char __user *optval,int opt | |||
918 | if (optname==MRT_ADD_VIF) { | 953 | if (optname==MRT_ADD_VIF) { |
919 | ret = vif_add(&vif, sk==mroute_socket); | 954 | ret = vif_add(&vif, sk==mroute_socket); |
920 | } else { | 955 | } else { |
921 | ret = vif_delete(vif.vifc_vifi); | 956 | ret = vif_delete(vif.vifc_vifi, 0); |
922 | } | 957 | } |
923 | rtnl_unlock(); | 958 | rtnl_unlock(); |
924 | return ret; | 959 | return ret; |
@@ -1097,7 +1132,7 @@ static int ipmr_device_event(struct notifier_block *this, unsigned long event, v | |||
1097 | v=&vif_table[0]; | 1132 | v=&vif_table[0]; |
1098 | for (ct=0;ct<maxvif;ct++,v++) { | 1133 | for (ct=0;ct<maxvif;ct++,v++) { |
1099 | if (v->dev==dev) | 1134 | if (v->dev==dev) |
1100 | vif_delete(ct); | 1135 | vif_delete(ct, 1); |
1101 | } | 1136 | } |
1102 | return NOTIFY_DONE; | 1137 | return NOTIFY_DONE; |
1103 | } | 1138 | } |
@@ -1143,7 +1178,7 @@ static inline int ipmr_forward_finish(struct sk_buff *skb) | |||
1143 | { | 1178 | { |
1144 | struct ip_options * opt = &(IPCB(skb)->opt); | 1179 | struct ip_options * opt = &(IPCB(skb)->opt); |
1145 | 1180 | ||
1146 | IP_INC_STATS_BH(IPSTATS_MIB_OUTFORWDATAGRAMS); | 1181 | IP_INC_STATS_BH(dev_net(skb->dst->dev), IPSTATS_MIB_OUTFORWDATAGRAMS); |
1147 | 1182 | ||
1148 | if (unlikely(opt->optlen)) | 1183 | if (unlikely(opt->optlen)) |
1149 | ip_forward_options(skb); | 1184 | ip_forward_options(skb); |
@@ -1170,8 +1205,8 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi) | |||
1170 | if (vif->flags & VIFF_REGISTER) { | 1205 | if (vif->flags & VIFF_REGISTER) { |
1171 | vif->pkt_out++; | 1206 | vif->pkt_out++; |
1172 | vif->bytes_out+=skb->len; | 1207 | vif->bytes_out+=skb->len; |
1173 | ((struct net_device_stats*)netdev_priv(vif->dev))->tx_bytes += skb->len; | 1208 | vif->dev->stats.tx_bytes += skb->len; |
1174 | ((struct net_device_stats*)netdev_priv(vif->dev))->tx_packets++; | 1209 | vif->dev->stats.tx_packets++; |
1175 | ipmr_cache_report(skb, vifi, IGMPMSG_WHOLEPKT); | 1210 | ipmr_cache_report(skb, vifi, IGMPMSG_WHOLEPKT); |
1176 | kfree_skb(skb); | 1211 | kfree_skb(skb); |
1177 | return; | 1212 | return; |
@@ -1206,7 +1241,7 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi) | |||
1206 | to blackhole. | 1241 | to blackhole. |
1207 | */ | 1242 | */ |
1208 | 1243 | ||
1209 | IP_INC_STATS_BH(IPSTATS_MIB_FRAGFAILS); | 1244 | IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_FRAGFAILS); |
1210 | ip_rt_put(rt); | 1245 | ip_rt_put(rt); |
1211 | goto out_free; | 1246 | goto out_free; |
1212 | } | 1247 | } |
@@ -1230,8 +1265,8 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi) | |||
1230 | if (vif->flags & VIFF_TUNNEL) { | 1265 | if (vif->flags & VIFF_TUNNEL) { |
1231 | ip_encap(skb, vif->local, vif->remote); | 1266 | ip_encap(skb, vif->local, vif->remote); |
1232 | /* FIXME: extra output firewall step used to be here. --RR */ | 1267 | /* FIXME: extra output firewall step used to be here. --RR */ |
1233 | ((struct ip_tunnel *)netdev_priv(vif->dev))->stat.tx_packets++; | 1268 | vif->dev->stats.tx_packets++; |
1234 | ((struct ip_tunnel *)netdev_priv(vif->dev))->stat.tx_bytes+=skb->len; | 1269 | vif->dev->stats.tx_bytes += skb->len; |
1235 | } | 1270 | } |
1236 | 1271 | ||
1237 | IPCB(skb)->flags |= IPSKB_FORWARDED; | 1272 | IPCB(skb)->flags |= IPSKB_FORWARDED; |
@@ -1487,8 +1522,8 @@ int pim_rcv_v1(struct sk_buff * skb) | |||
1487 | skb->pkt_type = PACKET_HOST; | 1522 | skb->pkt_type = PACKET_HOST; |
1488 | dst_release(skb->dst); | 1523 | dst_release(skb->dst); |
1489 | skb->dst = NULL; | 1524 | skb->dst = NULL; |
1490 | ((struct net_device_stats*)netdev_priv(reg_dev))->rx_bytes += skb->len; | 1525 | reg_dev->stats.rx_bytes += skb->len; |
1491 | ((struct net_device_stats*)netdev_priv(reg_dev))->rx_packets++; | 1526 | reg_dev->stats.rx_packets++; |
1492 | nf_reset(skb); | 1527 | nf_reset(skb); |
1493 | netif_rx(skb); | 1528 | netif_rx(skb); |
1494 | dev_put(reg_dev); | 1529 | dev_put(reg_dev); |
@@ -1542,8 +1577,8 @@ static int pim_rcv(struct sk_buff * skb) | |||
1542 | skb->ip_summed = 0; | 1577 | skb->ip_summed = 0; |
1543 | skb->pkt_type = PACKET_HOST; | 1578 | skb->pkt_type = PACKET_HOST; |
1544 | dst_release(skb->dst); | 1579 | dst_release(skb->dst); |
1545 | ((struct net_device_stats*)netdev_priv(reg_dev))->rx_bytes += skb->len; | 1580 | reg_dev->stats.rx_bytes += skb->len; |
1546 | ((struct net_device_stats*)netdev_priv(reg_dev))->rx_packets++; | 1581 | reg_dev->stats.rx_packets++; |
1547 | skb->dst = NULL; | 1582 | skb->dst = NULL; |
1548 | nf_reset(skb); | 1583 | nf_reset(skb); |
1549 | netif_rx(skb); | 1584 | netif_rx(skb); |
@@ -1887,16 +1922,36 @@ static struct net_protocol pim_protocol = { | |||
1887 | * Setup for IP multicast routing | 1922 | * Setup for IP multicast routing |
1888 | */ | 1923 | */ |
1889 | 1924 | ||
1890 | void __init ip_mr_init(void) | 1925 | int __init ip_mr_init(void) |
1891 | { | 1926 | { |
1927 | int err; | ||
1928 | |||
1892 | mrt_cachep = kmem_cache_create("ip_mrt_cache", | 1929 | mrt_cachep = kmem_cache_create("ip_mrt_cache", |
1893 | sizeof(struct mfc_cache), | 1930 | sizeof(struct mfc_cache), |
1894 | 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, | 1931 | 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, |
1895 | NULL); | 1932 | NULL); |
1933 | if (!mrt_cachep) | ||
1934 | return -ENOMEM; | ||
1935 | |||
1896 | setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0); | 1936 | setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0); |
1897 | register_netdevice_notifier(&ip_mr_notifier); | 1937 | err = register_netdevice_notifier(&ip_mr_notifier); |
1938 | if (err) | ||
1939 | goto reg_notif_fail; | ||
1898 | #ifdef CONFIG_PROC_FS | 1940 | #ifdef CONFIG_PROC_FS |
1899 | proc_net_fops_create(&init_net, "ip_mr_vif", 0, &ipmr_vif_fops); | 1941 | err = -ENOMEM; |
1900 | proc_net_fops_create(&init_net, "ip_mr_cache", 0, &ipmr_mfc_fops); | 1942 | if (!proc_net_fops_create(&init_net, "ip_mr_vif", 0, &ipmr_vif_fops)) |
1943 | goto proc_vif_fail; | ||
1944 | if (!proc_net_fops_create(&init_net, "ip_mr_cache", 0, &ipmr_mfc_fops)) | ||
1945 | goto proc_cache_fail; | ||
1901 | #endif | 1946 | #endif |
1947 | return 0; | ||
1948 | reg_notif_fail: | ||
1949 | kmem_cache_destroy(mrt_cachep); | ||
1950 | #ifdef CONFIG_PROC_FS | ||
1951 | proc_vif_fail: | ||
1952 | unregister_netdevice_notifier(&ip_mr_notifier); | ||
1953 | proc_cache_fail: | ||
1954 | proc_net_remove(&init_net, "ip_mr_vif"); | ||
1955 | #endif | ||
1956 | return err; | ||
1902 | } | 1957 | } |