static struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v) { struct net_device *dev; dev = __dev_get_by_name(net, "tunl0"); if (dev) { const struct net_device_ops *ops = dev->netdev_ops; int err; struct ifreq ifr; struct ip_tunnel_parm p; struct in_device *in_dev; memset(&p, 0, sizeof(p)); p.iph.daddr = v->vifc_rmt_addr.s_addr; p.iph.saddr = v->vifc_lcl_addr.s_addr; p.iph.version = 4; p.iph.ihl = 5; p.iph.protocol = IPPROTO_IPIP; sprintf(p.name, "dvmrp%d", v->vifc_vifi); ifr.ifr_ifru.ifru_data = (__force void __user *)&p; if (ops->ndo_do_ioctl) { mm_segment_t oldfs = get_fs(); set_fs(KERNEL_DS); err = ops->ndo_do_ioctl(dev, &ifr, SIOCADDTUNNEL); set_fs(oldfs); } else err = -EOPNOTSUPP; dev = NULL; if (err == 0 && (dev = __dev_get_by_name(net, p.name)) != NULL) { dev->flags |= IFF_MULTICAST; in_dev = __in_dev_get_rtnl(dev); if (in_dev == NULL) goto failure; ipv4_devconf_setall(in_dev); IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0; if (dev_open(dev)) goto failure; dev_hold(dev); } } return dev; failure: /* allow the register to be completed before unregistering. */ rtnl_unlock(); rtnl_lock(); unregister_netdevice(dev); return NULL; }
static int vif_delete(struct net *net, int vifi, int notify, struct list_head *head) { struct vif_device *v; struct net_device *dev; struct in_device *in_dev; if (vifi < 0 || vifi >= net->ipv4.maxvif) return -EADDRNOTAVAIL; v = &net->ipv4.vif_table[vifi]; write_lock_bh(&mrt_lock); dev = v->dev; v->dev = NULL; if (!dev) { write_unlock_bh(&mrt_lock); return -EADDRNOTAVAIL; } #ifdef CONFIG_IP_PIMSM if (vifi == net->ipv4.mroute_reg_vif_num) net->ipv4.mroute_reg_vif_num = -1; #endif if (vifi+1 == net->ipv4.maxvif) { int tmp; for (tmp=vifi-1; tmp>=0; tmp--) { if (VIF_EXISTS(net, tmp)) break; } net->ipv4.maxvif = tmp+1; } write_unlock_bh(&mrt_lock); dev_set_allmulti(dev, -1); if ((in_dev = __in_dev_get_rtnl(dev)) != NULL) { IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)--; ip_rt_multicast_event(in_dev); } if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER) && !notify) unregister_netdevice_queue(dev, head); dev_put(dev); return 0; }
static struct net_device *ipmr_reg_vif(struct net *net) { struct net_device *dev; struct in_device *in_dev; dev = alloc_netdev(0, "pimreg", reg_vif_setup); if (dev == NULL) return NULL; dev_net_set(dev, net); if (register_netdevice(dev)) { free_netdev(dev); return NULL; } dev->iflink = 0; rcu_read_lock(); if ((in_dev = __in_dev_get_rcu(dev)) == NULL) { rcu_read_unlock(); goto failure; } ipv4_devconf_setall(in_dev); IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0; rcu_read_unlock(); if (dev_open(dev)) goto failure; dev_hold(dev); return dev; failure: /* allow the register to be completed before unregistering. */ rtnl_unlock(); rtnl_lock(); unregister_netdevice(dev); return NULL; }
static struct in_device *inetdev_init(struct net_device *dev) { struct in_device *in_dev; ASSERT_RTNL(); in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL); if (!in_dev) goto out; memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt, sizeof(in_dev->cnf)); in_dev->cnf.sysctl = NULL; in_dev->dev = dev; in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl); if (!in_dev->arp_parms) goto out_kfree; if (IPV4_DEVCONF(in_dev->cnf, FORWARDING)) dev_disable_lro(dev); /* Reference in_dev->dev */ dev_hold(dev); /* Account for reference dev->ip_ptr (below) */ in_dev_hold(in_dev); devinet_sysctl_register(in_dev); ip_mc_init_dev(in_dev); if (dev->flags & IFF_UP) ip_mc_up(in_dev); /* we can receive as soon as ip_ptr is set -- do this last */ rcu_assign_pointer(dev->ip_ptr, in_dev); out: return in_dev; out_kfree: kfree(in_dev); in_dev = NULL; goto out; }
static int vif_add(struct net *net, struct vifctl *vifc, int mrtsock) { int vifi = vifc->vifc_vifi; struct vif_device *v = &net->ipv4.vif_table[vifi]; struct net_device *dev; struct in_device *in_dev; int err; /* Is vif busy ? */ if (VIF_EXISTS(net, vifi)) return -EADDRINUSE; switch (vifc->vifc_flags) { #ifdef CONFIG_IP_PIMSM case VIFF_REGISTER: /* * Special Purpose VIF in PIM * All the packets will be sent to the daemon */ if (net->ipv4.mroute_reg_vif_num >= 0) return -EADDRINUSE; dev = ipmr_reg_vif(net); if (!dev) return -ENOBUFS; err = dev_set_allmulti(dev, 1); if (err) { unregister_netdevice(dev); dev_put(dev); return err; } break; #endif case VIFF_TUNNEL: dev = ipmr_new_tunnel(net, vifc); if (!dev) return -ENOBUFS; err = dev_set_allmulti(dev, 1); if (err) { ipmr_del_tunnel(dev, vifc); dev_put(dev); return err; } break; case VIFF_USE_IFINDEX: case 0: if (vifc->vifc_flags == VIFF_USE_IFINDEX) { dev = dev_get_by_index(net, vifc->vifc_lcl_ifindex); if (dev && dev->ip_ptr == NULL) { dev_put(dev); return -EADDRNOTAVAIL; } } else dev = ip_dev_find(net, vifc->vifc_lcl_addr.s_addr); if (!dev) return -EADDRNOTAVAIL; err = dev_set_allmulti(dev, 1); if (err) { dev_put(dev); return err; } break; default: return -EINVAL; } if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) { dev_put(dev); return -EADDRNOTAVAIL; } IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++; ip_rt_multicast_event(in_dev); /* * Fill in the VIF structures */ v->rate_limit = vifc->vifc_rate_limit; v->local = vifc->vifc_lcl_addr.s_addr; v->remote = vifc->vifc_rmt_addr.s_addr; v->flags = vifc->vifc_flags; if (!mrtsock) v->flags |= VIFF_STATIC; v->threshold = vifc->vifc_threshold; v->bytes_in = 0; v->bytes_out = 0; v->pkt_in = 0; v->pkt_out = 0; v->link = dev->ifindex; if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER)) v->link = dev->iflink; /* And finish update writing critical data */ write_lock_bh(&mrt_lock); v->dev = dev; #ifdef CONFIG_IP_PIMSM if (v->flags&VIFF_REGISTER) net->ipv4.mroute_reg_vif_num = vifi; #endif if (vifi+1 > net->ipv4.maxvif) net->ipv4.maxvif = vifi+1; write_unlock_bh(&mrt_lock); return 0; }