1) Equipment that can directly package exchange between the hardware layers of the network interface device constitute a local area network, each of the local area networks has a unique hardware address. For the TCPIP protocol, each of the local area network has a unique IP address. When IP Packets have to send devices with another IP address from a device, the source device must obtain the hardware address of the SBS device, which requires hardware address resolution. Thearp protocol is based on the IP of the device. The address acquires its hardware address. Source device broadcasts the address parsing request to the LAN, and the remaining devices in the LAN received the request, and the device with the request IP address makes a response to the source device, providing its hardware address. ARP request broadcast feature, a device can respond to requests that are not from IP addresses, which is ARP proxy. 2) In the Linux kernel, the network interface device that will be able to communicate directly with the hardware layer directly "Neighbor", uses the neighbour structure description, which contains the hardware address information of the device. All IP packages in the system are sent to the interface device through the neighbor binding neighbors. Neighbors are indexed by the neighbor watch (ARP_TBL), with neighbors The IP address can query neighbors of a device in the neighbor table. 3) When the neighbor receives the IP packet to be sent, if the hardware address of the neighbor is not parsed, the sending package is temporarily buffered in the ARP_QUEUE queue, and then transmits address resolution. Request, this time is an unfinished state (NUD_INCOMPLETE). If you do not receive an external device answer within 1 second, the neighbor will resend the ARP request. If it reaches 3 times, the resolution fails, the neighbor is a failure (NUD_FAILED). When receiving the correct response, the neighbor enters the connection status (NUD_REACHABLE), at this time, the sending package in ARP_QUEUE will be sent to the device after being created. 4) The relationship between the neighbor's IP address and the hardware address is not fixed, the system is receiving When the neighbor's IP package, it will confirm the IP address of the "Confirm) and the mapping relationship of the hardware address. At the same time, the neighbor table scans the neighbor every 60 seconds, and the NEIGH_PERIDIC_TIMER is periodically, on the one hand, from the table clearing those resolution failures. And long (60 seconds) neighbors, on the other hand, identify neighbors that confirm the time out of time, turn them from the connection state into an expiration state (NUD_STALE). When the neighbor is sent to the IP package in the expiration, it will enter Delayed state (NUD_DELAY), if the neighbor's hardware address is still confirmed in the delayed state, the neighbor sends an ARP request. At this time, the detection status (NUD_PROBE) is entered. In the probe state, the IP package does not buffer, still use The expired neighbor address is sent, if the detection failed, the neighbor entry failed. 5) The transmission path of the IP package to the device is shortened. The frame head buffer structure (hh_cache) is introduced on the neighbor structure. If the neighbor is established, the IP package will send out the output of the frame head buffer. When the neighbor is in the connection state When the frame head buffer output directs DEV_QUEUE_XMIT (), when in an expiration state, the frame head buffer output is switched to the neighbor's output port, and the neighbor's output port points to Neigh_Resolve_Output (), neigh_connect () and neigh_suspect () () Two functions are used to perform such switches. 6) When the system is a request response to an external device ARP, the system will create the neighbor of the external device in ARP_TBL, and the refresh is an expired state. When receiving the address of other devices When the request is parsed, the system will refresh the neighbor of the source device to an expiration state. When the single sent it is self-contained, the destination IP address is not an ARP request from the host address, if the device is confirmed and the IP is defined by the agent table, Bush them to the Proxy_Queue queue, wait a random time to respond, prevent the target device from congestion, provide a self-contained device address. This part is a bit complicated, there are many details, I can only write so much, welcome Everyone is guided. Now, the problem is: In what circumstances must I use ARP proxy?; Net / IPv4 / ip_output.c: static inline int ip_finish_output2 (STRUCT SK_BUFF * SKB) IP package send out {struct DST_ENTRY * DST = SKB- > DST; Routing structure of the IP package Struct hh_cache * hh = dst-> hh;
SRI frame header buffer #ifdef CONFIG_NETFILTER_DEBUG nf_debug_ip_finish_output2 (skb); # endif / * CONFIG_NETFILTER_DEBUG * / if (hh) {if non-empty routing header buffer read_lock_bh (& hh-> hh_lock); memcpy (skb-> data - 16, HH-> HH_DATA, 16); Create a hardware frame head read_unlock_bh (& hh-> hh_lock); SKB_PUSH (SKB, HH-> hh_len); Return HH-> HH_OUTPUT (SKB); ELSE IF (DST-> neighbour) Return DST-> NEIGHBOUR-> OUTPUT (SKB); Printk (Kern_Debug "khm / n"); kfree_skb (skb); return-device;}; net / ipv4 / arp.c , core / neighbour.c: #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 can not be deleted by garbage collectors * / # define NUD_IN_TIMER (NUD_INCOMPLETE | NUD_DELAY | NUD_PROBE).. #defineNUD_VALID (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE | NUD_PROBE | NUD_STALE | NUD_DELAY) #define NUD_CONNECTED (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE) #define NEIGH_HASHMASK 0x1F # define PNEIGH_HASHMASK 0xFstruct neigh_table network neighbor 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;.! (60 seconds) int gc_thresh1; (128) int gc_thresh2; (512) int gc_thresh3 (1024) 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];}; struct neigh_parms neighborhood parameters {struct neigh_parms * next; int (* neigh_setup) (struct neighbour *); struct neigh_table * tbl; int entries; void * priv; void * sysctl_table; int base_reachable_time; (30 seconds Int retrans_time; (1 second) int GC_STALETIME; (60 seconds) int RECHABLE_TIME; (30 seconds) int delay_probe_time; (5 second) int queue_len; (3) int ucast_probes; (3) int App_Probes; (0) int MCAST_PROBES ; (3) int anycast_delay; (1 seconds) int proxy_delay; (0.8 seconds) int proxy_qlen; (64) int locktime; (1 seconds)}; struct neighbour network neighborhood structure {struct neighbour * next; struct neigh_table * tbl; struct Neigh_Parms * Parms; Struct Net_Device * dev; unsigned long set; unsigned long upd; unsigned long upd ated; __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 hh_cache header buffer structure {struct hh_cache * hh_next ; / * Next entry * / atomic_t hh_refcnt; / * number of users * / unsigned short hh_type; / * protocol identifier, fe ETH_P_IP * / int hh_len; / * length of header * / int (* hh_output) (struct sk_buff * skb ); rwlock_t hh_lock; / * cached hardware header;
. Allow for machine alignment needs * / unsigned long hh_data [16 / sizeof (unsigned long)];}; struct neigh_table arp_tbl = arp network neighbor table for the index information of neighbor TCPIP network protocol {NULL, AF_INET, sizeof (struct Neighbour 4, 4, ARP_HASH, ARP_CONSTRUctor, NULL, NULL, PARP_REDO, ARP_CACHE, {NULL, NULL, & ARP_TBL, 0, NULL, NULL, 30 * HZ, 1 * Hz, 60 * Hz, 30 * Hz, 5 * Hz, 3, 3, 0, 3, 1 * Hz, (8 * hz) / 10, 64, 1 * Hz}, 30 * Hz, 128, 512, 1024,}; void __init arp_init (void) address parsing module initialization {neigh_table_init (& arp_tbl); initialize arp protocol network neighbors resolution table dev_add_pack (& arp_packet_type); Register address resolution packet receiver proc_net_create ( "arp", 0, arp_get_info); # ifdef CONFIG_SYSCTL neigh_sysctl_register (NULL, & arp_tbl.parms, NET_IPV4 , NET_IPV4_NEIGH, "ipv4"); # endif} static struct neigh_table * neigh_tables; all network neighbor list resolution table void neigh_table_init (struct neigh_table * tbl) {unsigned long now = jiffies; tbl-> parms.reachable_time = neigh_rand_reach_time (tbl- > PARMS.BASE_RECHABLE_TIME); if (TBL-> KMEM_CACHEP == NULL) TBL-> KMEM_CACHEP = KMEM_CACHE_CREATE (TBL-> ID, (TBL-> Entry_Size 15) & ~ 15, 0, SLAB_HWCACHE_ALIGN, NULL, NULL); neighbor information networking architecture memory allocator #ifdef CONFIG_SMP tasklet_init (& tbl-> gc_task, SMP_TIMER_NAME (neigh_periodic_timer), (unsignedlong) tbl); # endif init_timer (& tbl-> gc_timer ); tbl-> lock = RW_LOCK_UNLOCKED; tbl-> gc_timer.data = (unsigned long) tbl; tbl-> gc_timer.function = neigh_periodic_timer; tbl-> gc_timer.expires = now tbl-> gc_interval tbl-> parms. REACHABLE_TIME; add_timer; init_timer (& tbl-> proxy_timer; tbl-> proxy_timer.data = (unsigned long) TBL; TBL-> proxy_timer.function = neigh_proxy_process;
skb_queue_head_init (& tbl-> proxy_queue); tbl-> last_flush = now; tbl-> last_rand = now tbl-> parms.reachable_time * 20; write_lock (& neigh_tbl_lock); tbl-> next = neigh_tables; neigh_tables = tbl; write_unlock (& neigh_tbl_lock );} unsigned long neigh_rand_reach_time (unsigned long base) taken around (base / 2) a random number {return (net_random ()% base) (base >> 1);} static void SMP_TIMER_NAME (neigh_periodic_timer) (unsigned long arg ) {struct neigh_table * tbl = (struct neigh_table *) arg; unsigned long now = jiffies; int i; write_lock (& tbl-> lock); / * * periodicly recompute ReachableTime from random function * / if (now - tbl-> last_rand > 300 * hz) {struct neigh_parms * p; tbl-> last_rand = now; for (p = & tbl-> parms; p; p = p-> next) P-> reachable_time = neigh_rand_reach_time (p-> base_reachable_time);} For (i = 0; i <= neigh_hashmask; i ) {Scan all network neighbors Struct neighbour * n, ** np; np = & tbl-> hash_buckets
WHILE ((n = * np)! = null) {unsigned state; write_lock (& n-> Lock); state = n-> nud_state; if (state & (nud_permanent | nud_in_timer) {For neighbors that are unsealed or parsed Write_unlock; goto next_lt;} if ((long) (n-> used - n-> confirmed <0) n-> subsid = n-> confirmed; if (atomic_read (& n-> refcnt) == 1 && (state == NUD_FAILED || Now - n-> subsage> n-> parms-> gc_staletime))) {* np = n-> next; release those parsing failures and neighbors exceeding (60) seconds N-> dead = 1; write_unlock; neigh_release (n); continue;} if (n-> nud_state & nud_reachable &&ow - n-> confirmed> n-> parms-> reachable_time) {n-> nud_state = NUD_STALE; if the parsing time is greater than the timeout, the neighbor's address fails neigh_suspect (n);} Write_unlock (& n-> lock); Next_lt: np = & n-> next;}} mod_timer (& tbl-> gc_timer, now tbl-> gc_interval); write_unlock (& tbl-> lock);} int arp_bind_neighbour (struct dst_entry * dst) to bind to a routing neighbor {struct net_device * dev = dst-> dev; struct neighbour * n = dst-> neighbour ; if (dev == null) Return-EinVal; if (n == null) {u32 nexthop = ((struct RTable *) DST) -> RT_GATEWAY; Take the gateway address if (dev-> flan gs & (IFF_LOOPBACK | IFF_POINTOPOINT)) nexthop = 0; n = __neigh_lookup_errno (#ifdef CONFIG_ATM_CLIP dev-> type == ARPHRD_ATM & clip_tbl:? #endif & arp_tbl, & nexthop, dev); query destination address nexthop equipment neighbors if (IS_ERR in arp_tbl in (n)) return PTR_ERR (n); dst-> neighbour = n;} return 0;} 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); created in the neighbor table, a new device neighbor} struct neighbour * neigh_lookup (struct neigh_table * tbl, const void * pkey, struct net_device * dev) {struct neighbour * n; u32 hash_val; int Key_LEN = TBL-> Key_Len; Hash_Val = TBL-> Hash (PKEY, DEV); calculates the index key of the neighbor, read_lock_bh (& tbl-> lock); for (n = tbl-> hash_buckets [hash_val]; n; n = n- > next) {if (dev == n-> dev && memcmp (n-> primary_key, pkey, key_len) == 0) {neigh_hold (n); break;}} read_unlock_bh (& tbl-> lock); return n; } Static U32 ARP_HASH (Const Void * PKey, Const struct net_device * dev) {u32 hash_val; hash_val = * (u32 *) pkey; hash_val ^ = (haveh_val >> 16); haveh_val = Hash_VAL >> 8; haveh_val ^ = hash_val >> 3; hash_val = (hash_val ^ dev-> ifindex) & NEIGH_HASHMASK; return hash_val;} struct neighbour * neigh_create (struct neigh_table * tbl, const void * pkey, struct net_device * dev) {struct neighbour * n, * n1; U32 hash_val; int key_len = tbl-> key_len; int error; n = neigh_alloc (tbl); creates new neighbor if (n == null) return err_ptr (-Enobufs) for neighbor table TBL; Memcpy (N-> PR); memcpy IMARY_KEY, PKEY, Key_LEN; copy neighbor's key value n-> dev = dev; dev_hold (dev); / * protocol specific setup. * / if (TBL-> Constructor && (Error = TBL-> Constructor (n)) <0) {neigh_release (n); return err_ptr (error);} / * device specific setup. * / If (n-> parms && n-> parms-> neigh_setup && (Error = n-> PARMS-> neigh_setup N)) <0) {neigh_release (n); return err_ptr (error);} n-> confirmed = Jiffies - (N-> PARMS-> Base_reachable_time << 1); haveh_val = tbl-> hash (pkey, dev) Write_lock_bh (& TBL-> Lock); for (n1 = tbl->
Hash_buckets [hash_val]; n1; n1 = n1-> next) {if (dev == n1-> dev && memory (n1-> primary_key, pkey, key_len) == 0) {neigh_hold (n1); if the neighbor watch If you have a key, you will release a new neighbor. Return to existing neighbors write_unlock_bh (& tbl-> lock); neigh_release (n); return n1;}} n-> next = tbl-> hash_buckets [hash_val]; tbl-> hash_buckets [ Hash_val] = n; Insert Index Chain N-> Dead = 0; Neigh_Hold (N); Write_Unlock_BH (& TBL-> Lock); Neigh_Printk2 ("Neigh% P IS Created./N", N); Return N;} Static Struct Neighbour * neigh_alloc (struct neigh_table * tbl) Assign neighbor structure {struct neighbour * n; unsigned long now = jiffies; if (TBL-> Entries> TBL-> gc_thresh3 || If the number of cells of the neighbor table exceeds (1024) (TBL -> Entries> TBL-> GC_THRESH2 && or exceeded (512) and NOW - TBL-> Last_Flush> 5 * Hz)) {The last refresh interval exceeds 5 seconds if (neigh_forced_gc (tbl) == 0 && release neighbor tbl-> entries> tbl-> gc_thresh3) return NULL;} n = kmem_cache_alloc (tbl-> kmem_cachep, SLAB_ATOMIC); if (n == NULL) return NULL; memset (n, 0, tbl-> entry_size); skb_queue_head_init (& n-> arp_queue); When the address of the neighbor is not parsed, the packet buffer to the neighbor is n-> lock = rw_lock_unlocked; n-> Updated = N-> Used = now; n-> nud_state = nud_none; n-> output = neigh_blackhole; neighbor's IP income entrance n-> PARMS = & tbl-> PARMS; inheriting the parameters of the neighbor watch Init_timer (& n-> Timer) ; N-> Timer.Function = neigh_timer_handler; Receive timeout traveler n-> timer.data = (unsigned long) n; tbl-> stats.allocs ; neigh_glbl_allocs ; tbl-> entries ; n-> tbl = tbl; atomic_set (& n-> refcnt, 1); n-> dead = 1; return n;} static int neigh_blackhole (struct SK_Buff * SKB) {kfree_sk (SKB); Return -Enetdown;
} static int neigh_forced_gc (struct neigh_table * tbl) Forced release of neighbor {int shrunk = 0; int 1; for (i = 0; i <= neigh_hashmask; i ) {struct neighbour * n, ** np; np = & tbl-> Hash_buckets; write_lock_bh (& TBL-> Lock); while ((n = * np)! = null) {/ * neighbour record May Be discarded if: - Nobody refers to it. - it is not premanent - (New and Probably Wrong) INCOMPLETE entries are kept at least for n-> parms-> retrans_time, otherwise we could flood network with resolution requests It is not clear, what is better table overflow or flooding * / write_lock (& n-> lock);.. if (atomic_read (& n-> refcnt) == 1 &&! (N-> NUD_STATE & NUD_PERMANENT "&& (n-> nud_state! = nud_incumplete || jiffies - n-> used> n-> parms-> retrans_time)) {* np = n- > next; n-> dead = 1; shrunk = 1; write_unlock; neigh_release (n); continue;} Write_unlock (& n-> lock); np = & n-> next;} Write_unlock_bh (& TBL- > LOCK);} TBL-> Last_flush = Jiffies; Return Shrunk;} static inline void neigh_release (Struct Neig hbour * neigh) {if (atomic_dec_and_test (& neigh-> refcnt)) neigh_destroy (neigh);} static int neigh_del_timer (struct neighbour * n) {if (n-> nud_state & NUD_IN_TIMER) {if (del_timer (& n-> timer) ) {neigh_release (n); return 1;}} return 0;} void neigh_destroy (struct neighbour * {struct hh_cache * hh neigh);! if (neigh-> dead) {printk ( "Destroying alive neighbour% p from% 08lx / N ", neigh, * ((unsigned long *) & neighh))))); return;}} (neigh_del_timer (neigh)) Printk (" Impossible Event./N "); while ((hh = neigh-> HH)! =
NULL) {neigh-> hh = hh-> hh_next; hh-> hh_next = NULL; write_lock_bh (& hh-> hh_lock); hh-> hh_output = neigh_blackhole; write_unlock_bh (& hh-> hh_lock); if (atomic_dec_and_test (& hh-> HH_REFCNT)) Kfree (HH);} Clear network neighbors frame head buffer IF (neigh-> ops-> destructor) (neighh) (neighh); SKB_QUE_PURGE (& neigh-> arp_queue ); Clear neighbor's IP package buffer queue DEV_PUT (neigh-> dev); neigh_printk2 ("neigh% p is destroyed./n", neigh_glbl_allocs -; neigh-> tbl-> entries ---; kmem_cache_free (neighh) -> tbl-> kmem_cachep, neigh);} / * As fast as possible without hh cache * / static __inline__ int neigh_max_probes (struct neighbour * n) {struct neigh_parms * p = n-> parms; return p-> ucast_probes p -> app_probes p-> mcast_probes;} static void neigh_timer_handler (unsigned long arg) {unsigned long now = jiffies; struct neighbour * neigh = (struct neighbour *) arg; unsigned state; int notify = 0; write_lock (& neigh-> LOCK); state = neigh-> nud_state; if (! (! ") {#ifndef config_smp printk (" neigh: Timer &! NUD_IN_TIMER / N "); # endif goto out;} if ((state & NUD_VALID) && now - neigh-> confirmed
neigh-> tbl-> stats.res_failed ; NEIGH_PRINTK2 ( "neigh% p is failed./n", neigh); / * It is very thin place report_unreachable is very complicated routine Particularly, it can hit the same neighbour entry..! So that, we try to be accurate and avoid dead loop. --ANK * / while (neigh-> nud_state == NUD_FAILED && (skb = __ skb_dequeue (& neigh-> arp_queue))! = NULL) {write_unlock (& neigh-> lock ); neigh-> ops-> error_report (neigh, skb); Write_lock (& Neigh-> Lock);} SKB_QUE_PURGE (& Neigh-> arp_queue); goto out;} neigh-> timer.expires = now neigh-> PARMS- > retrans_time; add_timer; write_unlock (& neigh-> lock); neigh-> ops-> solicit (neigh, skb_peek (& neigh-> arp_queue)); Reissue ARP request atomic_inc_inc_inc (& neigh-> probes); return; out: write_unlock (& neigh-> lock); # ifdef CONFIG_ARPD if (notify && neigh-> parms-> app_probes) neigh_app_notify (neigh); # endif neigh_release (neigh);} static int arp_constructor (struct neighbour * neigh) { U32 addr = * (u32 *) neigh-> primary_key; primary key is the neighbor's IP address strunt net_device * dev = neigh-> dev; neighbor Hosting equipment Struct in_Device * in_dev = in_dev_get (dev); if (in_dev == null) return-Einval; neigh-> type = inet_addr_type (addr); Net neighbors IP address type if (in_dev-> arp_parms) neighh -> PARMS = IN_DEV-> ARP_PARMS; Inherited device ARP parameter IN_DEV_PUT (in_dev); if (dev-> hard_header == null) {neigh-> nud_state = NUD_NOARP; Neigh-> Ops = & arp_direct_ops; Install Direct Operation Table NeighH- > OUTPUT = neigh-> ops-> queue_xmit;
The output function of the neighbors of (dev_queue_xmit)} else {/ * Good devices (checked by reading texts, but only Ethernet is tested) ARPHRD_ETHER: (ethernet, apfddi) ARPHRD_FDDI: (fddi) ARPHRD_IEEE802: (tr) ARPHRD_METRICOM: (strip) Arphrd_arcnet: etc. Etc. Etc. Arphrd_Ipddp Will ALSO Work, IF Author Repairs It. I DID Not IT, Because this Driver Does Not Work Even IN Old Paradigm. * / # If 1 / * so ... these "Amateur" Devices . are hopeless The only thing, that I can say now: It is very sad that we need to keep ugly obsolete code to make them happy They should be moved to more reasonable state, now they use rebuild_header INSTEAD OF hard_start_xmit !!! Besides. That, They Are Sort of Out of Date (a Lot of Redundant Clones / Copies, Useless In 2.1), I Wonder Why People Believe That They Work. * / Switch (dev-> type) {Default: Break; Case Arphrd_ROSE: # If defined (config_ax25) || defined (config_ax25_module) case arphrd_ax25: #if defined (config_netrom) || defined (config_net) ROM_MODULE) case ARPHRD_NETROM: #endif neigh-> ops = & arp_broken_ops; neigh-> output = neigh-> ops-> output; return 0; #endif;} # endif if (neigh-> type == RTN_MULTICAST) {neigh-> NUD_STATE = NUD_NOARP; ARP_MC_MAP (Addr, Neigh-> Ha, DEV, 1);} else if (dev-> flags & (iff_noarp | imp_loopback) {neigh-> nud_state = NUD_NOARP; Memcpy (neigh-> ha, dev-> dev_addr, dev-> addr_len);} else if (neigh-> type == RTN_BROADCAST || dev-> flags & IFF_POINTOPOINT) {neigh-> nud_state = NUD_NOARP; memcpy (neigh-> ha, dev-> broadcast, dev-> addr_len );} if (dev-> hard_header_cache) neigh-> ops = & arp_hh_ops; installing neighbor frame head buffer ELSE neigh-> ops = &
ARP_GENERIC_OPS; if (neigh-> nud_state & nud_valid) address has parsed neigh-> output = neigh-> ops-> connection_output; send else neigh-> output = neigh-> ops-> output; first parsing redemption} returnography; } 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 *); (* hh_output) (struct sk_buff *) int; int (* queue_xmit) (struct sk_buff *);}; static struct neigh_ops arp_direct_ops = None analytical transmission {AF_INET, NULL, NULL, NULL, dev_queue_xmit, dev_queue_xmit, dev_queue_xmit, dev_queue_xmit}; struct neigh_ops arp_broken_ops = not fully resolve {AF_INET, NULL, arp_solicit, arp_error_report, neigh_compat_output, neigh_compat_output, dev_queue_xmit, dev_queue_xmit,}; int neigh_compat_output (struct SK_BUFF * SKB) {struct net_device * dev = SKB-> dev; __skb_pull (SKB, SKB-> NH.RAW - SKB-> DATA); if (dev-> hard_header && dev-> hard_header (SKB, DEV, NTOHS SKB-> Protocol, N ULL, NULL, skb-> len) <0 && dev-> rebuild_header (skb)) return 0; return dev_queue_xmit (skb);} static struct neigh_ops arp_hh_ops = parse through the header buffer {AF_INET, NULL, arp_solicit, arp_error_report, neigh_resolve_output , neigh_resolve_output, dev_queue_xmit, dev_queue_xmit}; int neigh_resolve_output (struct sk_buff * skb) {struct dst_entry * dst = skb-> dst; struct neighbour * neigh; if goto discard (dst || (neigh = dst-> neighbour)!!) ; __skb_pull (SKB, SKB-> NH.RAW - SKB-> DATA); if (neigh_event_send (neigh, skb) == 0) {int err; struct net_device * dev = neigh-> dev; if (dev-> hard_header_cache && dst-> hh ==
NULL) {WRITE_LOCK_BH (& Neigh-> Lock); if (dst-> hh == null) neigh_hh_init (neigh, dst, dst-> ops-> protocol); err = dev-> hard_header (SKB, DEV, NTOHS (SKB -> protocol, neigh-> ha, null, skb-> len); Write_unlock_bh (& neigh-> lock);} else {read_lock_bh (& neigh-> lock); err = dev-> hard_header (SKB, DEV, NTOHS SKB-> Protocol, Neigh-> ha, null, skb-> len); read_unlock_bh (& neigh-> lock);} if (err> = 0) Return neigh-> ops-> queue_xmit (SKB); kfree_skb (SKB Return-EinVal;} Return 0; Discard: Neigh_Printk1 ("Neigh_Resolve_output: DST =% P NEigh =% P / N", DST, DST? DST-> neighbour: null); kfree_skb (SKB); Return-EinVal; } static void neigh_hh_init (struct neighbour * n, struct dst_entry * dst, u16 protocol) {struct hh_cache * hh = null; struct net_device * dev = dst-> dev; for (hh = n-> hh; hh; hh = hh -> hh_next) if (hh-> hh_type == protocol) Break; if (! hh && (hh = kmalloc (hhof)! = null) {MEMSET (HH, 0, Sizeof (Struct hh_cache ))); hh-> hh_lock = rw_lock_unlocked; hh-> hh_type = protocol; atomic_set (& hh-> hh_refcnt , 0); hh-> hh_next = null; if (dev-> hard_header_cache (n, hh)) {kfree (hh); hh = null;} else {atomic_inc (& hh-> hh_refcnt); hh-> hh_next = n -> hh; n-> hh; if (n-> nud_state & nud_connected) If the device address is valid hh-> hh_output = n-> ops-> hh_output; inherit the neighbor's frame head buffer output Else HH-> hh_output = n- > ops-> output; inherit the output of the neighbor}} f (hh) {atomic_inc (& hh-> hh_refcnt); dst-> hh = HH;}} static struct neigh_ops arp_generic_ops =
{AF_INET, NULL, arp_solicit, arp_error_report, neigh_resolve_output, neigh_connected_output, dev_queue_xmit, dev_queue_xmit}; int neigh_connected_output (struct sk_buff * skb) {int err; struct dst_entry * dst = skb-> dst; struct neighbour * neigh = dst-> neighbour; Struct Net_Device * dev = neigh-> dev; __skb_pull (SKB, SKB-> NH.RAW - SKB-> DATA); read_lock_bh (& neigh-> lock); err = dev-> hard_header (SKB, DEV, NTOHS (SKB- > protocol), neigh-> ha, null, skb-> len); read_unlock_bh (& neigh-> lock); if (Err> = 0) Return neigh-> ops-> queue_xmit (SKB); Kfree_skb (SKB); Return -EINVAL;} static inline int neigh_event_send (struct neighbour * neigh, struct sk_buff * skb) {neigh-> used = jiffies; (! (neigh-> nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))) if return __neigh_event_send (neigh, skb ); return 0;} int __neigh_event_send (struct neighbour * neigh, struct sk_buff * skb) {write_lock_bh (& neigh-> lock);! if ((neigh-> nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))!) {if (( Neigh-> NUD_STATE & (NUD_STALE | NUD_INCOMPLETE))) {IF (nei gh-> parms-> mcast_probes neigh-> parms-> app_probes) {atomic_set (& neigh-> probes, neigh-> parms-> ucast_probes); neigh-> nud_state = NUD_INCOMPLETE; neigh_hold (neigh); neigh-> timer. Expires = Jiffies Neigh-> PARMS-> RETRANS_TIME; Next Resend Time Add_timer (& Neigh-> Timer); Write_Unlock_BH (& Neigh-> Lock); Neigh-> Ops-> Solicit (neigh, skb); atomic_inc (& neighh- > probes); write_lock_bh (& neigh-> lock);} else {neigh-> nud_state = NUD_FAILED; write_unlock_bh (& neigh-> lock); if (skb) kfree_skb (skb); return 1;}} if (neigh-> nud_state ==
NUD_INCOMPLETE) {if (skb) {if (skb_queue_len (& neigh-> arp_queue)> = neigh-> parms-> queue_len) {struct sk_buff * buff; buff = neigh-> arp_queue.prev; __skb_unlink (buff, & neigh-> arp_queue ); kfree_skb (buff);} __skb_queue_head (& neigh-> arp_queue, skb);} write_unlock_bh (& neigh-> lock); return 1;} if (neigh-> nud_state == NUD_STALE) {NEIGH_PRINTK2 ( "neigh% p is delayed ./n ", neigh); neigh_hold (neigh); neigh-> nud_state = NUD_DELAY; neigh-> timer.expires = jiffies neigh-> parms-> delay_probe_time; add_timer (& neigh-> timer);}} write_unlock_bh (& neigh -> lock); return 0;} static void arp_solicit (struct neighbour * neigh, struct sk_buff * skb) arp request {u32 saddr; u8 * dst_ha = NULL; struct net_device * dev = neigh-> dev; u32 target = * ( U32 *) neigh-> primary_key; 取 = i 地址 地址 INT probes = atomic_read (& neigh-> probes); if (SKB && INET_ADDR_TYPE (SKB && INET_ADDR_TYPE (SKB-> NH.IPH-> Saddr) == RTN_LOCAL) SADDR = SKB-> NH .iph-> saddr; else saddr = inet_select_addr (dev, target, rt_scope_link); if ((probes - = neigh-> parms-> ucast_probes) <0) { (! (Neigh-> nud_state & NUD_VALID)) if printk (KERN_DEBUG "trying to ucast probe in NUD_INVALID / n"); dst_ha = neigh-> ha; read_lock_bh (& neigh-> lock);} else if ((probes - = neigh- > parms-> app_probes) <0) {#ifdef CONFIG_ARPD neigh_app_ns (neigh); # endif return;} arp_send (ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr, dst_ha, dev-> dev_addr, NULL); if (dst_ha) read_unlock_bh (& neigh-> lock);} struct arphdr {unsigned short ar_hrd; hardware address format Unsigned short ar_pro; protocol address format Unsigned char Ar_hln; Hardware address length UNSIGNED CHAR AR_PLN;
Protocol address length unsigned short ar_op; command code #if 0 / * * Ethernet looks like this: This bit is variable sized however ... * / unsigned char ar_sha [ETH_ALEN]; / * sender hardware address * / unsigned char ar_sip [4 ]; / * sender ip address * / unsigned char ar_tha [eth_alen]; / * target hardware address * / unsigned char ar_tip [4]; / * target ip address * / # endif}; void ARP_SEND (int Type, int ptype, u32 dest_ip, struct net_device * dev, u32 src_ip, unsigned char * dest_hw, unsigned char * src_hw, unsigned char * target_hw) {struct sk_buff * skb; struct arphdr * arp; unsigned char * arp_ptr; / * * No arp on this interface * / if (dev-> flags & iff_noarp) return; / * * allocate a buffer * / SKB = alloc_skb (Struct Arphdr) 2 * (dev-> addr_len 4) dev-> hard_header_len 15, gfp_atomic) Create an address resolution package buffer IF (SKB == NULL) Return; SKB_RESERVE (SKB, (Dev-> HARD_HEADER_LEN 15) & ~ 15); retain hardware frame head area, 16-byte align SKB-> nh.raw = SKB-> DATA; Setup header pointer arp = (struct arphdr *) SKB_PUT (SKB, SIZEOF (Struct Arphdr) 2 * (dev-> addr_len 4); Data area SKB-> DEV = DEV; package transmission device SKB-> protocol = __constant_htons (eth_p_arp); Setting package type if (src_hw == null) src_hw = dev-> dev_addr; if the source The hardware address is empty, the hardware address IF of the device is taken (dest_hw == null) dest_hw = dev-> Broadcast; if the resider hardware address is empty, take the device broadcast address / * * Fill the device header for the arp frame * / if (dev-> hard_header && dev-> hard_header (SKB, DEV, PTYPE, DEST_HW, SRC_HW, SKB-> LEN) <0) Hardware Framehead for assembly packages.
/ * * Fill out the arp protocol part. * * The arp hardware type should match the device type, except for FDDI, * which (according to RFC 1390) should always equal 1 (Ethernet). * / / * * Exceptions everywhere. AX.25 Uses The AX.25 PID Value NOT The * DIX CODE for the Protocol. Make these Device Structure Fields. * / Switch (dev-> type) {Default: arp-> ar_hrd = htons (dev-> type); type device type taken as an address of the address resolution packet arp-> ar_pro = __constant_htons (ETH_P_IP); break; #if defined (CONFIG_AX25) || defined (CONFIG_AX25_MODULE) case ARPHRD_AX25: arp-> ar_hrd = __constant_htons (ARPHRD_AX25); arp-> ar_pro = __constant_htons (AX25_P_IP); break; #if defined (CONFIG_NETROM) || defined (CONFIG_NETROM_MODULE) case ARPHRD_NETROM: arp-> ar_hrd = __constant_htons (ARPHRD_NETROM); arp-> ar_pro = __constant_htons (AX25_P_IP); break; # endif # endif #ifdef CONFIG_FDDI case ARPHRD_FDDI: arp-> ar_hrd = __constant_htons (ARPHRD_ETHER); arp-> ar_pro = __constant_htons (ETH_P_IP); break; # endif # ifdef CONFIG_TR case ARPHRD_IEEE802_TR: arp-> ar_hrd = __const Ant_htons (arphrd_ieee802); arp-> ar_pro = __constant_htons (eth_p_ip); break; #ENDIF} arp-> ar_hln = dev-> addr_len; set hardware address length ARP-> ar_pln = 4; set protocol address length ARP-> ar_op = Htons (TYPE); set the address parsing operation code arp_ptr = (ARP 1); pointing the parameter area of the packet Memcpy (arp_ptr, src_hw, dev-> addr_len); set the source hardware address ARP_PTR = dev-> Addr_len; Memcpy (ARP_PTR, & SRC_IP, 4); Setting source IP address arp_ptr = 4; if (target_hw! = null) Memcpy (arp_ptr, target_hw, dev-> addr_len); Else Memset (ARP_PTR, 0, Dev-> addr_len) ARP_PTR = dev-> addr_len; memcpy (arp_ptr, & dest_ip, 4); set the destination IP address SKB-> DEV = dev; dev_queue_xmit (SKB); Return; Out: kfree_skb (SKB);
} Static struct packet_type arp_packet_type = {__constant_htons (ETH_P_ARP), NULL, / * All devices * / arp_rcv, (void *) 1, NULL}; static inline int skb_shared (struct sk_buff * skb) {return (atomic_read (& skb-> users !) = 1);} static inline struct sk_buff * skb_share_check (struct sk_buff * skb, int pri) {if (skb_shared (skb)) {struct sk_buff * nskb; nskb = skb_clone (skb, pri); kfree_skb (skb); return nskb;} return skb;} # define IN_DEV_PROXY_ARP (in_dev) (ipv4_devconf.proxy_arp || (in_dev) -> cnf.proxy_arp) #define IN_DEV_FORWARD (in_dev) ((in_dev) -> cnf.forwarding) int arp_rcv (struct sk_buff * skb, struct net_device * dev, struct packet_type * pt) {struct arphdr * arp = skb-> nh.arph; unsigned char * arp_ptr = (unsigned char *) (arp 1); struct rtable * rt; unsigned char * sha, * tha; u32 sip, tip; u16 dev_type = dev-> type; int addr_type; struct in_device * in_dev = in_dev_get (dev); struct neighbour * n; / * * The hardware length of the packet should match the hardware length * of the device. Similarly, The Hardware Typ Es Should Match. The * Device Should Be Arp-Able. Also, IF Pln IS Not 4, THEN The Lookup * Is Not from An IP Number. We can't Currently Handle this, so Toss * it. * / if (in_DEV == NULL || If the device has not opened ARP-> ar_hln! = Dev-> addr_len || If the hardware address length does not match dev-> flags & iff_noarp || If the device does not need ARP SKB-> PKT_TYPE == Packet_otherhost | It is a package SKB-> pkt_type == packet_loopback || == NULL) GOTO OUT_OF_MEM; Switch (dev_type) {default: if (arp-> ar_pro! = __Constant_htons (eth_ip)) goto output; if (htons (dev_type)! =
arp-> ar_hrd) goto out; break; #ifdef CONFIG_NET_ETHERNET case ARPHRD_ETHER:. / * * ETHERNET devices will accept ARP hardware types of either * 1 (Ethernet) or 6 (IEEE 802.2) * / if (arp-> ar_hrd =! __constant_htons (ARPHRD_ETHER) && arp-> ar_hrd = __constant_htons (ARPHRD_IEEE802)) goto out; if (arp-> ar_pro = __constant_htons (ETH_P_IP!)) goto out; break; # endif # ifdef CONFIG_TR case ARPHRD_IEEE802_TR:! / * * Token ring . devices will accept ARP hardware types of either * 1 (Ethernet) or 6 (IEEE 802.2) * / if (arp-> ar_hrd = __constant_htons (ARPHRD_ETHER) && arp-> ar_hrd = __constant_htons (ARPHRD_IEEE802)!!) goto out; if (arp-> ar_pro = __constant_htons (ETH_P_IP)!) goto out; break; # endif # ifdef CONFIG_FDDI 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 (IEEE 802.2). * / if (arp-> ar_hrd! = __constant_htons (arphrd_ther) && arp-> ar_hrd! = __con stant_htons (ARPHRD_IEEE802)) goto out; if (arp-> ar_pro = __constant_htons (ETH_P_IP!)) goto out; break; # endif # if defined (CONFIG_AX25) || defined (CONFIG_AX25_MODULE) case ARPHRD_AX25: if (arp-> ar_pro! = __constant_htons (AX25_P_IP)) goto out; if (arp-> ar_hrd = __constant_htons (ARPHRD_AX25!)) goto out; break; #if defined (CONFIG_NETROM) || defined (CONFIG_NETROM_MODULE) case ARPHRD_NETROM: if (arp-> ar_pro =! __constant_htons (AX25_P_IP)) goto out; if (arp-> ar_hrd = __constant_htons (ARPHRD_NETROM!)) goto out; break;! # endif # endif} / * Understand only these message types * / if (arp-> ar_op =
__constant_htons (arpop_reply) && arp-> ar_op! = __constant_htons (arpop_request)) goto output; only process "response" and "request" two opcodes / * * extract fields * / SHA = ARP_PTR; point to the parameter area hardware address ARP_PTR = dev-> addr_len; memcpy (& SIP, ARP_PTR, 4); sender IP address ARP_PTR = 4; THA = ARP_PTR; the hardware address ARP_PTR = dev-> addr_len; memcpy (& TIP, ARP, ARP_PTR) , 4); Take the (to) parsed IP address / * check for bad requests for 127.xxx and requests for multicast * addresses. If this is one such, delete it. * / If (loopback (tip) || Multicast (TIP)) goto out; / * * Process Entry. The IDEA Here IS WANT TO Send a reply if it is a request for US or if it is a request for Someone else That We Hold * a proxy for............................................................................................................................................................................................................................... want to add an entry to our cache if it is a reply * to us or if it is a request for our address. * (The assumption for this last is that if someone is requesting our * address, they are probably intending to talk to US, SO It Saves Time * if we cache their address. Their address is also probably not in * out * ur cache, Since ours is not In their cache.) * * Putting this Another Way, We Only Care About Replies If They is to * us, in which case we add the the the cache. for requests, We Care * About those for US and those forur proxies. We reply to Both, * and in the copy of requests for US we add the requester to the arp * cache. * / / * Special case: IPv4 duplicate address detection packet (rfc2131) * / if (SIP == 0) {If The sender IP address is zero IF (ARP-> ar_op == __constant_htons (arpop_request) && inet_addr_type (tip) == RTN_LOCAL) If the IP address to be resolved is the host's IP address arp_send (arpop_reply, eth_p_arp, tip, dev, TIP, SHA, DEV-> dev_addr, dev-> dev_addr); goto out;} if (arp->
Ar_op == __constant_htons (arpop_request) && od_route_input (SKB, TIP, SIP, 0, DEV) == 0) {Query destination address routing RT = (struct RTable *) SKB-> DST; addr_type = RT on input device DEV -> RT_TYPE; if (addr_type == == == rc) {n = neigh_event_ns (& ARP_TBL, SHA, & SIP, DEV); refresh the neighbor of the requesting device to "expire" status if (n) {arp_send (arpop_reply, eth_p_arp, sip, dev, dev , TIP, SHA, DEV-> DEV_ADDR, SHA); neigh_release (n);} goto out;} else if (in_dev_forward (in_dev)) {if ((rt-> rt_flags & rtcf_dnat) || (addr_type == RTN_UNICAST && RT- > u.dst.dev! = dev && (IN_DEV_PROXY_ARP (IN_DEV) || Pneigh_lookup (& Arp_TBL, & TIP, DEV, 0))))) {n = neigh_event_ns (& Arp_TBL, SHA, & SIP, DEV); if (n) neigh_release n); if (SKB-> stamp.tv_sec == 0 || If it is proxy_queue's REDO package SKB-> pkt_type == packet_host || If it is a packet in_dev-> arp_parms-> proxy_delay == 0) { arp_send (ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha, dev-> dev_addr, sha);} else {pneigh_enqueue (& arp_tbl, in_dev-> arp_parms, skb); buffer request packet for the delay processing in_dev_put (in_dev); return 0;} goto out;}}}; received a response package or non-already request package / * update Our ARP tables * / n = __neigh_lookup (& arp_tbl, & sip, dev, 0); Looking for the sender IP neighbor #ifdef CONFIG_IP_ACCEPT_UNSOLICITED_ARP / * Unsolicited ARP is not accepted by default It is possible, that this option should be enabled for some devices (. strip is candidate) * / if (n == NULL && arp-> ar_op == __constant_htons (ARPOP_REPLY) && inet_addr_type (sip) == RTN_UNICAST) n = __neigh_lookup (& arp_tbl, & sip, dev, -1); # endif if ( N) {int State = NUD_REACHABLE; int override = 0;
. / * If several different ARP replies follows back-to-back, use the FIRST one It is possible, if several proxy agents are active Taking the first reply prevents arp trashing and chooses the fastest router * / if (jiffies -.. N -> updated> = n-> parms-> locktime) override = 1; / * Broadcast replies and request packets do not assert neighbour reachability * / if || skb-> pkt_type. (arp-> ar_op = __constant_htons (ARPOP_REPLY!) ! = PACKET_HOST) state = NUD_STALE; neigh_update (n, sha, state, override, 1); neigh_release (n);} out: kfree_skb (skb); if (in_dev) in_dev_put (in_dev); out_of_mem: return 0;} struct neighbour * neigh_event_ns (struct neigh_table * tbl, u8 * lladdr, void * saddr, struct net_device * dev) will refresh a neighbor as "expired" status {struct neighbour * neigh; neigh = __neigh_lookup (tbl, saddr, dev, lladdr ||! dev-> addr_len); if (neigh) neigh_update (neigh, lladdr, NUD_STALE, 1, 1); return neigh;} static inline struct neighbour * __ neigh_lookup (struct neigh_table * tbl, const void * pkey, struct net_device * dev, intcreat) {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;} int neigh_update (struct neighbour * neigh, const u8 * lladdr, u8 new, int override, intarp) {u8 old; int err; int notify = 0; struct net_device * dev = neigh-> dev; write_lock_bh (& neigh- > lock); old = neigh-> nud_state; err = -EPERM; if (arp && (old & (NUD_NOARP | NUD_PERMANENT))) goto out; if (! (new & NUD_VALID)) {neigh_del_timer (neigh); if (old & NUD_CONNECTED) neigh_suspect (neighh); neigh-> nud_state = new; err = 0; Notify = Old & NUD_VALID; GOTO OUT
} / * Compare new lladdr with cached one * / if (dev-> addr_len == 0) {/ * first case: Device Needs no address. * / Lladdr = neigh-> ha;} else if (LLADDR) {/ * The second case: if something is already cached and a new address is proposed: - compare new & old - if they are different, check override flag * / if (old & NUD_VALID) {if (memcmp (lladdr, neigh-> ha, dev- > addr_len) == 0) LLADDR = neigh-> HA; Else if (!!) goto out;}} else {/ * no address is support; if we know something, use it, ostherwise discard the request. * / err = -EINVAL; if goto out ((old & NUD_VALID)!); lladdr = neigh-> ha;} neigh_sync (neigh); old = neigh-> nud_state; if (new & NUD_CONNECTED) neigh-> confirmed = jiffies; neigh-> updated = Jiffies; / * if Entry Was Valid and address is not change, do not change entry, if new one is stale. * / err = 0; if (ildr == neigh-> ha) IF (New == OLD || (New == NUD_STALE && (Old & NUD_CONNECTED)) Goto Out;} neigh_del_timer (neighh); neigh-> nud_stat E = New; IF (LLADDR! = neigh-> HA) {Memcpy (& Neigh-> ha, lladdr, dev-> addr_len); neigh_update_hhs (neigh); if (! (! (new & nud_connected) NEigh-> confirmed = Jiffies - ( neigh-> parms-> base_reachable_time << 1); # ifdef CONFIG_ARPD notify = 1; #endif} if (new == old) goto out; if (new & NUD_CONNECTED) neigh_connect (neigh); else neigh_suspect (neigh); if (! (old & NUD_VALID)) {struct sk_buff * skb; / * Again:! avoid dead loop if something went wrong * / while (neigh-> nud_state & NUD_VALID && (skb = __ skb_dequeue (& neigh-> arp_queue)) =
NULL) {struct neighbour * n1 = neigh; write_unlock_bh (& neigh-> lock); / * on shaper / eql skb-> dst-> neighbour! = Neighh :( * / if (SKB-> DST && SKB-> DST- > neighbour) n1 = skb-> dst-> neighbour; n1-> output (skb); write_lock_bh (& neigh-> lock);} skb_queue_purge (& neigh-> arp_queue);} out: write_unlock_bh (& neigh-> lock); # ifdef CONFIG_ARPD if (notify && neigh-> parms-> app_probes) neigh_app_notify (neigh); # endif return err;} static void neigh_sync (struct neighbour * n) {unsigned long now = jiffies; u8 state = n-> nud_state; ASSERT_WL (n); if (state & (nud_noarp | nud_permanent) Return; if (State & NUD_REACHABLE) {if (now - n-> confirmed> N-> PARMS-> REACHABLE_TIME) {n-> nud_state = NUD_STALE; neigh_suspect (n); }} else if (state & NUD_VALID) {if (now - n-> confirmed
Void (* update) (Struct hh_cache *, struct net_device *, unsigned char *) = neigh-> dev-> header_cache_update; if (update) {for (hh = neigh-> hh; hh; hh = hh-> hh_next) {write_lock_bh (& hh-> hh_lock); update (hh, neigh-> dev, neigh-> ha); write_unlock_bh (& hh-> hh_lock);}}} struct pneigh_entry {struct pneigh_entry * next; struct net_device * dev; u8 key [0];}; struct pneigh_entry * pneigh_lookup (struct neigh_table * tbl, const void * pkey, struct net_device * dev, int creat) {struct pneigh_entry * n; u32 hash_val; int key_len = tbl-> key_len; hash_val = * ( U32 *) (PKEY KEY_LEN - 4); Hash_VAL ^ = (Hash_Val >> 16); hash_val = Hash_VAL >> 8; Hash_VAL ^ = Hash_VAL >> 4; Hash_VAL & = Pneigh_hashmask; Read_Lock_BH (& TBL-> LOCK); For (n = tbl-> phash_buckets [hash_val]; n; n = n-> next) {if (Memcmp (N-> Key, PKey, Key_len) == 0 && (n-> dev == dev ||! N-> dev)) {read_unlock_bh (& TBL-> Lock); returnck_}}}}}}}}}}}; if (! creat) Return Null; N = kmalloc (Sizeof (* n) KEY_LEN, GFP_KERNEL) ; if (n == null) Return NUL L; Memcpy (n-> key, pkey, key_len); N-> dev = dev; if (TBL-> PConstructor && tbl-> pconstructor (n)) {kfree (n); return null;} Write_lock_bh (& TBL- > lock); n-> next = tbl-> phash_buckets [hash_val]; tbl-> phash_buckets [hash_val] = n; write_unlock_bh (& tbl-> lock); return n;} void pneigh_enqueue (struct neigh_table * tbl, struct neigh_parms * P, STRUCT SK_BUFF * SKB) Buffer external device ARP request package {Unsigned long now = jiffies; long scheduter_next = net_random ()% p-> proxy_delay; next delay interval (within 0.8 seconds) IF (TBL-> proxy_queue.qlen > P->
proxy_qlen) {kfree_skb (skb); return;} skb-> stamp.tv_sec = 0; skb-> stamp.tv_usec = now sched_next; spin_lock (& tbl-> proxy_queue.lock); if (del_timer (& tbl-> proxy_timer) ) {long TVal = TBL-> proxy_timer.expires - now; Time remaining time IF (tval