Example #1
0
/* The neighbour entry n->lock is held. */
static int neigh_check_cb(struct neighbour *n)
{
	struct atmarp_entry *entry = neighbour_priv(n);
	struct clip_vcc *cv;

	if (n->ops != &clip_neigh_ops)
		return 0;
	for (cv = entry->vccs; cv; cv = cv->next) {
		unsigned long exp = cv->last_use + cv->idle_timeout;

		if (cv->idle_timeout && time_after(jiffies, exp)) {
			pr_debug("releasing vcc %p->%p of entry %p\n",
				 cv, cv->vcc, entry);
			vcc_release_async(cv->vcc, -ETIMEDOUT);
		}
	}

	if (entry->vccs || time_before(jiffies, entry->expires))
		return 0;

	if (atomic_read(&n->refcnt) > 1) {
		struct sk_buff *skb;

		pr_debug("destruction postponed with ref %d\n",
			 atomic_read(&n->refcnt));

		while ((skb = skb_dequeue(&n->arp_queue)) != NULL)
			dev_kfree_skb(skb);

		return 0;
	}

	pr_debug("expired neigh %p\n", n);
	return 1;
}
Example #2
0
int ax25_neigh_construct(struct neighbour *neigh)
{
	/* This trouble could be saved if ax25 would right a proper
	 * dev_queue_xmit function.
	 */
	struct ax25_neigh_priv *priv = neighbour_priv(neigh);

	if (neigh->tbl->family != AF_INET)
		return -EINVAL;

	priv->ops = *neigh->ops;
	priv->ops.output = neigh_compat_output;
	priv->ops.connected_output = neigh_compat_output;
	return 0;
}
Example #3
0
static void lowpan_ndisc_802154_update(struct neighbour *n, u32 flags,
                                       u8 icmp6_type,
                                       const struct ndisc_options *ndopts)
{
    struct lowpan_802154_neigh *neigh = lowpan_802154_neigh(neighbour_priv(n));
    u8 *lladdr_short = NULL;

    switch (icmp6_type) {
    case NDISC_ROUTER_SOLICITATION:
    case NDISC_ROUTER_ADVERTISEMENT:
    case NDISC_NEIGHBOUR_SOLICITATION:
        if (ndopts->nd_802154_opts_src_lladdr) {
            lladdr_short = __ndisc_opt_addr_data(ndopts->nd_802154_opts_src_lladdr,
                                                 IEEE802154_SHORT_ADDR_LEN, 0);
            if (!lladdr_short) {
                ND_PRINTK(2, warn,
                          "NA: invalid short link-layer address length\n");
                return;
            }
        }
        break;
    case NDISC_REDIRECT:
    case NDISC_NEIGHBOUR_ADVERTISEMENT:
        if (ndopts->nd_802154_opts_tgt_lladdr) {
            lladdr_short = __ndisc_opt_addr_data(ndopts->nd_802154_opts_tgt_lladdr,
                                                 IEEE802154_SHORT_ADDR_LEN, 0);
            if (!lladdr_short) {
                ND_PRINTK(2, warn,
                          "NA: invalid short link-layer address length\n");
                return;
            }
        }
        break;
    default:
        break;
    }

    write_lock_bh(&n->lock);
    if (lladdr_short) {
        ieee802154_be16_to_le16(&neigh->short_addr, lladdr_short);
        if (!lowpan_802154_is_valid_src_short_addr(neigh->short_addr))
            neigh->short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC);
    } else {
        neigh->short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC);
    }
    write_unlock_bh(&n->lock);
}
Example #4
0
static int clip_setentry(struct atm_vcc *vcc, __be32 ip)
{
	struct neighbour *neigh;
	struct atmarp_entry *entry;
	int error;
	struct clip_vcc *clip_vcc;
	struct rtable *rt;

	if (vcc->push != clip_push) {
		pr_warning("non-CLIP VCC\n");
		return -EBADF;
	}
	clip_vcc = CLIP_VCC(vcc);
	if (!ip) {
		if (!clip_vcc->entry) {
			pr_err("hiding hidden ATMARP entry\n");
			return 0;
		}
		pr_debug("remove\n");
		unlink_clip_vcc(clip_vcc);
		return 0;
	}
	rt = ip_route_output(&init_net, ip, 0, 1, 0);
	if (IS_ERR(rt))
		return PTR_ERR(rt);
	neigh = __neigh_lookup(&arp_tbl, &ip, rt->dst.dev, 1);
	ip_rt_put(rt);
	if (!neigh)
		return -ENOMEM;
	entry = neighbour_priv(neigh);
	if (entry != clip_vcc->entry) {
		if (!clip_vcc->entry)
			pr_debug("add\n");
		else {
			pr_debug("update\n");
			unlink_clip_vcc(clip_vcc);
		}
		link_vcc(clip_vcc, entry);
	}
	error = neigh_update(neigh, llc_oui, NUD_PERMANENT,
			     NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_ADMIN);
	neigh_release(neigh);
	return error;
}
Example #5
0
static int clip_constructor(struct neighbour *neigh)
{
	struct atmarp_entry *entry = neighbour_priv(neigh);

	if (neigh->tbl->family != AF_INET)
		return -EINVAL;

	if (neigh->type != RTN_UNICAST)
		return -EINVAL;

	neigh->nud_state = NUD_NONE;
	neigh->ops = &clip_neigh_ops;
	neigh->output = neigh->ops->output;
	entry->neigh = neigh;
	entry->vccs = NULL;
	entry->expires = jiffies - 1;

	return 0;
}
Example #6
0
static int lowpan_ndisc_opt_addr_space(const struct net_device *dev,
                                       u8 icmp6_type, struct neighbour *neigh,
                                       u8 *ha_buf, u8 **ha)
{
    struct lowpan_802154_neigh *n;
    struct wpan_dev *wpan_dev;
    int addr_space = 0;

    if (!lowpan_is_ll(dev, LOWPAN_LLTYPE_IEEE802154))
        return 0;

    switch (icmp6_type) {
    case NDISC_REDIRECT:
        n = lowpan_802154_neigh(neighbour_priv(neigh));

        read_lock_bh(&neigh->lock);
        if (lowpan_802154_is_valid_src_short_addr(n->short_addr)) {
            memcpy(ha_buf, &n->short_addr,
                   IEEE802154_SHORT_ADDR_LEN);
            read_unlock_bh(&neigh->lock);
            addr_space += __ndisc_opt_addr_space(IEEE802154_SHORT_ADDR_LEN, 0);
            *ha = ha_buf;
        } else {
            read_unlock_bh(&neigh->lock);
        }
        break;
    case NDISC_NEIGHBOUR_ADVERTISEMENT:
    case NDISC_NEIGHBOUR_SOLICITATION:
    case NDISC_ROUTER_SOLICITATION:
        wpan_dev = lowpan_802154_dev(dev)->wdev->ieee802154_ptr;

        if (lowpan_802154_is_valid_src_short_addr(wpan_dev->short_addr))
            addr_space = __ndisc_opt_addr_space(IEEE802154_SHORT_ADDR_LEN, 0);
        break;
    default:
        break;
    }

    return addr_space;
}
Example #7
0
static netdev_tx_t clip_start_xmit(struct sk_buff *skb,
				   struct net_device *dev)
{
	struct clip_priv *clip_priv = PRIV(dev);
	struct dst_entry *dst = skb_dst(skb);
	struct atmarp_entry *entry;
	struct neighbour *n;
	struct atm_vcc *vcc;
	struct rtable *rt;
	__be32 *daddr;
	int old;
	unsigned long flags;

	pr_debug("(skb %p)\n", skb);
	if (!dst) {
		pr_err("skb_dst(skb) == NULL\n");
		dev_kfree_skb(skb);
		dev->stats.tx_dropped++;
		return NETDEV_TX_OK;
	}
	rt = (struct rtable *) dst;
	if (rt->rt_gateway)
		daddr = &rt->rt_gateway;
	else
		daddr = &ip_hdr(skb)->daddr;
	n = dst_neigh_lookup(dst, daddr);
	if (!n) {
		pr_err("NO NEIGHBOUR !\n");
		dev_kfree_skb(skb);
		dev->stats.tx_dropped++;
		return NETDEV_TX_OK;
	}
	entry = neighbour_priv(n);
	if (!entry->vccs) {
		if (time_after(jiffies, entry->expires)) {
			/* should be resolved */
			entry->expires = jiffies + ATMARP_RETRY_DELAY * HZ;
			to_atmarpd(act_need, PRIV(dev)->number, *((__be32 *)n->primary_key));
		}
		if (entry->neigh->arp_queue.qlen < ATMARP_MAX_UNRES_PACKETS)
			skb_queue_tail(&entry->neigh->arp_queue, skb);
		else {
			dev_kfree_skb(skb);
			dev->stats.tx_dropped++;
		}
		goto out_release_neigh;
	}
	pr_debug("neigh %p, vccs %p\n", entry, entry->vccs);
	ATM_SKB(skb)->vcc = vcc = entry->vccs->vcc;
	pr_debug("using neighbour %p, vcc %p\n", n, vcc);
	if (entry->vccs->encap) {
		void *here;

		here = skb_push(skb, RFC1483LLC_LEN);
		memcpy(here, llc_oui, sizeof(llc_oui));
		((__be16 *) here)[3] = skb->protocol;
	}
	atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
	ATM_SKB(skb)->atm_options = vcc->atm_options;
	entry->vccs->last_use = jiffies;
	pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, vcc, vcc->dev);
	old = xchg(&entry->vccs->xoff, 1);	/* assume XOFF ... */
	if (old) {
		pr_warning("XOFF->XOFF transition\n");
		goto out_release_neigh;
	}
	dev->stats.tx_packets++;
	dev->stats.tx_bytes += skb->len;
	vcc->send(vcc, skb);
	if (atm_may_send(vcc, 0)) {
		entry->vccs->xoff = 0;
		goto out_release_neigh;
	}
	spin_lock_irqsave(&clip_priv->xoff_lock, flags);
	netif_stop_queue(dev);	/* XOFF -> throttle immediately */
	barrier();
	if (!entry->vccs->xoff)
		netif_start_queue(dev);
	/* Oh, we just raced with clip_pop. netif_start_queue should be
	   good enough, because nothing should really be asleep because
	   of the brief netif_stop_queue. If this isn't true or if it
	   changes, use netif_wake_queue instead. */
	spin_unlock_irqrestore(&clip_priv->xoff_lock, flags);
out_release_neigh:
	neigh_release(n);
	return NETDEV_TX_OK;
}