Linux hardware address resolution process

xiaoxiao2021-03-05  24

Linux hardware address resolution process 1) Device that can be directly packaged between the hardware layers of the network interface device constitute a local area network, each of the local area network has a unique hardware address. For the TCPIP protocol, the local area network Each device has a unique IP address. When the IP Packet has a device that has another IP address from a device, the source device must obtain the hardware address of the SBS device, which requires the hardware address resolution .arp The protocol is a method of obtaining its hardware address based on the IP address of the device. Source device broadcasts the address parsing request to the LAN, and the remaining devices in the local area network receive the request, and the device with the request IP address will respond to the source device, provide Its hardware address. Due to the broadcast feature of the ARP request, a device can respond to requests not from the IP address, which is the ARP agent. 2) In the Linux kernel, other networks that are directly communicated directly with the hardware layer The interface device is called "neighbor", with the Neighbour structure description, it contains hardware address information of the device. All IP packages in the system are sent to the interface device through the routing neighbors. Neighbor is indexed by a neighbor watch (ARP_TBL) The neighbor's IP address can query a neighbor in the neighbor table. 3) When the IP package to be sent, if the neighbor's hardware address (MAC) has not parsed, the sending package is temporarily buffered in the arp_queue queue. Then send [Address Resolution] request, then the state of the neighbor is the unfinished state (NUD_INCOMPLETE). If there is no ARP answer in 1 second, the ARP request will be reused. If it reaches 3 times, the resolution failed, the neighbor failed State (NUD_FAILED). When receiving the correct response, the neighbor enters the connection status (NUD_REACHABLE), then 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. When the system receives the IP packet from the neighbor, it will confirm the mapping relationship of the IP address of the neighbors (the neighbor table scans the neighbor every 60 seconds, on the one hand from the table from the table every 60 sec. Clear those neighbors unused and long (60 seconds), on the other hand, identify neighbors that have timed the timeout, turn them from the connection state into an expiration state (NUD_STALE). When the neighbor sends IP in the expiration When the package, enter the delayed state (NUD_DELAY), if the neighbor's hardware address is still confirmed after the delayed state is still confirmed, the neighbor sends an ARP request, then enters the probe state (NUD_PROBE). In the probe state, the IP package is not Buffer, still use expired neighbor address, if the detection failed, Neighbor entering failure state. 5) In order to shorten the transmission path of the IP package to the device, the frame head buffer structure (hh_cache) is introduced on the neighbor structure. If the neighbor has established a frame head buffer, the IP package will transmit through the frame head buffer Out. When the neighbor is in the connection state, the frame head buffer output directs DEV_QUE_XMIT (), when in an expiration state, the frame head buffer output is switched to the neighbor's output port, and the ethernet device is pointed, 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 answers the request for external device ARP, the system will create the neighbor of the external device in ARP_TBL, refresh is an expiration state. When receiving an address resolution request for other devices, the system will refresh the neighbor of the source device to an expiration state. When the single is sent to self, but the destination IP address is not an ARP request from the host address, if the device is allowed to forward and IP is defined by the proxy table, buffers them to the proxy_queue queue, waiting for a random time to respond, prevent the target device congestion, providing the other party's own device address. This part is a bit complicated, and there are many details have not yet been cleared. I can only write so much. Welcome everyone. Now I have the problem: Under what circumstances must be used?; Net / IPv4 / ip_output.c: static inline int ip_finish_output2 (STRUCT SK_BUFF * SKB) IP package transmission exit {STRUCT DST_ENTRY * DST = SKB-> DST; Take the 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_ITERVAL; (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 seconds) int gc_staletime; (60 seconds) int reachable_time; (30 seconds) int delay_probe_time; (5 seconds) int queue_len; (3) int ucast_probes; (3) int App_Probes; (0) INT MCAST_PROBES; (3) INT Anycast_delay; (1 second) int proxy_delay; (0.8) int proxy_qlen; (64) int LockTime; (1 second)}; struct neighbour network neighbor structure { 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 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_THH_LOCK;

/ * cached hardware header; allow for machine alignment neseds. * / unsigned long hh_data [16 / sizeof (unsigned long);}; struct neigh_table arp_tbl = // network neighbor table, network neighbor information index in TCPIP 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 resolution 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_REACHABLE_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 (& TBL-> GC_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); ST ATE = N-> NUD_STATE; if (State & (NUD_PERMANENT | NUD_IN_TIMER) {For neighboring_unlock (& ​​n-> lock); goto next_lt;} if ((long) (n-> used - n- > confirmed <0) N-> Used = n-> confirmed; if (atomic_read (& n-> refcnt) == 1 && (state == NUD_FAILED || Now - n-> used> n-> PARMS-> GC_STALETIME )) {* np = N-> Next; release those neighbors of resolution failure and reference time exceeding (60) seconds; write_unlock; neigh_release (n); continue;} if N-> NUD_STATE & NUD_REACHABLE &&

Now - n-> confirmed> n-> parms-> reachable_time) {n-> nud_state = NUD_STALE; if the parser is greater than the timeout, the neighbor's address failed neigh_suspect (n);} Write_Unlock (& ​​n-> lock); Next_lt: np = & n-> next;}} mod_timer (& TBL-> GC_TIMER, WRITE_UNLOCK;} int ARP_BIND_NEIGHBOUR (STRUCT DST_ENTRY * DST) Binds the neighbor to the specified route {struct net_device * dev = dst-> dev; struct neighbour * n = dst-> neighbour; if (dev == null) return-device; if (n == null) {u32 nexthop = (Struct RTable *) DST ) -> rt_gateway; take the gateway address if (dev-> flags & (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);? querying the target address nexthop in arp_tbl the device neighbor if (IS_ERR (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_cre ate (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 a new neighbor if (n == null) return err_ptr (-Enobufs) for neighbor table TBL; Memcpy (N-> Primary_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 there is a key in the neighbor table, release a new neighbor, return an existing neighbor 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) assigned neighbor structure {struct neighbour * n; unsigned long now = jiffies; if (tbl-> entries> tbl-> gc_thresh3 || neighbor table if the number of cells exceeds (1024 (TBL-> Entries> TBL-> GC_THRESH2 && or exceeds (512) and NOW - TBL-> Last_Flush> 5 * Hz)) {NEIGH_FORCED_GC (TBL) == 0 && with the last refresh interval Release the outdated 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-> usd = now; n- > NUD_STATE = NUD_NONE; N-> Output = neigh_blackhole; Neighbor's IP Pack Inlet N-> PARMS = & TBL-> PARMS; inheriting the parameters of the neighbor watch infit_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_skb (SKB); RETURN -ENETDOWN;} static int neigh_forced_gc (struct neigh_table * tbl) Forced release of neighbor {INT Shrunk = 0; int i; 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 & NU (N-> NUD_STATATE! = NUD_INCOMPLETE || 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 neighbour * 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 neighbour * neigh) {struct hh_cache * hh; if (! neigh-> dead) {Printk "Destroying Alive Neighbour% P FROM% 08LX / N ", NEIGH, * ((unsigned long *) & neighh) - 1)))); return;} if (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) KFree (HH);} Clear Network Neighbors Frame Buffer IF (Neigh-> OPS && Neigh-> OPS-> Destructor) (neigh-> ops-> destructor) (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 (neigh-> 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;} f ((State & nud_valid) && now - neigh-> confirmed parms-> reachable_time) {neigh-> nud_state = NUD_REACHABLE; NEIGH_PRINTK2 ( "neigh% p is still alive./n", neigh); neigh_connect (neigh); goto out;} if (state == NUD_DELAY ) {Neigh_printk2 ("Neigh% P is probed./n", neighh); neigh-> NUD_STATE = NUD_PROBE; atomic_set (& neigh-> probes, 0);} if (atomic_read (& neigh-> probes)> = neigh_max_probes (neigh)) {struct sk_buff * skb; neigh-> nud_state = NUD_FAILED; notify = 1; 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_queue_purge (& neigh-> arp_queue); goto Out;} neigh-> time.expires = now neigh-> parms-> retrans_time; add_timer (& neigh-> time); write_unlock (& ​​neigh-> lock); neigh-> ops-> Solicit (neigh, skb_peek (& neighh- > arp_queue)); arp retransmission request atomic_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 IP address of the neighbor struct net_device * dev = neigh-> dev; taken neighbor where Host device struct in_device * in_dev = in_dev_get (dev); if (in_dev == null) Return-EinVal; neigh-> type = inet_addr_type (addr); Net neighbor 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; Direct action table mounted neigh-> output = neigh-> ops-> queue_xmit; the output is a function of the neighbor (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 * / # ix / * 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 (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_NETROM_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 | iff_loopback) {neigh-> NUD_STATE = NUD_NOARP; Memcpy (neigh-> ha, dev-> dev_addr, dev-> addr_len);} else} (neigh-> TYP) e == 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; buffering operation of mounting header neighbor else neigh-> ops = & arp_generic_ops; if (neigh-> nud_state & NUD_VALID) address is resolved neigh-> output = neigh-> ops-> connected_output; directly transmitting else neigh-> output = neigh -> OPS-> OUTPUT; first parsing and then send} return 0;} struct neigh_ops {int family; void (* destructor); 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 = no 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), NULL, NULL, SKB-> LEN) <0 && dev-> rebuild_header (SKB)) Return 0; return dev_queue_xmit (SKB );} static struct neigh_ops arp_hh_ops = buffer header by parsing {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 * neighh; if (! dst ||! (neigh = dst-> neighbour) goto discard; __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 (sizeof (* hh), gfp_atomic) )! = 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 = HH; IF (n-> nud_state & nud_connected) If the device address is valid hh-> hh_output = n- > ops-> hh_output; inherit the neighbor frame head buffer output Else HH-> hh_output = n-> ops-> output; inherit the output of the neighbor}} f (hh) {atomic_inc (& 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 * neighh = 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; if) return __neigh_event_send (neigh, skb) ((neigh-> nud_state & (NUD_CONNECTED | | NUD_DELAY NUD_PROBE)!); 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)) (! (neigh-> nud_state & (NUD_STALE | NUD_INCOMPLETE))) {if) {if (neigh-> 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 Renewable time add_timer (& neigh-> Timer); Write_Unlock_bh (& Neigh-> Lock); Nei GH-> OPS-> Solicit (Neigh, SKB); Atomic_inc (& Neigh-> Probes); Write_Lock_BH (& Neigh-> Lock);} else {neigh-> nud_state = nud_failed; Write_Unlock_bh (& Neigh-> Lock); if (SKB Kfree_skb (SKB); Return 1;}} f (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_sk (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_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; an IP address of a neighbor INT probes = atomic_read (& neigh-> probes); if (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) {if (! (! (! (!) Printk) 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 C ONFIG_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 (sizeof (struct arphdr) 2 * (dev-> addr_len 4) dev-> hard_header_len 15, gfp_atomic); create Address Analysis Pack Buffer IF (SKB == Null) Return; SKB_RESERVE (SKB, (Dev-> HARD_HEADER_LEN 15) & ~ 15); Keep hardware frame head area, 16-byte aligned SKB-> nh.raw = SKB- > data; set the header pointer arp = (struct arphdr *) SKB_PUT (SKB, SIZEOF (STRUCT ARPHDR) 2 * (dev-> addr_len 4)));; Assign the address parsing package data area SKB-> dev = dev; Package Transmit Device SKB-> Protocol = __constant_htons (Eth_P_arp); Setting Package Type IF (SRC_HW == Null) SRC_HW = Dev-> DEV_ADDR; if the source hardware address is empty, take the hardware address IF of the device (dest_hw == NULL) DEST_HW = Dev-> Broadcast; if the residual 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 Goto Out; / * * Fill Out The Arp Protocol Part. * * The ARP HARDWARE TYPT 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 = __constant_htons (ARPHRD_IEEE802); arp-> ar_pro = __constant_htons (eth_p_ip); break; #ndif} ARP-> ar_hln = dev-> addr_len; set hardware address length ARP-> ar_pln = 4; set protocol address length ARP-> ar_op = htons (type); set address resolution Operation code arp_ptr = (unsigned char *) (ARP 1); point to the parameter area Memcpy (ARP_PTR, SRC_HW, DEV-> addR_len); set source hardware address ARP_PTR = dev-> addr_len; memcpy (arp_ptr, & src_ip, 4 ); Set the source IP address ARP_PTR = 4; if (target_hw! = NULL) Memcpy (ARP_PTR, TARGET_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 types 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 || If it belongs to the outside Renly bag SKB-> PKT_TYPE == Packet_loopback || ) goto out_of_mem; switch! (dev_type) {default:! if (arp-> ar_pro = __constant_htons (ETH_P_IP)) goto out; 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_ETHER) && arp-> ar_hrd = __constant_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! = __c onstant_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_REQUEST)) goto out (arp-> ar_op = __constant_htons (ARPOP_REPLY!)!; Only deal with "response" and "request" two opcodes / * * extract fields * / SHA = ARP_PTR; point to the parameter area hardware address ARP_PTR = dev-> addr_len; memory (& SIP, ARP_PTR, 4); sender IP Address ARP_PTR = 4; THA = ARP_PTR;

Hardware address arp_ptr = dev-> addr_len; memcpy (& TIP, ARP_PTR, 4); Take the IP address of the (to) parsing / * * 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. We want to add an entry to out ing it is a reply * to US or if it is a request for outfor. * (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 * our cache, since ours is not in Their cache.) * * Putting this Another Way, We Only Care About Replies if the isy * us, in which case we add the the the cache. for requests, we care * about those for us and those for out those. we Reply to Both, * And in the CA Se 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) == r _ 地址) 地址 如果 解 i i i 地址 主 地址 a 地址 a (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) && == 0) {Query destination address in the input device DEV Rt = (struct RTable *) SKB-> DST; addr_type = rt-> rt_type; if (addr_type == = == == rc) {n = neigh_event_ns (& arp_tbl, sha, & sip, dev);

The neighbor of the requesting device is refreshed to "expired" status if (n) {arp_send (arpop_reply, eth_p_arp, sip, 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 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 Pack, delayed IN_DEV_PUT (IN_DEV); Return 0;} goto out;}}; received answering packages or non-already requested packages / * Update Our ARP Tables * / n = __neigh_lookup (& Arp_TBL, & SIP, DEV, 0); Looking for a sender IP neighbor #ifdef config_ip_accept_unsolicited_arp / * unsolicited arp is not an accepted by Default. it is possible, That this option should be enabled for some devices n (strip is candidate) * / if (n == NULL && arp-> ar_op == __constant_htons (ARPOP_REPLY) && inet_addr_type (sip) == RTN_UNICAST) = __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 trasting and chooses the failest router. * / if (Jiffies - n-> Updated> =

n-> parms-> locktime) override = 1; / * Broadcast replies and request packets do not assert neighbour reachability * / if || skb-> pkt_type = PACKET_HOST) state. (arp-> ar_op = __constant_htons (ARPOP_REPLY!)! = 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 NE W, int override, 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 (neigh); 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 (! override) goto out;}} else {/ * no address is support; if we know Something, USE IT , otherwise discard the request * / err = -EINVAL;. if ((old & NUD_VALID)!) goto out; 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 (ild_valid) {if (LLADDR = = neigh-> HA) IF (new == NUD || (new == NUD_STALE && (old & nud_connected))) goto out;} neigh_del_timer (neigh); neigh-> nud_state = 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 {struct sk_buff * skb; / * Again ((old & NUD_VALID)!): avoid dead loop if something went wrong * / while (neigh-> nud_state & NUD_VALID && ( SKB = __ SKB_DEQUEUE (& Neigh-> arp_queue))! = null) {structure 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-> recirmed> n->) {n-> nud_state = nud_stale; neigh_suspect (n);}} else if (state & nud_valid) {if (now - n-> confirmed parms-> reachable_time) {neigh_del_timer (n); n-> nud_state = NUD_REACHABLE; neigh_connect (n);}}} static void neigh_connect (struct neighbour * neigh) {struct hh_cache * hh; NEIGH_PRINTK2 ( "neigh% p is Connected./N ", Neigh); assert_wl (neigh); neigh-> output = neigh-> ops-> connection_output; for (hh = neigh-> hh; hh; hh = hh-> hh_next) hh-> hh_output = neigh-> ops-> hh_output;} static void neigh_suspect (struct neighbour * neigh) {struct hh_cache * hh; NEIGH_PRINTK2 ( "neigh% p is Suspecteded./N ", neigh); assert_wl (neigh); neigh-> output = neigh-> ops-> output; for (hh = neigh-> hh; hh; hh = hh-> hh_next) hh-> hh_output = neigh-> ops-> output;} static __inline__ void neigh_update_hhs (struct neighbour * neigh) {struct hh_cache * hh; void (* update) (struct hh_cache *, struct net_device *, unsigned char *) = neigh-> dev->

Header_cache_update; if (update) {for (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; haveh_val ^ = Hash_Val >> 4; Hash_Val & = Pneigh_hashmask; Read_Lock_BH (& TBL-> Lock); for (n = tbl-> phash_buckets [hash_val]; n; n = n-> next) {= (Memcmp) (N-> Key, PKey, Key_LEN) == 0 && (N-> DEV == Dev ||! n-> dev)) {read_unlock_bh (& tbl-> lock); returnck_bh (& tbl-> LOCK); if (! creat) return null; n = kmalloc (sizeof (* n) key_len, gfp_kernel); if (n == null) return null; memcpy (n-> key, pkey, key_len); N- > dev = dev; if (tbl-> pco NStructor && 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) buffering external device arp request packet {unsigned long now = jiffies; long sched_next = net_random ( )% p-> proxy_delay; next delay interval (within 0.8 seconds) IF (TBL-> Proxy_QUE.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; get the time being rest Time IF (tval DST); SKB-> DST = NULL; DEV_HOLD (SKB-> dev); __skb_queue_tail (& TBL-> proxy_queue, skb); mod_timer & tbl-> proxy_timer, now sched_next); spin_unlock (& ​​tbl-> proxy_queue.lock);} static void neigh_proxy_process (unsigned long arg) {struct neigh_table * tbl = (struct neigh_table *) arg; long sched_next = 0; unsigned long now = jiffies; struct sk_buff * skb; spin_lock (& ​​tbl-> proxy_queue.lock); skb = tbl-> proxy_queue.next; while (! skb = (struct sk_buff *) & tbl-> proxy_queue) {struct sk_buff * back = skb; Long tdif = back-> stamp.tv_usec - now; SKB = SKB-> Next; IF (TDIF <= 0) {struct net_device * dev = back-> dev; __skb_unlink (back, & tbl-> proxy_queue); if (TBL -> proxy_redo && netif_running (dev)) TBL-> proxy_redo (back); Else Kfree_skb (back); dev_put (dev);} el se if (! sched_next || tdif proxy_timer); if (sched_next) mod_timer (& tbl-> proxy_timer, jiffies sched_next); spin_unlock (& ​​tbl-> proxy_queue.lock); } static void parp_redo (struct sk_buff * skb) {arp_rcv (skb, skb-> dev, NULL);} static void arp_error_report (struct neighbour * neigh, struct sk_buff * skb) {dst_link_failure (skb); kfree_skb (skb);} Static Inline Void DST_LINK_FAILURE (STRUCT SK_BUFF * SKB) {STRUCT DST_ENTRY * DST = SKB-> DST; IF (DST && DST-> OPS && DST-> OPS->

转载请注明原文地址:https://www.9cbs.com/read-38620.html

New Post(0)