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; }
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; }
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; }
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); } }
/* * 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; }
/* * 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; }
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; }
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; }
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; }
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; }
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; }
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; }
/* * 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); }
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; }
/* 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; }
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; }
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); }
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); }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
/* 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; }
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); }