#ifndef _NET_NEIGHBOUR_H #define _NET_NEIGHBOUR_H /* * Generic neighbour manipulation * * Authors: * Pedro Roque * Alexey Kuznetsov */ /* The following flags & states are exported to user space, so that they should be moved to include/linux/ directory. */ /* * Neighbor Cache Entry Flags */ #define NTF_PROXY 0x08 /* == ATF_PUBL */ #define NTF_ROUTER 0x80 /* * Neighbor Cache Entry States. */ #define NUD_INCOMPLETE 0x01 #define NUD_REACHABLE 0x02 #define NUD_STALE 0x04 #define NUD_DELAY 0x08 #define NUD_PROBE 0x10 #define NUD_FAILED 0x20 /* Dummy states */ #define NUD_NOARP 0x40 #define NUD_PERMANENT 0x80 #define NUD_NONE 0x00 /* NUD_NOARP & NUD_PERMANENT are pseudostates, they never change and make no address resolution or NUD. NUD_PERMANENT is also cannot be deleted by garbage collectors. */ #ifdef __KERNEL__ #include #include #define NUD_IN_TIMER (NUD_INCOMPLETE|NUD_DELAY|NUD_PROBE) #define NUD_VALID (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE|NUD_PROBE|NUD_STALE|NUD_DELAY) #define NUD_CONNECTED (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE) struct neigh_parms { struct neigh_parms *next; int (*neigh_setup)(struct neighbour *); struct neigh_table *tbl; int entries; void *priv; void *sysctl_table; int base_reachable_time; int retrans_time; int gc_staletime; int reachable_time; int delay_probe_time; int queue_len; int ucast_probes; int app_probes; int mcast_probes; int anycast_delay; int proxy_delay; int proxy_qlen; int locktime; }; struct neigh_statistics { unsigned long allocs; unsigned long res_failed; unsigned long rcv_probes_mcast; unsigned long rcv_probes_ucast; }; struct neighbour { struct neighbour *next; struct neigh_table *tbl; struct neigh_parms *parms; struct net_device *dev; unsigned long used; unsigned long confirmed; unsigned long updated; __u8 flags; __u8 nud_state; __u8 type; __u8 dead; atomic_t probes; rwlock_t lock; unsigned char ha[(MAX_ADDR_LEN+sizeof(unsigned long)-1)&~(sizeof(unsigned long)-1)]; struct hh_cache *hh; atomic_t refcnt; int (*output)(struct sk_buff *skb); struct sk_buff_head arp_queue; struct timer_list timer; struct neigh_ops *ops; u8 primary_key[0]; }; struct neigh_ops { int family; void (*destructor)(struct neighbour *); void (*solicit)(struct neighbour *, struct sk_buff*); void (*error_report)(struct neighbour *, struct sk_buff*); int (*output)(struct sk_buff*); int (*connected_output)(struct sk_buff*); int (*hh_output)(struct sk_buff*); int (*queue_xmit)(struct sk_buff*); }; struct pneigh_entry { struct pneigh_entry *next; struct net_device *dev; u8 key[0]; }; #define NEIGH_HASHMASK 0x1F #define PNEIGH_HASHMASK 0xF /* * neighbour table manipulation */ struct neigh_table { struct neigh_table *next; int family; int entry_size; int key_len; __u32 (*hash)(const void *pkey, const struct net_device *); int (*constructor)(struct neighbour *); int (*pconstructor)(struct pneigh_entry *); void (*pdestructor)(struct pneigh_entry *); void (*proxy_redo)(struct sk_buff *skb); char *id; struct neigh_parms parms; /* HACK. gc_* shoul follow parms without a gap! */ int gc_interval; int gc_thresh1; int gc_thresh2; int gc_thresh3; unsigned long last_flush; struct timer_list gc_timer; struct timer_list proxy_timer; struct sk_buff_head proxy_queue; int entries; rwlock_t lock; unsigned long last_rand; struct neigh_parms *parms_list; kmem_cache_t *kmem_cachep; struct tasklet_struct gc_task; struct neigh_statistics stats; struct neighbour *hash_buckets[NEIGH_HASHMASK+1]; struct pneigh_entry *phash_buckets[PNEIGH_HASHMASK+1]; }; extern void neigh_table_init(struct neigh_table *tbl); extern int neigh_table_clear(struct neigh_table *tbl); extern struct neighbour * neigh_lookup(struct neigh_table *tbl, const void *pkey, struct net_device *dev); extern struct neighbour * neigh_create(struct neigh_table *tbl, const void *pkey, struct net_device *dev); extern void neigh_destroy(struct neighbour *neigh); extern int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb); extern int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, int override, int arp); extern int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev); extern int neigh_resolve_output(struct sk_buff *skb); extern int neigh_connected_output(struct sk_buff *skb); extern int neigh_compat_output(struct sk_buff *skb); extern struct neighbour *neigh_event_ns(struct neigh_table *tbl, u8 *lladdr, void *saddr, struct net_device *dev); extern struct neigh_parms *neigh_parms_alloc(struct net_device *dev, struct neigh_table *tbl); extern void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms); extern unsigned long neigh_rand_reach_time(unsigned long base); extern void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, struct sk_buff *skb); extern struct pneigh_entry *pneigh_lookup(struct neigh_table *tbl, const void *key, struct net_device *dev, int creat); extern int pneigh_delete(struct neigh_table *tbl, const void *key, struct net_device *dev); struct netlink_callback; struct nlmsghdr; extern int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb); extern int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg); extern int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg); extern void neigh_app_ns(struct neighbour *n); extern int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, int p_id, int pdev_id, char *p_name); extern void neigh_sysctl_unregister(struct neigh_parms *p); /* * Neighbour references */ static inline void neigh_release(struct neighbour *neigh) { if (atomic_dec_and_test(&neigh->refcnt)) neigh_destroy(neigh); } static inline struct neighbour * neigh_clone(struct neighbour *neigh) { if (neigh) atomic_inc(&neigh->refcnt); return neigh; } #define neigh_hold(n) atomic_inc(&(n)->refcnt) static inline void neigh_confirm(struct neighbour *neigh) { if (neigh) neigh->confirmed = jiffies; } static inline int neigh_is_connected(struct neighbour *neigh) { return neigh->nud_state&NUD_CONNECTED; } static inline int neigh_is_valid(struct neighbour *neigh) { return neigh->nud_state&NUD_VALID; } static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) { neigh->used = jiffies; if (!(neigh->nud_state&(NUD_CONNECTED|NUD_DELAY|NUD_PROBE))) return __neigh_event_send(neigh, skb); return 0; } static inline struct neighbour * __neigh_lookup(struct neigh_table *tbl, const void *pkey, struct net_device *dev, int creat) { struct neighbour *n = neigh_lookup(tbl, pkey, dev); if (n || !creat) return n; n = neigh_create(tbl, pkey, dev); return IS_ERR(n) ? NULL : n; } static inline struct neighbour * __neigh_lookup_errno(struct neigh_table *tbl, const void *pkey, struct net_device *dev) { struct neighbour *n = neigh_lookup(tbl, pkey, dev); if (n) return n; return neigh_create(tbl, pkey, dev); } #endif #endif