예제 #1
0
파일: arp.c 프로젝트: 274914765/C
int arp_find(unsigned char *haddr, struct sk_buff *skb)
{
    struct net_device *dev = skb->dev;
    __be32 paddr;
    struct neighbour *n;

    if (!skb->dst) {
        printk(KERN_DEBUG "arp_find is called with dst==NULL\n");
        kfree_skb(skb);
        return 1;
    }

    paddr = skb->rtable->rt_gateway;

    if (arp_set_predefined(inet_addr_type(dev_net(dev), paddr), haddr, paddr, dev))
        return 0;

    n = __neigh_lookup(&arp_tbl, &paddr, dev, 1);

    if (n) {
        n->used = jiffies;
        if (n->nud_state&NUD_VALID || neigh_event_send(n, skb) == 0) {
            read_lock_bh(&n->lock);
            memcpy(haddr, n->ha, dev->addr_len);
            read_unlock_bh(&n->lock);
            neigh_release(n);
            return 0;
        }
        neigh_release(n);
    } else
        kfree_skb(skb);
    return 1;
}
예제 #2
0
int arp_find(unsigned char *haddr, struct sk_buff *skb)
{
	struct net_device *dev = skb->dev;
	__be32 paddr;
	struct neighbour *n;

	if (!skb_dst(skb)) {
		pr_debug("arp_find is called with dst==NULL\n");
		kfree_skb(skb);
		return 1;
	}

	paddr = rt_nexthop(skb_rtable(skb), ip_hdr(skb)->daddr);
	if (arp_set_predefined(inet_addr_type(dev_net(dev), paddr), haddr,
			       paddr, dev))
		return 0;

	n = __neigh_lookup(&arp_tbl, &paddr, dev, 1);

	if (n) {
		n->used = jiffies;
		if (n->nud_state & NUD_VALID || neigh_event_send(n, skb) == 0) {
			neigh_ha_snapshot(haddr, n, dev);
			neigh_release(n);
			return 0;
		}
		neigh_release(n);
	} else
		kfree_skb(skb);
	return 1;
}
예제 #3
0
static int
__teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct net_device *dev)
{
	struct teql_sched_data *q = (void*)dev->qdisc->data;
	struct neighbour *mn = skb->dst->neighbour;
	struct neighbour *n = q->ncache;

	if (mn->tbl == NULL)
		return -EINVAL;
	if (n && n->tbl == mn->tbl &&
	    memcmp(n->primary_key, mn->primary_key, mn->tbl->key_len) == 0) {
		atomic_inc(&n->refcnt);
	} else {
		n = __neigh_lookup_errno(mn->tbl, mn->primary_key, dev);
		if (IS_ERR(n))
			return PTR_ERR(n);
	}
	if (neigh_event_send(n, skb_res) == 0) {
		int err;
		read_lock(&n->lock);
		err = dev->hard_header(skb, dev, ntohs(skb->protocol), n->ha, NULL, skb->len);
		read_unlock(&n->lock);
		if (err < 0) {
			neigh_release(n);
			return -EINVAL;
		}
		teql_neigh_release(xchg(&q->ncache, n));
		return 0;
	}
	neigh_release(n);
	return (skb_res == NULL) ? -EAGAIN : 1;
}
예제 #4
0
파일: br_input.c 프로젝트: 513855417/linux
static void br_do_proxy_arp(struct sk_buff *skb, struct net_bridge *br,
			    u16 vid, struct net_bridge_port *p)
{
	struct net_device *dev = br->dev;
	struct neighbour *n;
	struct arphdr *parp;
	u8 *arpptr, *sha;
	__be32 sip, tip;

	BR_INPUT_SKB_CB(skb)->proxyarp_replied = false;

	if (dev->flags & IFF_NOARP)
		return;

	if (!pskb_may_pull(skb, arp_hdr_len(dev))) {
		dev->stats.tx_dropped++;
		return;
	}
	parp = arp_hdr(skb);

	if (parp->ar_pro != htons(ETH_P_IP) ||
	    parp->ar_op != htons(ARPOP_REQUEST) ||
	    parp->ar_hln != dev->addr_len ||
	    parp->ar_pln != 4)
		return;

	arpptr = (u8 *)parp + sizeof(struct arphdr);
	sha = arpptr;
	arpptr += dev->addr_len;	/* sha */
	memcpy(&sip, arpptr, sizeof(sip));
	arpptr += sizeof(sip);
	arpptr += dev->addr_len;	/* tha */
	memcpy(&tip, arpptr, sizeof(tip));

	if (ipv4_is_loopback(tip) ||
	    ipv4_is_multicast(tip))
		return;

	n = neigh_lookup(&arp_tbl, &tip, dev);
	if (n) {
		struct net_bridge_fdb_entry *f;

		if (!(n->nud_state & NUD_VALID)) {
			neigh_release(n);
			return;
		}

		f = __br_fdb_get(br, n->ha, vid);
		if (f && ((p->flags & BR_PROXYARP) ||
			  (f->dst && (f->dst->flags & BR_PROXYARP_WIFI)))) {
			arp_send(ARPOP_REPLY, ETH_P_ARP, sip, skb->dev, tip,
				 sha, n->ha, sha);
			BR_INPUT_SKB_CB(skb)->proxyarp_replied = true;
		}

		neigh_release(n);
	}
}
예제 #5
0
/*
 * Ethernet router hello message received
 */
int dn_neigh_router_hello(struct sk_buff *skb)
{
    struct rtnode_hello_message *msg = (struct rtnode_hello_message *)skb->data;

    struct neighbour *neigh;
    struct dn_neigh *dn;
    struct dn_dev *dn_db;
    dn_address src;

    src = dn_htons(dn_eth2dn(msg->id));

    neigh = __neigh_lookup(&dn_neigh_table, &src, skb->dev, 1);

    dn = (struct dn_neigh *)neigh;

    if (neigh) {
        write_lock(&neigh->lock);

        neigh->used = jiffies;
        dn_db = (struct dn_dev *)neigh->dev->dn_ptr;

        if (!(neigh->nud_state & NUD_PERMANENT)) {
            neigh->updated = jiffies;

            if (neigh->dev->type == ARPHRD_ETHER)
                memcpy(neigh->ha, &skb->mac.ethernet->h_source, ETH_ALEN);

            dn->blksize  = dn_ntohs(msg->blksize);
            dn->priority = msg->priority;

            dn->flags &= ~DN_NDFLAG_P3;

            switch(msg->iinfo & DN_RT_INFO_TYPE) {
            case DN_RT_INFO_L1RT:
                dn->flags &=~DN_NDFLAG_R2;
                dn->flags |= DN_NDFLAG_R1;
                break;
            case DN_RT_INFO_L2RT:
                dn->flags |= DN_NDFLAG_R2;
            }
        }

        if (!dn_db->router) {
            dn_db->router = neigh_clone(neigh);
        } else {
            if (msg->priority > ((struct dn_neigh *)dn_db->router)->priority)
                neigh_release(xchg(&dn_db->router, neigh_clone(neigh)));
        }
        write_unlock(&neigh->lock);
        neigh_release(neigh);
    }

    kfree_skb(skb);
    return 0;
}
예제 #6
0
/*
 * Endnode hello message received
 */
int dn_neigh_endnode_hello(struct sk_buff *skb)
{
    struct endnode_hello_message *msg = (struct endnode_hello_message *)skb->data;
    struct neighbour *neigh;
    struct dn_neigh *dn;
    dn_address src;

    src = dn_htons(dn_eth2dn(msg->id));

    neigh = __neigh_lookup(&dn_neigh_table, &src, skb->dev, 1);

    dn = (struct dn_neigh *)neigh;

    if (neigh) {
        write_lock(&neigh->lock);

        neigh->used = jiffies;

        if (!(neigh->nud_state & NUD_PERMANENT)) {
            neigh->updated = jiffies;

            if (neigh->dev->type == ARPHRD_ETHER)
                memcpy(neigh->ha, &skb->mac.ethernet->h_source, ETH_ALEN);
            dn->flags   &= ~(DN_NDFLAG_R1 | DN_NDFLAG_R2);
            dn->blksize  = dn_ntohs(msg->blksize);
            dn->priority = 0;
        }

        write_unlock(&neigh->lock);
        neigh_release(neigh);
    }

    kfree_skb(skb);
    return 0;
}
예제 #7
0
static inline void neigh_replace(struct l2t_entry *e, struct neighbour *n)
{
	neigh_hold(n);
	if (e->neigh)
		neigh_release(e->neigh);
	e->neigh = n;
}
예제 #8
0
static int arp_req_set(struct net *net, struct arpreq *r,
		       struct net_device *dev)
{
	__be32 ip;
	struct neighbour *neigh;
	int err;

	if (r->arp_flags & ATF_PUBL)
		return arp_req_set_public(net, r, dev);

	ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
	if (r->arp_flags & ATF_PERM)
		r->arp_flags |= ATF_COM;
	if (dev == NULL) {
		struct flowi fl = { .nl_u.ip4_u = { .daddr = ip,
						    .tos = RTO_ONLINK } };
		struct rtable *rt;
		err = ip_route_output_key(net, &rt, &fl);
		if (err != 0)
			return err;
		dev = rt->dst.dev;
		ip_rt_put(rt);
		if (!dev)
			return -EINVAL;
	}
	switch (dev->type) {
#if defined(CONFIG_FDDI) || defined(CONFIG_FDDI_MODULE)
	case ARPHRD_FDDI:
		/*
		 * According to RFC 1390, FDDI devices should accept ARP
		 * hardware types of 1 (Ethernet).  However, to be more
		 * robust, we'll accept hardware types of either 1 (Ethernet)
		 * or 6 (IEEE 802.2).
		 */
		if (r->arp_ha.sa_family != ARPHRD_FDDI &&
		    r->arp_ha.sa_family != ARPHRD_ETHER &&
		    r->arp_ha.sa_family != ARPHRD_IEEE802)
			return -EINVAL;
		break;
#endif
	default:
		if (r->arp_ha.sa_family != dev->type)
			return -EINVAL;
		break;
	}

	neigh = __neigh_lookup_errno(&arp_tbl, &ip, dev);
	err = PTR_ERR(neigh);
	if (!IS_ERR(neigh)) {
		unsigned state = NUD_STALE;
		if (r->arp_flags & ATF_PERM)
			state = NUD_PERMANENT;
		err = neigh_update(neigh, (r->arp_flags & ATF_COM) ?
				   r->arp_ha.sa_data : NULL, state,
				   NEIGH_UPDATE_F_OVERRIDE |
				   NEIGH_UPDATE_F_ADMIN);
		neigh_release(neigh);
	}
	return err;
}
예제 #9
0
static int
ndisc_build_ll_hdr(struct sk_buff *skb, struct device *dev,
		   struct in6_addr *daddr, struct neighbour *neigh, int len)
{
	unsigned char ha[MAX_ADDR_LEN];
	unsigned char *h_dest = NULL;

	skb_reserve(skb, (dev->hard_header_len + 15) & ~15);

	if (dev->hard_header) {
		if (ipv6_addr_type(daddr) & IPV6_ADDR_MULTICAST) {
			ndisc_mc_map(daddr, ha, dev, 1);
			h_dest = ha;
		} else if (neigh) {
			h_dest = neigh->ha;
		} else {
			neigh = neigh_lookup(&nd_tbl, daddr, dev);
			if (neigh) {
				if (neigh->nud_state&NUD_VALID) {
					memcpy(ha, neigh->ha, dev->addr_len);
					h_dest = ha;
				}
				neigh_release(neigh);
			}
		}

		if (dev->hard_header(skb, dev, ETH_P_IPV6, h_dest, NULL, len) < 0)
			return 0;
	}

	return 1;
}
예제 #10
0
파일: arp.c 프로젝트: 274914765/C
static int arp_req_delete(struct net *net, struct arpreq *r,
        struct net_device * dev)
{
    int err;
    __be32 ip;
    struct neighbour *neigh;

    if (r->arp_flags & ATF_PUBL)
        return arp_req_delete_public(net, r, dev);

    ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
    if (dev == NULL) {
        struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip,
                             .tos = RTO_ONLINK } } };
        struct rtable * rt;
        if ((err = ip_route_output_key(net, &rt, &fl)) != 0)
            return err;
        dev = rt->u.dst.dev;
        ip_rt_put(rt);
        if (!dev)
            return -EINVAL;
    }
    err = -ENXIO;
    neigh = neigh_lookup(&arp_tbl, &ip, dev);
    if (neigh) {
        if (neigh->nud_state&~NUD_NOARP)
            err = neigh_update(neigh, NULL, NUD_FAILED,
                       NEIGH_UPDATE_F_OVERRIDE|
                       NEIGH_UPDATE_F_ADMIN);
        neigh_release(neigh);
    }
    return err;
}
예제 #11
0
int arp_req_set(struct arpreq *r, struct net_device * dev)
{
	u32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr;
	struct neighbour *neigh;
	int err;

	if (r->arp_flags&ATF_PUBL) {
		u32 mask = ((struct sockaddr_in *) &r->arp_netmask)->sin_addr.s_addr;
		if (mask && mask != 0xFFFFFFFF)
			return -EINVAL;
		if (!dev && (r->arp_flags & ATF_COM)) {
			dev = dev_getbyhwaddr(r->arp_ha.sa_family, r->arp_ha.sa_data);
			if (!dev)
				return -ENODEV;
		}
		if (mask) {
			if (pneigh_lookup(&arp_tbl, &ip, dev, 1) == NULL)
				return -ENOBUFS;
			return 0;
		}
		if (dev == NULL) {
			ipv4_devconf.proxy_arp = 1;
			return 0;
		}
		if (__in_dev_get(dev)) {
			__in_dev_get(dev)->cnf.proxy_arp = 1;
			return 0;
		}
		return -ENXIO;
	}

	if (r->arp_flags & ATF_PERM)
		r->arp_flags |= ATF_COM;
	if (dev == NULL) {
		struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip,
							 .tos = RTO_ONLINK } } };
		struct rtable * rt;
		if ((err = ip_route_output_key(&rt, &fl)) != 0)
			return err;
		dev = rt->u.dst.dev;
		ip_rt_put(rt);
		if (!dev)
			return -EINVAL;
	}
	if (r->arp_ha.sa_family != dev->type)	
		return -EINVAL;

	neigh = __neigh_lookup_errno(&arp_tbl, &ip, dev);
	err = PTR_ERR(neigh);
	if (!IS_ERR(neigh)) {
		unsigned state = NUD_STALE;
		if (r->arp_flags & ATF_PERM)
			state = NUD_PERMANENT;
		err = neigh_update(neigh, (r->arp_flags&ATF_COM) ?
				   r->arp_ha.sa_data : NULL, state, 1, 0);
		neigh_release(neigh);
	}
	return err;
}
예제 #12
0
static int arp_req_delete(struct arpreq *r, struct net_device * dev)
{
	int err;
	u32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
	struct neighbour *neigh;

	if (r->arp_flags & ATF_PUBL) {
		u32 mask =
		       ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr;
		if (mask == 0xFFFFFFFF)
			return pneigh_delete(&arp_tbl, &ip, dev);
		if (mask == 0) {
			if (dev == NULL) {
				ipv4_devconf.proxy_arp = 0;
				return 0;
			}
			if (__in_dev_get_rtnl(dev)) {
				__in_dev_get_rtnl(dev)->cnf.proxy_arp = 0;
				return 0;
			}
			return -ENXIO;
		}
		return -EINVAL;
	}

	if (dev == NULL) {
#ifndef __TCS__
		struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip,
							 .tos = RTO_ONLINK } } };
		struct rtable * rt;
#else
		struct rtable * rt;
		struct flowi fl;
		memset(&fl,0,sizeof(fl));
		fl.nl_u.ip4_u.daddr=ip;
		fl.nl_u.ip4_u.tos=RTO_ONLINK;
#endif 
		if ((err = ip_route_output_key(&rt, &fl)) != 0)
			return err;
		dev = rt->u.dst.dev;
		ip_rt_put(rt);
		if (!dev)
			return -EINVAL;
	}
	err = -ENXIO;
	neigh = neigh_lookup(&arp_tbl, &ip, dev);
	if (neigh) {
		if (neigh->nud_state&~NUD_NOARP)
			err = neigh_update(neigh, NULL, NUD_FAILED, 
					   NEIGH_UPDATE_F_OVERRIDE|
					   NEIGH_UPDATE_F_ADMIN);
		neigh_release(neigh);
	}
	return err;
}
예제 #13
0
/*
 * Called when an L2T entry has no more users.  The entry is left in the hash
 * table since it is likely to be reused but we also bump nfree to indicate
 * that the entry can be reallocated for a different neighbor.  We also drop
 * the existing neighbor reference in case the neighbor is going away and is
 * waiting on our reference.
 *
 * Because entries can be reallocated to other neighbors once their ref count
 * drops to 0 we need to take the entry's lock to avoid races with a new
 * incarnation.
 */
void t3_l2e_free(struct l2t_data *d, struct l2t_entry *e)
{
	spin_lock_bh(&e->lock);
	if (atomic_read(&e->refcnt) == 0) {	/* hasn't been recycled */
		if (e->neigh) {
			neigh_release(e->neigh);
			e->neigh = NULL;
		}
	}
	spin_unlock_bh(&e->lock);
	atomic_inc(&d->nfree);
}
예제 #14
0
static int arp_req_set(struct net *net, struct arpreq *r,
		       struct net_device *dev)
{
	__be32 ip;
	struct neighbour *neigh;
	int err;

	if (r->arp_flags & ATF_PUBL)
		return arp_req_set_public(net, r, dev);

	ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
	if (r->arp_flags & ATF_PERM)
		r->arp_flags |= ATF_COM;
	if (dev == NULL) {
		struct rtable *rt = ip_route_output(net, ip, 0, RTO_ONLINK, 0);

		if (IS_ERR(rt))
			return PTR_ERR(rt);
		dev = rt->dst.dev;
		ip_rt_put(rt);
		if (!dev)
			return -EINVAL;
	}
	switch (dev->type) {
#if IS_ENABLED(CONFIG_FDDI)
	case ARPHRD_FDDI:
		if (r->arp_ha.sa_family != ARPHRD_FDDI &&
		    r->arp_ha.sa_family != ARPHRD_ETHER &&
		    r->arp_ha.sa_family != ARPHRD_IEEE802)
			return -EINVAL;
		break;
#endif
	default:
		if (r->arp_ha.sa_family != dev->type)
			return -EINVAL;
		break;
	}

	neigh = __neigh_lookup_errno(&arp_tbl, &ip, dev);
	err = PTR_ERR(neigh);
	if (!IS_ERR(neigh)) {
		unsigned state = NUD_STALE;
		if (r->arp_flags & ATF_PERM)
			state = NUD_PERMANENT;
		err = neigh_update(neigh, (r->arp_flags & ATF_COM) ?
				   r->arp_ha.sa_data : NULL, state,
				   NEIGH_UPDATE_F_OVERRIDE |
				   NEIGH_UPDATE_F_ADMIN);
		neigh_release(neigh);
	}
	return err;
}
예제 #15
0
파일: helper.c 프로젝트: Marcus1911/kulfi
/* Get eth_addr for a dst_ip by looking up into the ARP table */
int get_dst_haddr(unsigned char* daddr, u32 dst_ip, struct net_device *dev){
    struct neighbour *neigh = neigh_lookup(&arp_tbl, &dst_ip, dev);
    int err = -ENXIO;
    if(neigh){
        memcpy(daddr, neigh->ha, dev->addr_len);
        neigh_release(neigh);
        err = 0;
    }
    else{
        pr_debug("neigh_lookup failed!\n");
    }
    return err;
}
예제 #16
0
struct dst_entry *dst_destroy(struct dst_entry * dst)
{
	struct dst_entry *child;
	struct neighbour *neigh;
	struct hh_cache *hh;

	smp_rmb();

again:
	neigh = dst->neighbour;
	hh = dst->hh;
	child = dst->child;

	dst->hh = NULL;
	if (hh && atomic_dec_and_test(&hh->hh_refcnt))
		kfree(hh);

	if (neigh) {
		dst->neighbour = NULL;
		neigh_release(neigh);
	}

	if (!(dst->flags & DST_NOCOUNT))
		atomic_dec(&dst->ops->entries);

	if (dst->ops->destroy)
		dst->ops->destroy(dst);
	if (dst->dev)
		dev_put(dst->dev);
#if RT_CACHE_DEBUG >= 2
	atomic_dec(&dst_total);
#endif
	kmem_cache_free(dst->ops->kmem_cachep, dst);

	dst = child;
	if (dst) {
		int nohash = dst->flags & DST_NOHASH;

		if (atomic_dec_and_test(&dst->__refcnt)) {
			/* We were real parent of this dst, so kill child. */
			if (nohash)
				goto again;
		} else {
			/* Child is still referenced, return it for freeing. */
			if (nohash)
				return dst;
			/* Child is still in his hash table */
		}
	}
	return NULL;
}
예제 #17
0
static int clip_setentry(struct atm_vcc *vcc,u32 ip)
{
	struct neighbour *neigh;
	struct atmarp_entry *entry;
	int error;
	struct clip_vcc *clip_vcc;
#ifndef __TCS__
	struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip, .tos = 1 } } };
	struct rtable *rt;
#else
	struct rtable *rt;
	struct flowi fl;
	memset(&fl,0,sizeof(fl));
	fl.nl_u.ip4_u.daddr=ip;
	fl.nl_u.ip4_u.tos=1;
#endif 

	if (vcc->push != clip_push) {
		printk(KERN_WARNING "clip_setentry: non-CLIP VCC\n");
		return -EBADF;
	}
	clip_vcc = CLIP_VCC(vcc);
	if (!ip) {
		if (!clip_vcc->entry) {
			printk(KERN_ERR "hiding hidden ATMARP entry\n");
			return 0;
		}
		DPRINTK("setentry: remove\n");
		unlink_clip_vcc(clip_vcc);
		return 0;
	}
	error = ip_route_output_key(&rt,&fl);
	if (error) return error;
	neigh = __neigh_lookup(&clip_tbl,&ip,rt->u.dst.dev,1);
	ip_rt_put(rt);
	if (!neigh)
		return -ENOMEM;
	entry = NEIGH2ENTRY(neigh);
	if (entry != clip_vcc->entry) {
		if (!clip_vcc->entry) DPRINTK("setentry: add\n");
		else {
			DPRINTK("setentry: 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;
}
static void idle_timer_check(unsigned long dummy)
{
	int i;

	/*DPRINTK("idle_timer_check\n");*/
	write_lock(&clip_tbl.lock);
	for (i = 0; i <= NEIGH_HASHMASK; i++) {
		struct neighbour **np;

		for (np = &clip_tbl.hash_buckets[i]; *np;) {
			struct neighbour *n = *np;
			struct atmarp_entry *entry = NEIGH2ENTRY(n);
			struct clip_vcc *clip_vcc;

			for (clip_vcc = entry->vccs; clip_vcc;
			    clip_vcc = clip_vcc->next)
				if (clip_vcc->idle_timeout &&
				    time_after(jiffies, clip_vcc->last_use+
				    clip_vcc->idle_timeout)) {
					DPRINTK("releasing vcc %p->%p of "
					    "entry %p\n",clip_vcc,clip_vcc->vcc,
					    entry);
					atm_async_release_vcc(clip_vcc->vcc,
					    -ETIMEDOUT);
				}
			if (entry->vccs ||
			    time_before(jiffies, entry->expires)) {
				np = &n->next;
				continue;
			}
			if (atomic_read(&n->refcnt) > 1) {
				struct sk_buff *skb;

				DPRINTK("destruction postponed with ref %d\n",
				    atomic_read(&n->refcnt));
				while ((skb = skb_dequeue(&n->arp_queue)) !=
				     NULL) 
					dev_kfree_skb(skb);
				np = &n->next;
				continue;
			}
			*np = n->next;
			DPRINTK("expired neigh %p\n",n);
			n->dead = 1;
			neigh_release(n);
		}
	}
	mod_timer(&idle_timer, jiffies+CLIP_CHECK_INTERVAL*HZ);
	write_unlock(&clip_tbl.lock);
}
예제 #19
0
static void xfrm6_dst_destroy(struct dst_entry *dst)
{
	struct xfrm_dst *xdst = (struct xfrm_dst *)dst;

	if (likely(xdst->u.rt6.n))
		neigh_release(xdst->u.rt6.n);
	if (likely(xdst->u.rt6.rt6i_idev))
		in6_dev_put(xdst->u.rt6.rt6i_idev);
	dst_destroy_metrics_generic(dst);
	if (rt6_has_peer(&xdst->u.rt6)) {
		struct inet_peer *peer = rt6_peer_ptr(&xdst->u.rt6);
		inet_putpeer(peer);
	}
	xfrm_dst_destroy(xdst);
}
예제 #20
0
int arp_invalidate(struct net_device *dev, __be32 ip)
{
	struct neighbour *neigh = neigh_lookup(&arp_tbl, &ip, dev);
	int err = -ENXIO;

	if (neigh) {
		if (neigh->nud_state & ~NUD_NOARP)
			err = neigh_update(neigh, NULL, NUD_FAILED,
					   NEIGH_UPDATE_F_OVERRIDE|
					   NEIGH_UPDATE_F_ADMIN);
		neigh_release(neigh);
	}

	return err;
}
예제 #21
0
static int
__teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res,
	       struct net_device *dev, struct netdev_queue *txq,
	       struct neighbour *mn)
{
	struct teql_sched_data *q = qdisc_priv(txq->qdisc);
	struct neighbour *n = q->ncache;

	if (mn->tbl == NULL)
		return -EINVAL;
	if (n && n->tbl == mn->tbl &&
	    memcmp(n->primary_key, mn->primary_key, mn->tbl->key_len) == 0) {
		atomic_inc(&n->refcnt);
	} else {
		n = __neigh_lookup_errno(mn->tbl, mn->primary_key, dev);
		if (IS_ERR(n))
			return PTR_ERR(n);
	}
	if (neigh_event_send(n, skb_res) == 0) {
		int err;
		char haddr[MAX_ADDR_LEN];

		neigh_ha_snapshot(haddr, n, dev);
		err = dev_hard_header(skb, dev, ntohs(skb->protocol), haddr,
				      NULL, skb->len);

		if (err < 0) {
			neigh_release(n);
			return -EINVAL;
		}
		teql_neigh_release(xchg(&q->ncache, n));
		return 0;
	}
	neigh_release(n);
	return (skb_res == NULL) ? -EAGAIN : 1;
}
예제 #22
0
static int arp_req_delete(struct arpreq *r, struct net_device * dev)
{
	int err;
	__be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
	struct neighbour *neigh;

	if (r->arp_flags & ATF_PUBL) {
		__be32 mask =
		       ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr;
		if (mask == htonl(0xFFFFFFFF))
			return pneigh_delete(&arp_tbl, &ip, dev);
		if (mask == 0) {
			if (dev == NULL) {
				IPV4_DEVCONF_ALL(PROXY_ARP) = 0;
				return 0;
			}
			if (__in_dev_get_rtnl(dev)) {
				IN_DEV_CONF_SET(__in_dev_get_rtnl(dev),
						PROXY_ARP, 0);
				return 0;
			}
			return -ENXIO;
		}
		return -EINVAL;
	}

	if (dev == NULL) {
		struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip,
							 .tos = RTO_ONLINK } } };
		struct rtable * rt;
		if ((err = ip_route_output_key(&rt, &fl)) != 0)
			return err;
		dev = rt->u.dst.dev;
		ip_rt_put(rt);
		if (!dev)
			return -EINVAL;
	}
	err = -ENXIO;
	neigh = neigh_lookup(&arp_tbl, &ip, dev);
	if (neigh) {
		if (neigh->nud_state&~NUD_NOARP)
			err = neigh_update(neigh, NULL, NUD_FAILED,
					   NEIGH_UPDATE_F_OVERRIDE|
					   NEIGH_UPDATE_F_ADMIN);
		neigh_release(neigh);
	}
	return err;
}
예제 #23
0
int arp_req_delete(struct arpreq *r, struct net_device * dev)
{
	int err;
	u32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
	struct neighbour *neigh;

	if (r->arp_flags & ATF_PUBL) {
		u32 mask =
		       ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr;
		if (mask == 0xFFFFFFFF)
			return pneigh_delete(&arp_tbl, &ip, dev);
		if (mask == 0) {
			if (dev == NULL) {
				ipv4_devconf.proxy_arp = 0;
				return 0;
			}
			if (__in_dev_get(dev)) {
				__in_dev_get(dev)->cnf.proxy_arp = 0;
				return 0;
			}
			return -ENXIO;
		}
		return -EINVAL;
	}

	if (dev == NULL) {
		struct flowi fl = { .nl_u = { .ip4_u = { .daddr = ip,
							 .tos = RTO_ONLINK } } };
		struct rtable * rt;
		if ((err = ip_route_output_key(&rt, &fl)) != 0)
			return err;
		dev = rt->u.dst.dev;
		ip_rt_put(rt);
		if (!dev)
			return -EINVAL;
	}
	err = -ENXIO;
	neigh = neigh_lookup(&arp_tbl, &ip, dev);
	if (neigh) {
		if (neigh->nud_state&~NUD_NOARP)
			err = neigh_update(neigh, NULL, NUD_FAILED, 1, 0);
		neigh_release(neigh);
	}
	return err;
}
예제 #24
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;
}
예제 #25
0
파일: arp.c 프로젝트: 274914765/C
static int arp_req_get(struct arpreq *r, struct net_device *dev)
{
    __be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr;
    struct neighbour *neigh;
    int err = -ENXIO;

    neigh = neigh_lookup(&arp_tbl, &ip, dev);
    if (neigh) {
        read_lock_bh(&neigh->lock);
        memcpy(r->arp_ha.sa_data, neigh->ha, dev->addr_len);
        r->arp_flags = arp_state_to_flags(neigh);
        read_unlock_bh(&neigh->lock);
        r->arp_ha.sa_family = dev->type;
        strlcpy(r->arp_dev, dev->name, sizeof(r->arp_dev));
        neigh_release(neigh);
        err = 0;
    }
    return err;
}
예제 #26
0
파일: arp.c 프로젝트: AlexShiLucky/linux
static int arp_invalidate(struct net_device *dev, __be32 ip)
{
	struct neighbour *neigh = neigh_lookup(&arp_tbl, &ip, dev);
	int err = -ENXIO;
	struct neigh_table *tbl = &arp_tbl;

	if (neigh) {
		if (neigh->nud_state & ~NUD_NOARP)
			err = neigh_update(neigh, NULL, NUD_FAILED,
					   NEIGH_UPDATE_F_OVERRIDE|
					   NEIGH_UPDATE_F_ADMIN, 0);
		write_lock_bh(&tbl->lock);
		neigh_release(neigh);
		neigh_remove_one(neigh, tbl);
		write_unlock_bh(&tbl->lock);
	}

	return err;
}
int clip_setentry(struct atm_vcc *vcc,u32 ip)
{
	struct neighbour *neigh;
	struct atmarp_entry *entry;
	int error;
	struct clip_vcc *clip_vcc;
	struct rtable *rt;

	if (vcc->push != clip_push) {
		printk(KERN_WARNING "clip_setentry: non-CLIP VCC\n");
		return -EBADF;
	}
	clip_vcc = CLIP_VCC(vcc);
	if (!ip) {
		if (!clip_vcc->entry) {
			printk(KERN_ERR "hiding hidden ATMARP entry\n");
			return 0;
		}
		DPRINTK("setentry: remove\n");
		unlink_clip_vcc(clip_vcc);
		return 0;
	}
	error = ip_route_output(&rt,ip,0,1,0);
	if (error) return error;
	neigh = __neigh_lookup(&clip_tbl,&ip,rt->u.dst.dev,1);
	ip_rt_put(rt);
	if (!neigh)
		return -ENOMEM;
	entry = NEIGH2ENTRY(neigh);
	if (entry != clip_vcc->entry) {
		if (!clip_vcc->entry) DPRINTK("setentry: add\n");
		else {
			DPRINTK("setentry: update\n");
			unlink_clip_vcc(clip_vcc);
		}
		link_vcc(clip_vcc,entry);
	}
	error = neigh_update(neigh,llc_oui,NUD_PERMANENT,1,0);
	neigh_release(neigh);
	return error;
}
예제 #28
0
static int clip_learn(struct clip_vcc *clip_vcc, u32 ip)
{
    struct neighbour *neigh;
    struct atmarp_entry *entry;
    int error;

    if (!ip)
    {
	if (!clip_vcc->entry)
	{
	    printk(KERN_ERR "hiding hidden ATMARP entry\n");
	    return 0;
	}
	DPRINTK("setentry: remove\n");
	unlink_clip_vcc(clip_vcc);
	return 0;
    }

    neigh = __neigh_lookup(&clip_tbl, &ip, clip_vcc->dev, 1);
    if (!neigh)
	return -ENOMEM;
    del_timer(&clip_vcc->resolve_timer);
    clip_vcc->resolve_timeout = 0; /* Mark resolved */
    entry = NEIGH2ENTRY(neigh);
    if (entry != clip_vcc->entry)
    {
	if (!clip_vcc->entry)
	    DPRINTK("setentry: add\n");
	else
	{
	    DPRINTK("setentry: update %p\n", clip_vcc->entry);
	    unlink_clip_vcc(clip_vcc);
	}
	link_vcc(clip_vcc, entry);
    }
    error = neigh_update(neigh, llc_oui, NUD_PERMANENT, 1, 0);
    entry->expires = jiffies + CLIP_ENTRY_EXPIRE;
    neigh_release(neigh);
    return error;
}
예제 #29
0
/* Obtain the correct destination MAC address, while preserving the original
 * source MAC address. If we already know this address, we just copy it. If we
 * don't, we use the neighbour framework to find out. In both cases, we make
 * sure that br_handle_frame_finish() is called afterwards.
 */
int br_nf_pre_routing_finish_bridge(struct net *net, struct sock *sk, struct sk_buff *skb)
{
	struct neighbour *neigh;
	struct dst_entry *dst;

	skb->dev = bridge_parent(skb->dev);
	if (!skb->dev)
		goto free_skb;
	dst = skb_dst(skb);
	neigh = dst_neigh_lookup_skb(dst, skb);
	if (neigh) {
		struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
		int ret;

		if (neigh->hh.hh_len) {
			neigh_hh_bridge(&neigh->hh, skb);
			skb->dev = nf_bridge->physindev;
			ret = br_handle_frame_finish(net, sk, skb);
		} else {
			/* the neighbour function below overwrites the complete
			 * MAC header, so we save the Ethernet source address and
			 * protocol number.
			 */
			skb_copy_from_linear_data_offset(skb,
							 -(ETH_HLEN-ETH_ALEN),
							 nf_bridge->neigh_header,
							 ETH_HLEN-ETH_ALEN);
			/* tell br_dev_xmit to continue with forwarding */
			nf_bridge->bridged_dnat = 1;
			/* FIXME Need to refragment */
			ret = neigh->output(neigh, skb);
		}
		neigh_release(neigh);
		return ret;
	}
free_skb:
	kfree_skb(skb);
	return 0;
}
예제 #30
0
파일: dst.c 프로젝트: dmgerman/original
void dst_destroy(struct dst_entry * dst)
{
	struct neighbour *neigh = dst->neighbour;
	struct hh_cache *hh = dst->hh;

	dst->hh = NULL;
	if (hh && atomic_dec_and_test(&hh->hh_refcnt))
		kfree(hh);

	if (neigh) {
		dst->neighbour = NULL;
		neigh_release(neigh);
	}

	atomic_dec(&dst->ops->entries);

	if (dst->ops->destroy)
		dst->ops->destroy(dst);
	if (dst->dev)
		dev_put(dst->dev);
	atomic_dec(&dst_total);
	kmem_cache_free(dst->ops->kmem_cachep, dst);
}