static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
			  const struct flowi *fl)
{
	struct rt6_info *rt = (struct rt6_info*)xdst->route;

	xdst->u.dst.dev = dev;
	dev_hold(dev);

	xdst->u.rt6.rt6i_idev = in6_dev_get(dev);
	if (!xdst->u.rt6.rt6i_idev)
		return -ENODEV;

	xdst->u.rt6.rt6i_peer = rt->rt6i_peer;
	if (rt->rt6i_peer)
		atomic_inc(&rt->rt6i_peer->refcnt);

	xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST |
						   RTF_LOCAL);
	xdst->u.rt6.rt6i_metric = rt->rt6i_metric;
	xdst->u.rt6.rt6i_node = rt->rt6i_node;
	if (rt->rt6i_node)
		xdst->route_cookie = rt->rt6i_node->fn_sernum;
	xdst->u.rt6.rt6i_gateway = rt->rt6i_gateway;
	xdst->u.rt6.rt6i_dst = rt->rt6i_dst;
	xdst->u.rt6.rt6i_src = rt->rt6i_src;

	return 0;
}
static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev)
{
	struct rt6_info *rt = (struct rt6_info*)xdst->route;

	xdst->u.dst.dev = dev;
	dev_hold(dev);

	xdst->u.rt6.rt6i_idev = in6_dev_get(rt->u.dst.dev);
	if (!xdst->u.rt6.rt6i_idev)
		return -ENODEV;

	/* Sheit... I remember I did this right. Apparently,
	 * it was magically lost, so this code needs audit */
	xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST |
						   RTF_LOCAL);
	xdst->u.rt6.rt6i_metric = rt->rt6i_metric;
	xdst->u.rt6.rt6i_node = rt->rt6i_node;
	if (rt->rt6i_node)
		xdst->route_cookie = rt->rt6i_node->fn_sernum;
	xdst->u.rt6.rt6i_gateway = rt->rt6i_gateway;
	xdst->u.rt6.rt6i_dst = rt->rt6i_dst;
	xdst->u.rt6.rt6i_src = rt->rt6i_src;

	return 0;
}
Exemple #3
0
static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
{
	struct inet6_dev *idev = in6_dev_get(skb->dev);
	if (skb->ip_summed != CHECKSUM_UNNECESSARY) {
		if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) {
			UDP6_INC_STATS_BH(UdpInErrors);
			IP6_INC_STATS_BH(idev,Ip6InDiscards);
			if (idev)
				in6_dev_put(idev);
			kfree_skb(skb);
			return 0;
		}
		skb->ip_summed = CHECKSUM_UNNECESSARY;
	}
	if (sock_queue_rcv_skb(sk,skb)<0) {
		UDP6_INC_STATS_BH(UdpInErrors);
		IP6_INC_STATS_BH(idev,Ip6InDiscards);
		if (idev)
			in6_dev_put(idev);
		kfree_skb(skb);
		return 0;
	}
  	IP6_INC_STATS_BH(idev,Ip6InDelivers);
	UDP6_INC_STATS_BH(UdpInDatagrams);

	if (idev)
		in6_dev_put(idev);
	return 0;
}
Exemple #4
0
/*
 *	check if the interface/address pair is valid
 */
int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *addr)
{
	struct inet6_dev *idev;
	struct ifmcaddr6 *mc;
#ifdef CONFIG_IPV6_MLD6_DEBUG
	char abuf[128];
	in6_ntop(addr, abuf);

	MDBG3((KERN_DEBUG
		"ipv6_chk_mcast_addr(dev=%p(%s), addr=%s)\n",
		dev, dev->name ? dev->name : "<null>", abuf));
#endif

	idev = in6_dev_get(dev);
	if (idev) {
		read_lock_bh(&idev->lock);
		for (mc = idev->mc_list; mc; mc=mc->next) {
			if (ipv6_addr_cmp(&mc->mca_addr, addr) == 0) {
				read_unlock_bh(&idev->lock);
				in6_dev_put(idev);
				return 1;
			}
		}
		read_unlock_bh(&idev->lock);
		in6_dev_put(idev);
	}
	return 0;
}
static void rmnet_usb_setup(struct net_device *dev)
{
#ifdef DISABLE_RMNET_USB_IPV6_ACCEPT_RA_DEFRTR
	struct inet6_dev *idev = NULL;
#endif //DISABLE_RMNET_USB_IPV6_ACCEPT_RA_DEFRTR

	/* Using Ethernet mode by default */
	dev->netdev_ops = &rmnet_usb_ops_ether;

	/* set this after calling ether_setup */
	dev->mtu = RMNET_DATA_LEN;

	dev->needed_headroom = HEADROOM_FOR_QOS;
	random_ether_addr(dev->dev_addr);
	dev->watchdog_timeo = 1000; /* 10 seconds? */

#ifdef DISABLE_RMNET_USB_IPV6_ACCEPT_RA_DEFRTR
	idev = in6_dev_get(dev);
	if (idev)
	{
		idev->cnf.accept_ra_defrtr = 0;
		if (idev->dev)
			pr_info("net_device:%s set accept_ra_defrtr:%d\n", idev->dev->name, idev->cnf.accept_ra_defrtr);
	}

	if (idev)
		in6_dev_put(idev);
#endif //DISABLE_RMNET_USB_IPV6_ACCEPT_RA_DEFRTR
}
Exemple #6
0
/*
 *	device multicast group del
 */
int ipv6_dev_mc_dec(struct net_device *dev, struct in6_addr *addr)
{
	struct inet6_dev *idev;
	struct ifmcaddr6 *ma, **map;

	idev = in6_dev_get(dev);
	if (idev == NULL)
		return -ENODEV;

	write_lock_bh(&idev->lock);
	for (map = &idev->mc_list; (ma=*map) != NULL; map = &ma->next) {
		if (ipv6_addr_cmp(&ma->mca_addr, addr) == 0) {
			if (--ma->mca_users == 0) {
				*map = ma->next;
				write_unlock_bh(&idev->lock);

				igmp6_group_dropped(ma);

				ma_put(ma);
				in6_dev_put(idev);
				return 0;
			}
			write_unlock_bh(&idev->lock);
			in6_dev_put(idev);
			return 0;
		}
	}
	write_unlock_bh(&idev->lock);
	in6_dev_put(idev);

	return -ENOENT;
}
Exemple #7
0
static void xfrm6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
			     int unregister)
{
	struct xfrm_dst *xdst;

	if (!unregister)
		return;

	xdst = (struct xfrm_dst *)dst;
	if (xdst->u.rt6.rt6i_idev->dev == dev) {
		struct inet6_dev *loopback_idev = in6_dev_get(&loopback_dev);
		BUG_ON(!loopback_idev);

		do {
			in6_dev_put(xdst->u.rt6.rt6i_idev);
			xdst->u.rt6.rt6i_idev = loopback_idev;
			in6_dev_hold(loopback_idev);
			xdst = (struct xfrm_dst *)xdst->u.dst.child;
		} while (xdst->u.dst.xfrm);

		__in6_dev_put(loopback_idev);
	}

	xfrm_dst_ifdown(dst, dev);
}
Exemple #8
0
static int igmp6_read_proc(char *buffer, char **start, off_t offset,
			   int length, int *eof, void *data)
{
	off_t pos=0, begin=0;
	struct ifmcaddr6 *im;
	int len=0;
	struct net_device *dev;
	
	read_lock(&dev_base_lock);
	for (dev = dev_base; dev; dev = dev->next) {
		struct inet6_dev *idev;

		if ((idev = in6_dev_get(dev)) == NULL)
			continue;

		read_lock_bh(&idev->lock);
		for (im = idev->mc_list; im; im = im->next) {
			int i;

			len += sprintf(buffer+len,"%-4d %-15s ", dev->ifindex, dev->name);

			for (i=0; i<16; i++)
				len += sprintf(buffer+len, "%02x", im->mca_addr.s6_addr[i]);

			len+=sprintf(buffer+len,
				     " %5d %08X %ld\n",
				     im->mca_users,
				     im->mca_flags,
				     (im->mca_flags&MAF_TIMER_RUNNING) ? im->mca_timer.expires-jiffies : 0);

			pos=begin+len;
			if (pos < offset) {
				len=0;
				begin=pos;
			}
			if (pos > offset+length) {
				read_unlock_bh(&idev->lock);
				in6_dev_put(idev);
				goto done;
			}
		}
		read_unlock_bh(&idev->lock);
		in6_dev_put(idev);
	}
	*eof = 1;

done:
	read_unlock(&dev_base_lock);

	*start=buffer+(offset-begin);
	len-=(offset-begin);
	if(len>length)
		len=length;
	if (len<0)
		len=0;
	return len;
}
Exemple #9
0
/*
 *	device multicast group inc (add if not found)
 */
int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr)
{
	struct ifmcaddr6 *mc;
	struct inet6_dev *idev;

	idev = in6_dev_get(dev);

	if (idev == NULL)
		return -EINVAL;

	write_lock_bh(&idev->lock);
	if (idev->dead) {
		write_unlock_bh(&idev->lock);
		in6_dev_put(idev);
		return -ENODEV;
	}

	for (mc = idev->mc_list; mc; mc = mc->next) {
		if (ipv6_addr_cmp(&mc->mca_addr, addr) == 0) {
			mc->mca_users++;
			write_unlock_bh(&idev->lock);
			in6_dev_put(idev);
			return 0;
		}
	}

	/*
	 *	not found: create a new one.
	 */

	mc = kmalloc(sizeof(struct ifmcaddr6), GFP_ATOMIC);

	if (mc == NULL) {
		write_unlock_bh(&idev->lock);
		in6_dev_put(idev);
		return -ENOMEM;
	}

	memset(mc, 0, sizeof(struct ifmcaddr6));
	mc->mca_timer.function = igmp6_timer_handler;
	mc->mca_timer.data = (unsigned long) mc;

	memcpy(&mc->mca_addr, addr, sizeof(struct in6_addr));
	mc->idev = idev;
	mc->mca_users = 1;
	atomic_set(&mc->mca_refcnt, 2);
	mc->mca_lock = SPIN_LOCK_UNLOCKED;

	mc->next = idev->mc_list;
	idev->mc_list = mc;
	write_unlock_bh(&idev->lock);

	igmp6_group_added(mc);
	ma_put(mc);
	return 0;
}
int ip6_pkt_discard(struct sk_buff *skb)
{
	struct inet6_dev *idev = in6_dev_get(skb->dev);
	IP6_INC_STATS(idev,Ip6OutNoRoutes);
	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, skb->dev);
	if (idev)
		in6_dev_put(idev);
	kfree_skb(skb);
	return 0;
}
Exemple #11
0
static int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr)
{
	int ret;
	struct inet6_dev *idev = in6_dev_get(dev);
	if (idev == NULL)
		return -ENODEV;
	ret = __ipv6_dev_ac_dec(idev, addr);
	in6_dev_put(idev);
	return ret;
}
Exemple #12
0
static int ipv6_get_mtu(struct net_device *dev)
{
	int mtu = IPV6_MIN_MTU;
	struct inet6_dev *idev;

	idev = in6_dev_get(dev);
	if (idev) {
		mtu = idev->cnf.mtu6;
		in6_dev_put(idev);
	}
	return mtu;
}
Exemple #13
0
static int ipv6_get_hoplimit(struct net_device *dev)
{
	int hoplimit = ipv6_devconf.hop_limit;
	struct inet6_dev *idev;

	idev = in6_dev_get(dev);
	if (idev) {
		hoplimit = idev->cnf.hop_limit;
		in6_dev_put(idev);
	}
	return hoplimit;
}
Exemple #14
0
static int vrf_rt6_create(struct net_device *dev)
{
	int flags = DST_HOST | DST_NOPOLICY | DST_NOXFRM | DST_NOCACHE;
	struct net_vrf *vrf = netdev_priv(dev);
	struct net *net = dev_net(dev);
	struct fib6_table *rt6i_table;
	struct rt6_info *rt6, *rt6_local;
	int rc = -ENOMEM;

	/* IPv6 can be CONFIG enabled and then disabled runtime */
	if (!ipv6_mod_enabled())
		return 0;

	rt6i_table = fib6_new_table(net, vrf->tb_id);
	if (!rt6i_table)
		goto out;

	/* create a dst for routing packets out a VRF device */
	rt6 = ip6_dst_alloc(net, dev, flags);
	if (!rt6)
		goto out;

	dst_hold(&rt6->dst);

	rt6->rt6i_table = rt6i_table;
	rt6->dst.output	= vrf_output6;

	/* create a dst for local routing - packets sent locally
	 * to local address via the VRF device as a loopback
	 */
	rt6_local = ip6_dst_alloc(net, dev, flags);
	if (!rt6_local) {
		dst_release(&rt6->dst);
		goto out;
	}

	dst_hold(&rt6_local->dst);

	rt6_local->rt6i_idev  = in6_dev_get(dev);
	rt6_local->rt6i_flags = RTF_UP | RTF_NONEXTHOP | RTF_LOCAL;
	rt6_local->rt6i_table = rt6i_table;
	rt6_local->dst.input  = ip6_input;

	rcu_assign_pointer(vrf->rt6, rt6);
	rcu_assign_pointer(vrf->rt6_local, rt6_local);

	rc = 0;
out:
	return rc;
}
Exemple #15
0
static int ndisc_constructor(struct neighbour *neigh)
{
	struct in6_addr *addr = (struct in6_addr*)&neigh->primary_key;
	struct net_device *dev = neigh->dev;
	struct inet6_dev *in6_dev;
	struct neigh_parms *parms;
	int is_multicast = ipv6_addr_is_multicast(addr);

	rcu_read_lock();
	in6_dev = in6_dev_get(dev);
	if (in6_dev == NULL) {
		rcu_read_unlock();
		return -EINVAL;
	}

	parms = in6_dev->nd_parms;
	__neigh_parms_put(neigh->parms);
	neigh->parms = neigh_parms_clone(parms);
	rcu_read_unlock();

	neigh->type = is_multicast ? RTN_MULTICAST : RTN_UNICAST;
	if (dev->hard_header == NULL) {
		neigh->nud_state = NUD_NOARP;
		neigh->ops = &ndisc_direct_ops;
		neigh->output = neigh->ops->queue_xmit;
	} else {
		if (is_multicast) {
			neigh->nud_state = NUD_NOARP;
			ndisc_mc_map(addr, neigh->ha, dev, 1);
		} else if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) {
			neigh->nud_state = NUD_NOARP;
			memcpy(neigh->ha, dev->dev_addr, dev->addr_len);
			if (dev->flags&IFF_LOOPBACK)
				neigh->type = RTN_LOCAL;
		} else if (dev->flags&IFF_POINTOPOINT) {
			neigh->nud_state = NUD_NOARP;
			memcpy(neigh->ha, dev->broadcast, dev->addr_len);
		}
		if (dev->hard_header_cache)
			neigh->ops = &ndisc_hh_ops;
		else
			neigh->ops = &ndisc_generic_ops;
		if (neigh->nud_state&NUD_VALID)
			neigh->output = neigh->ops->connected_output;
		else
			neigh->output = neigh->ops->output;
	}
	in6_dev_put(in6_dev);
	return 0;
}
/* Some devices are known to send Neigbor Solicitation messages and
 * require Neigbor Advertisement replies.  The IPv6 core will not
 * respond since IFF_NOARP is set, so we must handle them ourselves.
 */
static void do_neigh_solicit(struct usbnet *dev, u8 *buf, u16 tci)
{
	struct ipv6hdr *iph = (void *)buf;
	struct nd_msg *msg = (void *)(iph + 1);
	struct net_device *netdev;
	struct inet6_dev *in6_dev;
	bool is_router;

	/* we'll only respond to requests from unicast addresses to
	 * our solicited node addresses.
	 */
	if (!ipv6_addr_is_solict_mult(&iph->daddr) ||
	    !(ipv6_addr_type(&iph->saddr) & IPV6_ADDR_UNICAST))
		return;

	/* need to send the NA on the VLAN dev, if any */
	rcu_read_lock();
	if (tci) {
		netdev = __vlan_find_dev_deep_rcu(dev->net, htons(ETH_P_8021Q),
						  tci);
		if (!netdev) {
			rcu_read_unlock();
			return;
		}
	} else {
		netdev = dev->net;
	}
	dev_hold(netdev);
	rcu_read_unlock();

	in6_dev = in6_dev_get(netdev);
	if (!in6_dev)
		goto out;
	is_router = !!in6_dev->cnf.forwarding;
	in6_dev_put(in6_dev);

	/* ipv6_stub != NULL if in6_dev_get returned an inet6_dev */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
	ipv6_stub->ndisc_send_na(netdev, &iph->saddr, &msg->target,
				 is_router /* router */,
				 true /* solicited */,
				 false /* override */,
				 true /* inc_opt */);
#else
	ipv6_stub->ndisc_send_na(netdev, NULL, &iph->saddr, &msg->target,
				 is_router, true, false, true);
#endif
out:
	dev_put(netdev);
}
Exemple #17
0
void ndisc_send_skb(struct sk_buff *skb,
		    struct net_device *dev,
		    struct neighbour *neigh,
		    const struct in6_addr *daddr,
		    const struct in6_addr *saddr,
		    struct icmp6hdr *icmp6h)
{
	struct flowi fl;
	struct dst_entry *dst;
	struct net *net = dev_net(dev);
	struct sock *sk = net->ipv6.ndisc_sk;
	struct inet6_dev *idev;
	int err;
	u8 type;

	type = icmp6h->icmp6_type;

	icmpv6_flow_init(sk, &fl, type, saddr, daddr, dev->ifindex);

	dst = icmp6_dst_alloc(dev, neigh, daddr);
	if (!dst) {
		kfree_skb(skb);
		return;
	}

	err = xfrm_lookup(net, &dst, &fl, NULL, 0);
	if (err < 0) {
		kfree_skb(skb);
		return;
	}

	skb_dst_set(skb, dst);

	idev = in6_dev_get(dst->dev);
	IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);

	err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,
		      dst_output);
	if (!err) {
		ICMP6MSGOUT_INC_STATS(net, idev, type);
		ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
	}

	if (likely(idev != NULL))
		in6_dev_put(idev);
}
Exemple #18
0
/*
 *	check if the interface has this anycast address
 */
static int ipv6_chk_acast_dev(struct net_device *dev, struct in6_addr *addr)
{
	struct inet6_dev *idev;
	struct ifacaddr6 *aca;

	idev = in6_dev_get(dev);
	if (idev) {
		read_lock_bh(&idev->lock);
		for (aca = idev->ac_list; aca; aca = aca->aca_next)
			if (ipv6_addr_equal(&aca->aca_addr, addr))
				break;
		read_unlock_bh(&idev->lock);
		in6_dev_put(idev);
		return aca != NULL;
	}
	return 0;
}
Exemple #19
0
/*
 * Assign bond->master_ipv6 to the next IPv6 address in the list, or
 * zero it out if there are none.
 */
static void bond_glean_dev_ipv6(struct net_device *dev, struct in6_addr *addr)
{
	struct inet6_dev *idev;

	if (!dev)
		return;

	idev = in6_dev_get(dev);
	if (!idev)
		return;

	read_lock_bh(&idev->lock);
	if (!list_empty(&idev->addr_list)) {
		struct inet6_ifaddr *ifa
			= list_first_entry(&idev->addr_list,
					   struct inet6_ifaddr, if_list);
		ipv6_addr_copy(addr, &ifa->addr);
	} else
Exemple #20
0
static void inc_stats_ipv6(struct sk_buff *skb, int field)
{
	struct inet6_dev *idev;

	if (is_error(inc_stats_validate(skb))) {
		/* Maybe we can fall back to increase the stat on the other skb's dev... */
		skb = skb_original_skb(skb);
		if (is_error(inc_stats_validate(skb)))
			return;
	}
	idev = in6_dev_get(skb->dev);
	if (!idev)
		return;

	IP6_INC_STATS_BH(dev_net(skb->dev), idev, field);

	in6_dev_put(idev);
}
Exemple #21
0
int igmp6_event_query(struct sk_buff *skb, struct icmp6hdr *hdr, int len)
{
	struct ifmcaddr6 *ma;
	struct in6_addr *addrp;
	unsigned long resptime;
	struct inet6_dev *idev;


	if (len < sizeof(struct icmp6hdr) + sizeof(struct in6_addr))
		return -EINVAL;

	/* Drop queries with not link local source */
	if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr)&IPV6_ADDR_LINKLOCAL))
		return -EINVAL;

	resptime = ntohs(hdr->icmp6_maxdelay);
	/* Translate milliseconds to jiffies */
	resptime = (resptime<<10)/(1024000/HZ);

	addrp = (struct in6_addr *) (hdr + 1);

	idev = in6_dev_get(skb->dev);

	if (idev == NULL)
		return 0;

	read_lock(&idev->lock);
	if (ipv6_addr_any(addrp)) {
		for (ma = idev->mc_list; ma; ma=ma->next)
			igmp6_group_queried(ma, resptime);
	} else {
		for (ma = idev->mc_list; ma; ma=ma->next) {
			if (ipv6_addr_cmp(addrp, &ma->mca_addr) == 0) {
				igmp6_group_queried(ma, resptime);
				break;
			}
		}
	}
	read_unlock(&idev->lock);
	in6_dev_put(idev);

	return 0;
}
Exemple #22
0
void ndisc_send_skb(struct sk_buff *skb,
		    struct net_device *dev,
		    struct neighbour *neigh,
		    struct in6_addr *daddr,
		    struct in6_addr *saddr,
		    struct icmp6hdr *icmp6h)
{
	struct flowi fl;
	struct dst_entry *dst;
	struct inet6_dev *idev;
	int err;
	u8 type;

	type = icmp6h->icmp6_type;

	ndisc_flow_init(&fl, icmp6h->icmp6_type, saddr, daddr, dev->ifindex);

	dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output);
	if (!dst) {
		kfree_skb(skb);
		return;
	}

	err = xfrm_lookup(&dst, &fl, NULL, 0);
	if (err < 0) {
		kfree_skb(skb);
		return;
	}

	skb->dst = dst;

	idev = in6_dev_get(dst->dev);
	IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);

	err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output);
	if (!err) {
		ICMP6_INC_STATS(idev, type);
		ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);
	}

	if (likely(idev != NULL))
		in6_dev_put(idev);
}
Exemple #23
0
int igmp6_event_report(struct sk_buff *skb, struct icmp6hdr *hdr, int len)
{
	struct ifmcaddr6 *ma;
	struct in6_addr *addrp;
	struct inet6_dev *idev;

	/* Our own report looped back. Ignore it. */
	if (skb->pkt_type == PACKET_LOOPBACK)
		return 0;

	if (len < sizeof(struct icmp6hdr) + sizeof(struct in6_addr))
		return -EINVAL;

	/* Drop reports with not link local source */
	if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr)&IPV6_ADDR_LINKLOCAL))
		return -EINVAL;

	addrp = (struct in6_addr *) (hdr + 1);

	idev = in6_dev_get(skb->dev);
	if (idev == NULL)
		return -ENODEV;

	/*
	 *	Cancel the timer for this group
	 */

	read_lock(&idev->lock);
	for (ma = idev->mc_list; ma; ma=ma->next) {
		if (ipv6_addr_cmp(&ma->mca_addr, addrp) == 0) {
			spin_lock(&ma->mca_lock);
			if (del_timer(&ma->mca_timer))
				atomic_dec(&ma->mca_refcnt);
			ma->mca_flags &= ~(MAF_LAST_REPORTER|MAF_TIMER_RUNNING);
			spin_unlock(&ma->mca_lock);
			break;
		}
	}
	read_unlock(&idev->lock);
	in6_dev_put(idev);
	return 0;
}
Exemple #24
0
/*
 *	check if the interface/address pair is valid
 */
int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *addr)
{
	struct inet6_dev *idev;
	struct ifmcaddr6 *mc;

	idev = in6_dev_get(dev);
	if (idev) {
		read_lock_bh(&idev->lock);
		for (mc = idev->mc_list; mc; mc=mc->next) {
			if (ipv6_addr_cmp(&mc->mca_addr, addr) == 0) {
				read_unlock_bh(&idev->lock);
				in6_dev_put(idev);
				return 1;
			}
		}
		read_unlock_bh(&idev->lock);
		in6_dev_put(idev);
	}
	return 0;
}
Exemple #25
0
/*
 *	device multicast group del
 */
int ipv6_dev_mc_dec(struct net_device *dev, struct in6_addr *addr)
{
	struct inet6_dev *idev;
	struct ifmcaddr6 *ma, **map;

#ifdef CONFIG_IPV6_MLD6_DEBUG
	char abuf[128];
	in6_ntop(addr, abuf);

	MDBG3((KERN_DEBUG
		"ipv6_dev_mc_dec(dev=%p(%s), addr=%s)\n",
		dev, dev->name ? dev->name : "<null>", abuf));
#endif

	idev = in6_dev_get(dev);
	if (idev == NULL)
		return -ENODEV;

	write_lock_bh(&idev->lock);
	for (map = &idev->mc_list; (ma=*map) != NULL; map = &ma->next) {
		if (ipv6_addr_cmp(&ma->mca_addr, addr) == 0) {
			if (--ma->mca_users == 0) {
				*map = ma->next;
				write_unlock_bh(&idev->lock);

				igmp6_group_dropped(ma);

				ma_put(ma);
				in6_dev_put(idev);
				return 0;
			}
			write_unlock_bh(&idev->lock);
			in6_dev_put(idev);
			return 0;
		}
	}
	write_unlock_bh(&idev->lock);
	in6_dev_put(idev);

	return -ENOENT;
}
Exemple #26
0
static void ip6_frag_expire(unsigned long data)
{
	struct frag_queue *fq = (struct frag_queue *) data;
	struct net_device *dev;
	struct inet6_dev *idev;

	spin_lock(&fq->lock);

	if (fq->last_in & COMPLETE)
		goto out;

	fq_kill(fq);

	dev = dev_get_by_index(fq->iif);
	idev = dev ? in6_dev_get(dev) : NULL;

	IP6_INC_STATS_BH(idev,Ip6ReasmTimeout);
	IP6_INC_STATS_BH(idev,Ip6ReasmFails);

	/* Send error only if the first segment arrived. */
	if (fq->last_in&FIRST_IN && fq->fragments) {
		/*
		   But use as source device on which LAST ARRIVED
		   segment was received. And do not use fq->dev
		   pointer directly, device might already disappeared.
		 */
		if (dev) {
			fq->fragments->dev = dev;
			icmpv6_send(fq->fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0,
				    dev);
		}
	}
	if (idev)
		in6_dev_put(idev);
	if (dev)
		dev_put(dev);
out:
	spin_unlock(&fq->lock);
	fq_put(fq);
}
int afinet6_read_devsnmp(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
{
	int len = 0;
	struct net_device *dev;
	struct inet6_dev *idev = data;
	off_t done = 0;

	if (idev){
		done += snmp6_explore(idev->stats.ipv6,snmp6_list_ipv6,offset,length,done,buffer,start);
		done += snmp6_explore(idev->stats.icmpv6,snmp6_list_icmpv6,offset,length,done,buffer,start);
	}
	else{
		read_lock(&dev_base_lock);
		for (dev=dev_base; dev; dev=dev->next) {
			struct inet6_dev *idev = in6_dev_get(dev);
			if (!idev)
				continue;
			done += snmp6_explore_dev(idev->stats.ipv6,snmp6_list_ipv6,dev->ifindex,offset,length,done,buffer,start);
			done += snmp6_explore_dev(idev->stats.icmpv6,snmp6_list_icmpv6,dev->ifindex,offset,length,done,buffer,start);
			in6_dev_put(idev);
		}
		read_unlock(&dev_base_lock);
	}

	if (done > offset){
		len = done - offset;
		if (len > length)
			len = length;
		else if (len < length)
			*eof = 1;
	}
	else{
		len = 0;
		*eof = 1;
	}

	return len;
}
Exemple #28
0
/* Some devices are known to send Neigbor Solicitation messages and
 * require Neigbor Advertisement replies.  The IPv6 core will not
 * respond since IFF_NOARP is set, so we must handle them ourselves.
 */
static void do_neigh_solicit(struct usbnet *dev, u8 *buf, u16 tci)
{
	struct ipv6hdr *iph = (void *)buf;
	struct nd_msg *msg = (void *)(iph + 1);
	struct net_device *netdev;
	struct inet6_dev *in6_dev;
	bool is_router;

	/* we'll only respond to requests from unicast addresses to
	 * our solicited node addresses.
	 */
	if (!ipv6_addr_is_solict_mult(&iph->daddr) ||
	    !(ipv6_addr_type(&iph->saddr) & IPV6_ADDR_UNICAST))
		return;

	/* need to send the NA on the VLAN dev, if any */
	if (tci)
		netdev = __vlan_find_dev_deep(dev->net, htons(ETH_P_8021Q),
					      tci);
	else
		netdev = dev->net;
	if (!netdev)
		return;

	in6_dev = in6_dev_get(netdev);
	if (!in6_dev)
		return;
	is_router = !!in6_dev->cnf.forwarding;
	in6_dev_put(in6_dev);

	/* ipv6_stub != NULL if in6_dev_get returned an inet6_dev */
	ipv6_stub->ndisc_send_na(netdev, NULL, &iph->saddr, &msg->target,
				 is_router /* router */,
				 true /* solicited */,
				 false /* override */,
				 true /* inc_opt */);
}
Exemple #29
0
static void rmnet_usb_setup(struct net_device *dev, int mux_enabled)
{
#ifdef DISABLE_RMNET_USB_IPV6_ACCEPT_RA_DEFRTR
	struct inet6_dev *idev = NULL;
#endif 
	
	dev->netdev_ops = &rmnet_usb_ops_ether;

	
	dev->mtu = RMNET_DATA_LEN;

	if (mux_enabled) {
		dev->needed_headroom = RMNET_HEADROOM_W_MUX;

		
		dev->needed_tailroom = RMNET_TAILROOM;
	} else {
		dev->needed_headroom = RMNET_HEADROOM;
	}

	random_ether_addr(dev->dev_addr);
	dev->watchdog_timeo = 1000; 

#ifdef DISABLE_RMNET_USB_IPV6_ACCEPT_RA_DEFRTR
	idev = in6_dev_get(dev);
	if (idev)
	{
		idev->cnf.accept_ra_defrtr = 0;
		if (idev->dev)
			pr_info("net_device:%s set accept_ra_defrtr:%d\n", idev->dev->name, idev->cnf.accept_ra_defrtr);
	}

	if (idev)
		in6_dev_put(idev);
#endif 
}
Exemple #30
0
void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
{
	struct sock *sk = igmp6_socket->sk;
        struct sk_buff *skb;
	struct inet6_dev *idev;
        struct icmp6hdr *hdr;
	struct in6_addr *snd_addr;
	struct in6_addr *addrp;
	struct in6_addr addr_buf;
	struct in6_addr all_routers;
	int err, len, payload_len, full_len;
	u8 ra[8] = { IPPROTO_ICMPV6, 0,
		     IPV6_TLV_ROUTERALERT, 2, 0, 0,
		     IPV6_TLV_PADN, 0 };
#ifdef CONFIG_IPV6_MLD6_DEBUG
	char abuf[128];
	in6_ntop(addr, abuf);

	MDBG3((KERN_DEBUG
		"igmp6_send(addr=%s, dev=%p(%s), type=%d)\n",
		abuf, dev, dev->name ? dev->name :"<null>", type));
#endif

	snd_addr = addr;
	if (type == ICMPV6_MGM_REDUCTION) {
		snd_addr = &all_routers;
		ipv6_addr_all_routers(&all_routers);
	}

	len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
	payload_len = len + sizeof(ra);
	full_len = sizeof(struct ipv6hdr) + payload_len;

	skb = sock_alloc_send_skb(sk, dev->hard_header_len + full_len + 15, 0, &err);

	if (skb == NULL)
		return;

	skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
	if (dev->hard_header) {
		unsigned char ha[MAX_ADDR_LEN];
		ndisc_mc_map(snd_addr, ha, dev, 1);
		if (dev->hard_header(skb, dev, ETH_P_IPV6, ha, NULL, full_len) < 0)
			goto out;
	}

	if (ipv6_get_lladdr(dev, &addr_buf)) {
		MDBG1((KERN_WARNING "igmp6: %s no linklocal address\n",
		       dev->name));
		goto out;
	}

	ip6_nd_hdr(sk, skb, dev, &addr_buf, snd_addr, NEXTHDR_HOP, payload_len);

	memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra));

	hdr = (struct icmp6hdr *) skb_put(skb, sizeof(struct icmp6hdr));
	memset(hdr, 0, sizeof(struct icmp6hdr));
	hdr->icmp6_type = type;

	addrp = (struct in6_addr *) skb_put(skb, sizeof(struct in6_addr));
	ipv6_addr_copy(addrp, addr);

	hdr->icmp6_cksum = csum_ipv6_magic(&addr_buf, snd_addr, len,
					   IPPROTO_ICMPV6,
					   csum_partial((__u8 *) hdr, len, 0));

	dev_queue_xmit(skb);
	idev = in6_dev_get(dev);
	if (type == ICMPV6_MGM_REDUCTION)
		ICMP6_INC_STATS(idev,Icmp6OutGroupMembReductions);
	else
		ICMP6_INC_STATS(idev,Icmp6OutGroupMembResponses);
	ICMP6_INC_STATS(idev,Icmp6OutMsgs);
	if (idev)
		in6_dev_put(idev);
	return;

out:
	kfree_skb(skb);
}