| 
				
			 | 
			
			
				
				@@ -19,6 +19,7 @@ 
			 | 
		
		
	
		
			
			| 
				19
			 | 
			
				19
			 | 
			
			
				
				 FILE_LICENCE ( GPL2_OR_LATER ); 
			 | 
		
		
	
		
			
			| 
				20
			 | 
			
				20
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				21
			 | 
			
				21
			 | 
			
			
				
				 #include <stdint.h> 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				22
			 | 
			
			
				
				+#include <stdlib.h> 
			 | 
		
		
	
		
			
			| 
				22
			 | 
			
				23
			 | 
			
			
				
				 #include <string.h> 
			 | 
		
		
	
		
			
			| 
				23
			 | 
			
				24
			 | 
			
			
				
				 #include <byteswap.h> 
			 | 
		
		
	
		
			
			| 
				24
			 | 
			
				25
			 | 
			
			
				
				 #include <errno.h> 
			 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			
				
				@@ -26,6 +27,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); 
			 | 
		
		
	
		
			
			| 
				26
			 | 
			
				27
			 | 
			
			
				
				 #include <ipxe/if_arp.h> 
			 | 
		
		
	
		
			
			| 
				27
			 | 
			
				28
			 | 
			
			
				
				 #include <ipxe/iobuf.h> 
			 | 
		
		
	
		
			
			| 
				28
			 | 
			
				29
			 | 
			
			
				
				 #include <ipxe/netdevice.h> 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				30
			 | 
			
			
				
				+#include <ipxe/list.h> 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				31
			 | 
			
			
				
				+#include <ipxe/retry.h> 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				32
			 | 
			
			
				
				+#include <ipxe/timer.h> 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				33
			 | 
			
			
				
				+#include <ipxe/malloc.h> 
			 | 
		
		
	
		
			
			| 
				29
			 | 
			
				34
			 | 
			
			
				
				 #include <ipxe/arp.h> 
			 | 
		
		
	
		
			
			| 
				30
			 | 
			
				35
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				31
			 | 
			
				36
			 | 
			
			
				
				 /** @file 
			 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			
				
				@@ -38,104 +43,263 @@ FILE_LICENCE ( GPL2_OR_LATER ); 
			 | 
		
		
	
		
			
			| 
				38
			 | 
			
				43
			 | 
			
			
				
				  * 
			 | 
		
		
	
		
			
			| 
				39
			 | 
			
				44
			 | 
			
			
				
				  */ 
			 | 
		
		
	
		
			
			| 
				40
			 | 
			
				45
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				46
			 | 
			
			
				
				+/** ARP minimum timeout */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				47
			 | 
			
			
				
				+#define ARP_MIN_TIMEOUT ( TICKS_PER_SEC / 8 ) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				48
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				49
			 | 
			
			
				
				+/** ARP maximum timeout */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				50
			 | 
			
			
				
				+#define ARP_MAX_TIMEOUT ( TICKS_PER_SEC * 3 ) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				51
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				41
			 | 
			
				52
			 | 
			
			
				
				 /** An ARP cache entry */ 
			 | 
		
		
	
		
			
			| 
				42
			 | 
			
				53
			 | 
			
			
				
				 struct arp_entry { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				54
			 | 
			
			
				
				+	/** List of ARP cache entries */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				55
			 | 
			
			
				
				+	struct list_head list; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				56
			 | 
			
			
				
				+	/** Network device */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				57
			 | 
			
			
				
				+	struct net_device *netdev; 
			 | 
		
		
	
		
			
			| 
				43
			 | 
			
				58
			 | 
			
			
				
				 	/** Network-layer protocol */ 
			 | 
		
		
	
		
			
			| 
				44
			 | 
			
				59
			 | 
			
			
				
				 	struct net_protocol *net_protocol; 
			 | 
		
		
	
		
			
			| 
				45
			 | 
			
				
			 | 
			
			
				
				-	/** Link-layer protocol */ 
			 | 
		
		
	
		
			
			| 
				46
			 | 
			
				
			 | 
			
			
				
				-	struct ll_protocol *ll_protocol; 
			 | 
		
		
	
		
			
			| 
				47
			 | 
			
				
			 | 
			
			
				
				-	/** Network-layer address */ 
			 | 
		
		
	
		
			
			| 
				48
			 | 
			
				
			 | 
			
			
				
				-	uint8_t net_addr[MAX_NET_ADDR_LEN]; 
			 | 
		
		
	
		
			
			| 
				49
			 | 
			
				
			 | 
			
			
				
				-	/** Link-layer address */ 
			 | 
		
		
	
		
			
			| 
				50
			 | 
			
				
			 | 
			
			
				
				-	uint8_t ll_addr[MAX_LL_ADDR_LEN]; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				60
			 | 
			
			
				
				+	/** Network-layer destination address */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				61
			 | 
			
			
				
				+	uint8_t net_dest[MAX_NET_ADDR_LEN]; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				62
			 | 
			
			
				
				+	/** Network-layer source address */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				63
			 | 
			
			
				
				+	uint8_t net_source[MAX_NET_ADDR_LEN]; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				64
			 | 
			
			
				
				+	/** Link-layer destination address */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				65
			 | 
			
			
				
				+	uint8_t ll_dest[MAX_LL_ADDR_LEN]; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				66
			 | 
			
			
				
				+	/** Retransmission timer */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				67
			 | 
			
			
				
				+	struct retry_timer timer; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				68
			 | 
			
			
				
				+	/** Pending I/O buffers */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				69
			 | 
			
			
				
				+	struct list_head tx_queue; 
			 | 
		
		
	
		
			
			| 
				51
			 | 
			
				70
			 | 
			
			
				
				 }; 
			 | 
		
		
	
		
			
			| 
				52
			 | 
			
				71
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				53
			 | 
			
				
			 | 
			
			
				
				-/** Number of entries in the ARP cache 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				72
			 | 
			
			
				
				+/** The ARP cache */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				73
			 | 
			
			
				
				+static LIST_HEAD ( arp_entries ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				74
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				75
			 | 
			
			
				
				+struct net_protocol arp_protocol __net_protocol; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				76
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				77
			 | 
			
			
				
				+static void arp_expired ( struct retry_timer *timer, int over ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				78
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				79
			 | 
			
			
				
				+/** 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				80
			 | 
			
			
				
				+ * Create ARP cache entry 
			 | 
		
		
	
		
			
			| 
				54
			 | 
			
				81
			 | 
			
			
				
				  * 
			 | 
		
		
	
		
			
			| 
				55
			 | 
			
				
			 | 
			
			
				
				- * This is a global cache, covering all network interfaces, 
			 | 
		
		
	
		
			
			| 
				56
			 | 
			
				
			 | 
			
			
				
				- * network-layer protocols and link-layer protocols. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				82
			 | 
			
			
				
				+ * @v netdev		Network device 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				83
			 | 
			
			
				
				+ * @v net_protocol	Network-layer protocol 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				84
			 | 
			
			
				
				+ * @v net_dest		Destination network-layer address 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				85
			 | 
			
			
				
				+ * @v net_source	Source network-layer address 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				86
			 | 
			
			
				
				+ * @ret arp		ARP cache entry, or NULL if allocation failed 
			 | 
		
		
	
		
			
			| 
				57
			 | 
			
				87
			 | 
			
			
				
				  */ 
			 | 
		
		
	
		
			
			| 
				58
			 | 
			
				
			 | 
			
			
				
				-#define NUM_ARP_ENTRIES 4 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				88
			 | 
			
			
				
				+static struct arp_entry * arp_create ( struct net_device *netdev, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				89
			 | 
			
			
				
				+				       struct net_protocol *net_protocol, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				90
			 | 
			
			
				
				+				       const void *net_dest, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				91
			 | 
			
			
				
				+				       const void *net_source ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				92
			 | 
			
			
				
				+	struct arp_entry *arp; 
			 | 
		
		
	
		
			
			| 
				59
			 | 
			
				93
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				60
			 | 
			
				
			 | 
			
			
				
				-/** The ARP cache */ 
			 | 
		
		
	
		
			
			| 
				61
			 | 
			
				
			 | 
			
			
				
				-static struct arp_entry arp_table[NUM_ARP_ENTRIES]; 
			 | 
		
		
	
		
			
			| 
				62
			 | 
			
				
			 | 
			
			
				
				-#define arp_table_end &arp_table[NUM_ARP_ENTRIES] 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				94
			 | 
			
			
				
				+	/* Allocate entry and add to cache */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				95
			 | 
			
			
				
				+	arp = zalloc ( sizeof ( *arp ) ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				96
			 | 
			
			
				
				+	if ( ! arp ) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				97
			 | 
			
			
				
				+		return NULL; 
			 | 
		
		
	
		
			
			| 
				63
			 | 
			
				98
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				64
			 | 
			
				
			 | 
			
			
				
				-static unsigned int next_new_arp_entry = 0; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				99
			 | 
			
			
				
				+	/* Initialise entry and add to cache */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				100
			 | 
			
			
				
				+	arp->netdev = netdev_get ( netdev ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				101
			 | 
			
			
				
				+	arp->net_protocol = net_protocol; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				102
			 | 
			
			
				
				+	memcpy ( arp->net_dest, net_dest, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				103
			 | 
			
			
				
				+		 net_protocol->net_addr_len ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				104
			 | 
			
			
				
				+	memcpy ( arp->net_source, net_source, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				105
			 | 
			
			
				
				+		 net_protocol->net_addr_len ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				106
			 | 
			
			
				
				+	timer_init ( &arp->timer, arp_expired, NULL ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				107
			 | 
			
			
				
				+	arp->timer.min_timeout = ARP_MIN_TIMEOUT; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				108
			 | 
			
			
				
				+	arp->timer.max_timeout = ARP_MAX_TIMEOUT; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				109
			 | 
			
			
				
				+	INIT_LIST_HEAD ( &arp->tx_queue ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				110
			 | 
			
			
				
				+	list_add ( &arp->list, &arp_entries ); 
			 | 
		
		
	
		
			
			| 
				65
			 | 
			
				111
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				66
			 | 
			
				
			 | 
			
			
				
				-struct net_protocol arp_protocol __net_protocol; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				112
			 | 
			
			
				
				+	/* Start timer running to trigger initial transmission */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				113
			 | 
			
			
				
				+	start_timer_nodelay ( &arp->timer ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				114
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				115
			 | 
			
			
				
				+	DBGC ( arp, "ARP %p %s %s %s created\n", arp, netdev->name, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				116
			 | 
			
			
				
				+	       net_protocol->name, net_protocol->ntoa ( net_dest ) ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				117
			 | 
			
			
				
				+	return arp; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				118
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				67
			 | 
			
				119
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				68
			 | 
			
				120
			 | 
			
			
				
				 /** 
			 | 
		
		
	
		
			
			| 
				69
			 | 
			
				121
			 | 
			
			
				
				  * Find entry in the ARP cache 
			 | 
		
		
	
		
			
			| 
				70
			 | 
			
				122
			 | 
			
			
				
				  * 
			 | 
		
		
	
		
			
			| 
				71
			 | 
			
				
			 | 
			
			
				
				- * @v ll_protocol	Link-layer protocol 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				123
			 | 
			
			
				
				+ * @v netdev		Network device 
			 | 
		
		
	
		
			
			| 
				72
			 | 
			
				124
			 | 
			
			
				
				  * @v net_protocol	Network-layer protocol 
			 | 
		
		
	
		
			
			| 
				73
			 | 
			
				
			 | 
			
			
				
				- * @v net_addr		Network-layer address 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				125
			 | 
			
			
				
				+ * @v net_dest		Destination network-layer address 
			 | 
		
		
	
		
			
			| 
				74
			 | 
			
				126
			 | 
			
			
				
				  * @ret arp		ARP cache entry, or NULL if not found 
			 | 
		
		
	
		
			
			| 
				75
			 | 
			
				
			 | 
			
			
				
				- * 
			 | 
		
		
	
		
			
			| 
				76
			 | 
			
				127
			 | 
			
			
				
				  */ 
			 | 
		
		
	
		
			
			| 
				77
			 | 
			
				
			 | 
			
			
				
				-static struct arp_entry * 
			 | 
		
		
	
		
			
			| 
				78
			 | 
			
				
			 | 
			
			
				
				-arp_find_entry ( struct ll_protocol *ll_protocol, 
			 | 
		
		
	
		
			
			| 
				79
			 | 
			
				
			 | 
			
			
				
				-		 struct net_protocol *net_protocol, 
			 | 
		
		
	
		
			
			| 
				80
			 | 
			
				
			 | 
			
			
				
				-		 const void *net_addr ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				128
			 | 
			
			
				
				+static struct arp_entry * arp_find ( struct net_device *netdev, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				129
			 | 
			
			
				
				+				     struct net_protocol *net_protocol, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				130
			 | 
			
			
				
				+				     const void *net_dest ) { 
			 | 
		
		
	
		
			
			| 
				81
			 | 
			
				131
			 | 
			
			
				
				 	struct arp_entry *arp; 
			 | 
		
		
	
		
			
			| 
				82
			 | 
			
				132
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				83
			 | 
			
				
			 | 
			
			
				
				-	for ( arp = arp_table ; arp < arp_table_end ; arp++ ) { 
			 | 
		
		
	
		
			
			| 
				84
			 | 
			
				
			 | 
			
			
				
				-		if ( ( arp->ll_protocol == ll_protocol ) && 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				133
			 | 
			
			
				
				+	list_for_each_entry ( arp, &arp_entries, list ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				134
			 | 
			
			
				
				+		if ( ( arp->netdev == netdev ) && 
			 | 
		
		
	
		
			
			| 
				85
			 | 
			
				135
			 | 
			
			
				
				 		     ( arp->net_protocol == net_protocol ) && 
			 | 
		
		
	
		
			
			| 
				86
			 | 
			
				
			 | 
			
			
				
				-		     ( memcmp ( arp->net_addr, net_addr, 
			 | 
		
		
	
		
			
			| 
				87
			 | 
			
				
			 | 
			
			
				
				-				net_protocol->net_addr_len ) == 0 ) ) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				136
			 | 
			
			
				
				+		     ( memcmp ( arp->net_dest, net_dest, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				137
			 | 
			
			
				
				+				net_protocol->net_addr_len ) == 0 ) ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				138
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				139
			 | 
			
			
				
				+			/* Move to start of cache */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				140
			 | 
			
			
				
				+			list_del ( &arp->list ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				141
			 | 
			
			
				
				+			list_add ( &arp->list, &arp_entries ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				142
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				88
			 | 
			
				143
			 | 
			
			
				
				 			return arp; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				144
			 | 
			
			
				
				+		} 
			 | 
		
		
	
		
			
			| 
				89
			 | 
			
				145
			 | 
			
			
				
				 	} 
			 | 
		
		
	
		
			
			| 
				90
			 | 
			
				146
			 | 
			
			
				
				 	return NULL; 
			 | 
		
		
	
		
			
			| 
				91
			 | 
			
				147
			 | 
			
			
				
				 } 
			 | 
		
		
	
		
			
			| 
				92
			 | 
			
				148
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				93
			 | 
			
				149
			 | 
			
			
				
				 /** 
			 | 
		
		
	
		
			
			| 
				94
			 | 
			
				
			 | 
			
			
				
				- * Look up media-specific link-layer address in the ARP cache 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				150
			 | 
			
			
				
				+ * Destroy ARP cache entry 
			 | 
		
		
	
		
			
			| 
				95
			 | 
			
				151
			 | 
			
			
				
				  * 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				152
			 | 
			
			
				
				+ * @v arp		ARP cache entry 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				153
			 | 
			
			
				
				+ * @v rc		Reason for destruction 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				154
			 | 
			
			
				
				+ */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				155
			 | 
			
			
				
				+static void arp_destroy ( struct arp_entry *arp, int rc ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				156
			 | 
			
			
				
				+	struct net_device *netdev = arp->netdev; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				157
			 | 
			
			
				
				+	struct net_protocol *net_protocol = arp->net_protocol; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				158
			 | 
			
			
				
				+	struct io_buffer *iobuf; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				159
			 | 
			
			
				
				+	struct io_buffer *tmp; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				160
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				161
			 | 
			
			
				
				+	/* Stop timer */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				162
			 | 
			
			
				
				+	stop_timer ( &arp->timer ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				163
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				164
			 | 
			
			
				
				+	/* Discard any outstanding I/O buffers */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				165
			 | 
			
			
				
				+	list_for_each_entry_safe ( iobuf, tmp, &arp->tx_queue, list ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				166
			 | 
			
			
				
				+		DBGC2 ( arp, "ARP %p %s %s %s discarding deferred packet: " 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				167
			 | 
			
			
				
				+			"%s\n", arp, netdev->name, net_protocol->name, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				168
			 | 
			
			
				
				+			net_protocol->ntoa ( arp->net_dest ), strerror ( rc ) ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				169
			 | 
			
			
				
				+		list_del ( &iobuf->list ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				170
			 | 
			
			
				
				+		netdev_tx_err ( arp->netdev, iobuf, rc ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				171
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				172
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				173
			 | 
			
			
				
				+	DBGC ( arp, "ARP %p %s %s %s destroyed: %s\n", arp, netdev->name, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				174
			 | 
			
			
				
				+	       net_protocol->name, net_protocol->ntoa ( arp->net_dest ), 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				175
			 | 
			
			
				
				+	       strerror ( rc ) ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				176
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				177
			 | 
			
			
				
				+	/* Drop reference to network device, remove from cache and free */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				178
			 | 
			
			
				
				+	netdev_put ( arp->netdev ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				179
			 | 
			
			
				
				+	list_del ( &arp->list ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				180
			 | 
			
			
				
				+	free ( arp ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				181
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				182
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				183
			 | 
			
			
				
				+/** 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				184
			 | 
			
			
				
				+ * Test if ARP cache entry has a valid link-layer address 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				185
			 | 
			
			
				
				+ * 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				186
			 | 
			
			
				
				+ * @v arp		ARP cache entry 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				187
			 | 
			
			
				
				+ * @ret resolved	ARP cache entry is resolved 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				188
			 | 
			
			
				
				+ */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				189
			 | 
			
			
				
				+static inline int arp_resolved ( struct arp_entry *arp ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				190
			 | 
			
			
				
				+	return ( ! timer_running ( &arp->timer ) ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				191
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				192
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				193
			 | 
			
			
				
				+/** 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				194
			 | 
			
			
				
				+ * Transmit packet, determining link-layer address via ARP 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				195
			 | 
			
			
				
				+ * 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				196
			 | 
			
			
				
				+ * @v iobuf		I/O buffer 
			 | 
		
		
	
		
			
			| 
				96
			 | 
			
				197
			 | 
			
			
				
				  * @v netdev		Network device 
			 | 
		
		
	
		
			
			| 
				97
			 | 
			
				198
			 | 
			
			
				
				  * @v net_protocol	Network-layer protocol 
			 | 
		
		
	
		
			
			| 
				98
			 | 
			
				
			 | 
			
			
				
				- * @v dest_net_addr	Destination network-layer address 
			 | 
		
		
	
		
			
			| 
				99
			 | 
			
				
			 | 
			
			
				
				- * @v source_net_addr	Source network-layer address 
			 | 
		
		
	
		
			
			| 
				100
			 | 
			
				
			 | 
			
			
				
				- * @ret dest_ll_addr	Destination link layer address 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				199
			 | 
			
			
				
				+ * @v net_dest		Destination network-layer address 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				200
			 | 
			
			
				
				+ * @v net_source	Source network-layer address 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				201
			 | 
			
			
				
				+ * @v ll_source		Source link-layer address 
			 | 
		
		
	
		
			
			| 
				101
			 | 
			
				202
			 | 
			
			
				
				  * @ret rc		Return status code 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				203
			 | 
			
			
				
				+ */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				204
			 | 
			
			
				
				+int arp_tx ( struct io_buffer *iobuf, struct net_device *netdev, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				205
			 | 
			
			
				
				+	     struct net_protocol *net_protocol, const void *net_dest, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				206
			 | 
			
			
				
				+	     const void *net_source, const void *ll_source ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				207
			 | 
			
			
				
				+	struct arp_entry *arp; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				208
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				209
			 | 
			
			
				
				+	/* Find or create ARP cache entry */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				210
			 | 
			
			
				
				+	arp = arp_find ( netdev, net_protocol, net_dest ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				211
			 | 
			
			
				
				+	if ( ! arp ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				212
			 | 
			
			
				
				+		arp = arp_create ( netdev, net_protocol, net_dest, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				213
			 | 
			
			
				
				+				   net_source ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				214
			 | 
			
			
				
				+		if ( ! arp ) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				215
			 | 
			
			
				
				+			return -ENOMEM; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				216
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				217
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				218
			 | 
			
			
				
				+	/* If a link-layer address is available then transmit 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				219
			 | 
			
			
				
				+	 * immediately, otherwise queue for later transmission. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				220
			 | 
			
			
				
				+	 */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				221
			 | 
			
			
				
				+	if ( arp_resolved ( arp ) ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				222
			 | 
			
			
				
				+		return net_tx ( iobuf, netdev, net_protocol, arp->ll_dest, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				223
			 | 
			
			
				
				+				ll_source ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				224
			 | 
			
			
				
				+	} else { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				225
			 | 
			
			
				
				+		DBGC2 ( arp, "ARP %p %s %s %s deferring packet\n", 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				226
			 | 
			
			
				
				+			arp, netdev->name, net_protocol->name, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				227
			 | 
			
			
				
				+			net_protocol->ntoa ( net_dest ) ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				228
			 | 
			
			
				
				+		list_add_tail ( &iobuf->list, &arp->tx_queue ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				229
			 | 
			
			
				
				+		return -EAGAIN; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				230
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				231
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				232
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				233
			 | 
			
			
				
				+/** 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				234
			 | 
			
			
				
				+ * Update ARP cache entry 
			 | 
		
		
	
		
			
			| 
				102
			 | 
			
				235
			 | 
			
			
				
				  * 
			 | 
		
		
	
		
			
			| 
				103
			 | 
			
				
			 | 
			
			
				
				- * This function will use the ARP cache to look up the link-layer 
			 | 
		
		
	
		
			
			| 
				104
			 | 
			
				
			 | 
			
			
				
				- * address for the link-layer protocol associated with the network 
			 | 
		
		
	
		
			
			| 
				105
			 | 
			
				
			 | 
			
			
				
				- * device and the given network-layer protocol and addresses.  If 
			 | 
		
		
	
		
			
			| 
				106
			 | 
			
				
			 | 
			
			
				
				- * found, the destination link-layer address will be filled in in @c 
			 | 
		
		
	
		
			
			| 
				107
			 | 
			
				
			 | 
			
			
				
				- * dest_ll_addr. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				236
			 | 
			
			
				
				+ * @v arp		ARP cache entry 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				237
			 | 
			
			
				
				+ * @v ll_dest		Destination link-layer address 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				238
			 | 
			
			
				
				+ */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				239
			 | 
			
			
				
				+static void arp_update ( struct arp_entry *arp, const void *ll_dest ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				240
			 | 
			
			
				
				+	struct net_device *netdev = arp->netdev; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				241
			 | 
			
			
				
				+	struct ll_protocol *ll_protocol = netdev->ll_protocol; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				242
			 | 
			
			
				
				+	struct net_protocol *net_protocol = arp->net_protocol; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				243
			 | 
			
			
				
				+	struct io_buffer *iobuf; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				244
			 | 
			
			
				
				+	struct io_buffer *tmp; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				245
			 | 
			
			
				
				+	int rc; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				246
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				247
			 | 
			
			
				
				+	DBGC ( arp, "ARP %p %s %s %s updated => %s\n", arp, netdev->name, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				248
			 | 
			
			
				
				+	       net_protocol->name, net_protocol->ntoa ( arp->net_dest ), 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				249
			 | 
			
			
				
				+	       ll_protocol->ntoa ( ll_dest ) ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				250
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				251
			 | 
			
			
				
				+	/* Fill in link-layer address */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				252
			 | 
			
			
				
				+	memcpy ( arp->ll_dest, ll_dest, ll_protocol->ll_addr_len ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				253
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				254
			 | 
			
			
				
				+	/* Stop retransmission timer */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				255
			 | 
			
			
				
				+	stop_timer ( &arp->timer ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				256
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				257
			 | 
			
			
				
				+	/* Transmit any packets in queue */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				258
			 | 
			
			
				
				+	list_for_each_entry_safe ( iobuf, tmp, &arp->tx_queue, list ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				259
			 | 
			
			
				
				+		DBGC2 ( arp, "ARP %p %s %s %s transmitting deferred packet\n", 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				260
			 | 
			
			
				
				+			arp, netdev->name, net_protocol->name, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				261
			 | 
			
			
				
				+			net_protocol->ntoa ( arp->net_dest ) ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				262
			 | 
			
			
				
				+		list_del ( &iobuf->list ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				263
			 | 
			
			
				
				+		if ( ( rc = net_tx ( iobuf, netdev, net_protocol, ll_dest, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				264
			 | 
			
			
				
				+				     netdev->ll_addr ) ) != 0 ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				265
			 | 
			
			
				
				+			DBGC ( arp, "ARP %p could not transmit deferred " 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				266
			 | 
			
			
				
				+			       "packet: %s\n", arp, strerror ( rc ) ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				267
			 | 
			
			
				
				+			/* Ignore error and continue */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				268
			 | 
			
			
				
				+		} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				269
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				270
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				271
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				272
			 | 
			
			
				
				+/** 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				273
			 | 
			
			
				
				+ * Handle ARP timer expiry 
			 | 
		
		
	
		
			
			| 
				108
			 | 
			
				274
			 | 
			
			
				
				  * 
			 | 
		
		
	
		
			
			| 
				109
			 | 
			
				
			 | 
			
			
				
				- * If no address is found in the ARP cache, an ARP request will be 
			 | 
		
		
	
		
			
			| 
				110
			 | 
			
				
			 | 
			
			
				
				- * transmitted on the specified network device and -ENOENT will be 
			 | 
		
		
	
		
			
			| 
				111
			 | 
			
				
			 | 
			
			
				
				- * returned. 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				275
			 | 
			
			
				
				+ * @v timer		Retry timer 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				276
			 | 
			
			
				
				+ * @v fail		Failure indicator 
			 | 
		
		
	
		
			
			| 
				112
			 | 
			
				277
			 | 
			
			
				
				  */ 
			 | 
		
		
	
		
			
			| 
				113
			 | 
			
				
			 | 
			
			
				
				-int arp_resolve ( struct net_device *netdev, struct net_protocol *net_protocol, 
			 | 
		
		
	
		
			
			| 
				114
			 | 
			
				
			 | 
			
			
				
				-		  const void *dest_net_addr, const void *source_net_addr, 
			 | 
		
		
	
		
			
			| 
				115
			 | 
			
				
			 | 
			
			
				
				-		  void *dest_ll_addr ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				278
			 | 
			
			
				
				+static void arp_expired ( struct retry_timer *timer, int fail ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				279
			 | 
			
			
				
				+	struct arp_entry *arp = container_of ( timer, struct arp_entry, timer ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				280
			 | 
			
			
				
				+	struct net_device *netdev = arp->netdev; 
			 | 
		
		
	
		
			
			| 
				116
			 | 
			
				281
			 | 
			
			
				
				 	struct ll_protocol *ll_protocol = netdev->ll_protocol; 
			 | 
		
		
	
		
			
			| 
				117
			 | 
			
				
			 | 
			
			
				
				-	const struct arp_entry *arp; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				282
			 | 
			
			
				
				+	struct net_protocol *net_protocol = arp->net_protocol; 
			 | 
		
		
	
		
			
			| 
				118
			 | 
			
				283
			 | 
			
			
				
				 	struct io_buffer *iobuf; 
			 | 
		
		
	
		
			
			| 
				119
			 | 
			
				284
			 | 
			
			
				
				 	struct arphdr *arphdr; 
			 | 
		
		
	
		
			
			| 
				120
			 | 
			
				285
			 | 
			
			
				
				 	int rc; 
			 | 
		
		
	
		
			
			| 
				121
			 | 
			
				286
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				122
			 | 
			
				
			 | 
			
			
				
				-	/* Look for existing entry in ARP table */ 
			 | 
		
		
	
		
			
			| 
				123
			 | 
			
				
			 | 
			
			
				
				-	arp = arp_find_entry ( ll_protocol, net_protocol, dest_net_addr ); 
			 | 
		
		
	
		
			
			| 
				124
			 | 
			
				
			 | 
			
			
				
				-	if ( arp ) { 
			 | 
		
		
	
		
			
			| 
				125
			 | 
			
				
			 | 
			
			
				
				-		DBG ( "ARP cache hit: %s %s => %s %s\n", 
			 | 
		
		
	
		
			
			| 
				126
			 | 
			
				
			 | 
			
			
				
				-		      net_protocol->name, net_protocol->ntoa ( arp->net_addr ), 
			 | 
		
		
	
		
			
			| 
				127
			 | 
			
				
			 | 
			
			
				
				-		      ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) ); 
			 | 
		
		
	
		
			
			| 
				128
			 | 
			
				
			 | 
			
			
				
				-		memcpy ( dest_ll_addr, arp->ll_addr, ll_protocol->ll_addr_len); 
			 | 
		
		
	
		
			
			| 
				129
			 | 
			
				
			 | 
			
			
				
				-		return 0; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				287
			 | 
			
			
				
				+	/* If we have failed, destroy the cache entry */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				288
			 | 
			
			
				
				+	if ( fail ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				289
			 | 
			
			
				
				+		arp_destroy ( arp, -ETIMEDOUT ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				290
			 | 
			
			
				
				+		return; 
			 | 
		
		
	
		
			
			| 
				130
			 | 
			
				291
			 | 
			
			
				
				 	} 
			 | 
		
		
	
		
			
			| 
				131
			 | 
			
				
			 | 
			
			
				
				-	DBG ( "ARP cache miss: %s %s\n", net_protocol->name, 
			 | 
		
		
	
		
			
			| 
				132
			 | 
			
				
			 | 
			
			
				
				-	      net_protocol->ntoa ( dest_net_addr ) ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				292
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				293
			 | 
			
			
				
				+	/* Restart the timer */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				294
			 | 
			
			
				
				+	start_timer ( &arp->timer ); 
			 | 
		
		
	
		
			
			| 
				133
			 | 
			
				295
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				134
			 | 
			
				296
			 | 
			
			
				
				 	/* Allocate ARP packet */ 
			 | 
		
		
	
		
			
			| 
				135
			 | 
			
				297
			 | 
			
			
				
				 	iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *arphdr ) + 
			 | 
		
		
	
		
			
			| 
				136
			 | 
			
				
			 | 
			
			
				
				-			  2 * ( MAX_LL_ADDR_LEN + MAX_NET_ADDR_LEN ) ); 
			 | 
		
		
	
		
			
			| 
				137
			 | 
			
				
			 | 
			
			
				
				-	if ( ! iobuf ) 
			 | 
		
		
	
		
			
			| 
				138
			 | 
			
				
			 | 
			
			
				
				-		return -ENOMEM; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				298
			 | 
			
			
				
				+			    ( 2 * ( MAX_LL_ADDR_LEN + MAX_NET_ADDR_LEN ) ) ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				299
			 | 
			
			
				
				+	if ( ! iobuf ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				300
			 | 
			
			
				
				+		/* Leave timer running and try again later */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				301
			 | 
			
			
				
				+		return; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				302
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				139
			 | 
			
				303
			 | 
			
			
				
				 	iob_reserve ( iobuf, MAX_LL_HEADER_LEN ); 
			 | 
		
		
	
		
			
			| 
				140
			 | 
			
				304
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				141
			 | 
			
				305
			 | 
			
			
				
				 	/* Build up ARP request */ 
			 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			
				
				@@ -148,18 +312,19 @@ int arp_resolve ( struct net_device *netdev, struct net_protocol *net_protocol, 
			 | 
		
		
	
		
			
			| 
				148
			 | 
			
				312
			 | 
			
			
				
				 	memcpy ( iob_put ( iobuf, ll_protocol->ll_addr_len ), 
			 | 
		
		
	
		
			
			| 
				149
			 | 
			
				313
			 | 
			
			
				
				 		 netdev->ll_addr, ll_protocol->ll_addr_len ); 
			 | 
		
		
	
		
			
			| 
				150
			 | 
			
				314
			 | 
			
			
				
				 	memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ), 
			 | 
		
		
	
		
			
			| 
				151
			 | 
			
				
			 | 
			
			
				
				-		 source_net_addr, net_protocol->net_addr_len ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				315
			 | 
			
			
				
				+		 arp->net_source, net_protocol->net_addr_len ); 
			 | 
		
		
	
		
			
			| 
				152
			 | 
			
				316
			 | 
			
			
				
				 	memset ( iob_put ( iobuf, ll_protocol->ll_addr_len ), 
			 | 
		
		
	
		
			
			| 
				153
			 | 
			
				317
			 | 
			
			
				
				 		 0, ll_protocol->ll_addr_len ); 
			 | 
		
		
	
		
			
			| 
				154
			 | 
			
				318
			 | 
			
			
				
				 	memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ), 
			 | 
		
		
	
		
			
			| 
				155
			 | 
			
				
			 | 
			
			
				
				-		 dest_net_addr, net_protocol->net_addr_len ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				319
			 | 
			
			
				
				+		 arp->net_dest, net_protocol->net_addr_len ); 
			 | 
		
		
	
		
			
			| 
				156
			 | 
			
				320
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				157
			 | 
			
				321
			 | 
			
			
				
				 	/* Transmit ARP request */ 
			 | 
		
		
	
		
			
			| 
				158
			 | 
			
				322
			 | 
			
			
				
				 	if ( ( rc = net_tx ( iobuf, netdev, &arp_protocol, 
			 | 
		
		
	
		
			
			| 
				159
			 | 
			
				
			 | 
			
			
				
				-			     netdev->ll_broadcast, netdev->ll_addr ) ) != 0 ) 
			 | 
		
		
	
		
			
			| 
				160
			 | 
			
				
			 | 
			
			
				
				-		return rc; 
			 | 
		
		
	
		
			
			| 
				161
			 | 
			
				
			 | 
			
			
				
				- 
			 | 
		
		
	
		
			
			| 
				162
			 | 
			
				
			 | 
			
			
				
				-	return -ENOENT; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				323
			 | 
			
			
				
				+			     netdev->ll_broadcast, netdev->ll_addr ) ) != 0 ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				324
			 | 
			
			
				
				+		DBGC ( arp, "ARP %p could not transmit request: %s\n", 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				325
			 | 
			
			
				
				+		       arp, strerror ( rc ) ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				326
			 | 
			
			
				
				+		return; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				327
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				163
			 | 
			
				328
			 | 
			
			
				
				 } 
			 | 
		
		
	
		
			
			| 
				164
			 | 
			
				329
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				165
			 | 
			
				330
			 | 
			
			
				
				 /** 
			 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			
				
				@@ -188,12 +353,6 @@ static struct arp_net_protocol * arp_find_protocol ( uint16_t net_proto ) { 
			 | 
		
		
	
		
			
			| 
				188
			 | 
			
				353
			 | 
			
			
				
				  * @v ll_source		Link-layer source address 
			 | 
		
		
	
		
			
			| 
				189
			 | 
			
				354
			 | 
			
			
				
				  * @v flags		Packet flags 
			 | 
		
		
	
		
			
			| 
				190
			 | 
			
				355
			 | 
			
			
				
				  * @ret rc		Return status code 
			 | 
		
		
	
		
			
			| 
				191
			 | 
			
				
			 | 
			
			
				
				- * 
			 | 
		
		
	
		
			
			| 
				192
			 | 
			
				
			 | 
			
			
				
				- * This handles ARP requests and responses as detailed in RFC826.  The 
			 | 
		
		
	
		
			
			| 
				193
			 | 
			
				
			 | 
			
			
				
				- * method detailed within the RFC is pretty optimised, handling 
			 | 
		
		
	
		
			
			| 
				194
			 | 
			
				
			 | 
			
			
				
				- * requests and responses with basically a single code path and 
			 | 
		
		
	
		
			
			| 
				195
			 | 
			
				
			 | 
			
			
				
				- * avoiding the need for extraneous ARP requests; read the RFC for 
			 | 
		
		
	
		
			
			| 
				196
			 | 
			
				
			 | 
			
			
				
				- * details. 
			 | 
		
		
	
		
			
			| 
				197
			 | 
			
				356
			 | 
			
			
				
				  */ 
			 | 
		
		
	
		
			
			| 
				198
			 | 
			
				357
			 | 
			
			
				
				 static int arp_rx ( struct io_buffer *iobuf, struct net_device *netdev, 
			 | 
		
		
	
		
			
			| 
				199
			 | 
			
				358
			 | 
			
			
				
				 		    const void *ll_dest __unused, 
			 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			
				
				@@ -204,71 +363,68 @@ static int arp_rx ( struct io_buffer *iobuf, struct net_device *netdev, 
			 | 
		
		
	
		
			
			| 
				204
			 | 
			
				363
			 | 
			
			
				
				 	struct net_protocol *net_protocol; 
			 | 
		
		
	
		
			
			| 
				205
			 | 
			
				364
			 | 
			
			
				
				 	struct ll_protocol *ll_protocol; 
			 | 
		
		
	
		
			
			| 
				206
			 | 
			
				365
			 | 
			
			
				
				 	struct arp_entry *arp; 
			 | 
		
		
	
		
			
			| 
				207
			 | 
			
				
			 | 
			
			
				
				-	int merge = 0; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				366
			 | 
			
			
				
				+	int rc; 
			 | 
		
		
	
		
			
			| 
				208
			 | 
			
				367
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				209
			 | 
			
				368
			 | 
			
			
				
				 	/* Identify network-layer and link-layer protocols */ 
			 | 
		
		
	
		
			
			| 
				210
			 | 
			
				369
			 | 
			
			
				
				 	arp_net_protocol = arp_find_protocol ( arphdr->ar_pro ); 
			 | 
		
		
	
		
			
			| 
				211
			 | 
			
				
			 | 
			
			
				
				-	if ( ! arp_net_protocol ) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				370
			 | 
			
			
				
				+	if ( ! arp_net_protocol ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				371
			 | 
			
			
				
				+		rc = -EPROTONOSUPPORT; 
			 | 
		
		
	
		
			
			| 
				212
			 | 
			
				372
			 | 
			
			
				
				 		goto done; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				373
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				213
			 | 
			
				374
			 | 
			
			
				
				 	net_protocol = arp_net_protocol->net_protocol; 
			 | 
		
		
	
		
			
			| 
				214
			 | 
			
				375
			 | 
			
			
				
				 	ll_protocol = netdev->ll_protocol; 
			 | 
		
		
	
		
			
			| 
				215
			 | 
			
				376
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				216
			 | 
			
				377
			 | 
			
			
				
				 	/* Sanity checks */ 
			 | 
		
		
	
		
			
			| 
				217
			 | 
			
				378
			 | 
			
			
				
				 	if ( ( arphdr->ar_hrd != ll_protocol->ll_proto ) || 
			 | 
		
		
	
		
			
			| 
				218
			 | 
			
				379
			 | 
			
			
				
				 	     ( arphdr->ar_hln != ll_protocol->ll_addr_len ) || 
			 | 
		
		
	
		
			
			| 
				219
			 | 
			
				
			 | 
			
			
				
				-	     ( arphdr->ar_pln != net_protocol->net_addr_len ) ) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				380
			 | 
			
			
				
				+	     ( arphdr->ar_pln != net_protocol->net_addr_len ) ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				381
			 | 
			
			
				
				+		rc = -EINVAL; 
			 | 
		
		
	
		
			
			| 
				220
			 | 
			
				382
			 | 
			
			
				
				 		goto done; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				383
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				221
			 | 
			
				384
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				222
			 | 
			
				385
			 | 
			
			
				
				 	/* See if we have an entry for this sender, and update it if so */ 
			 | 
		
		
	
		
			
			| 
				223
			 | 
			
				
			 | 
			
			
				
				-	arp = arp_find_entry ( ll_protocol, net_protocol, 
			 | 
		
		
	
		
			
			| 
				224
			 | 
			
				
			 | 
			
			
				
				-			       arp_sender_pa ( arphdr ) ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				386
			 | 
			
			
				
				+	arp = arp_find ( netdev, net_protocol, arp_sender_pa ( arphdr ) ); 
			 | 
		
		
	
		
			
			| 
				225
			 | 
			
				387
			 | 
			
			
				
				 	if ( arp ) { 
			 | 
		
		
	
		
			
			| 
				226
			 | 
			
				
			 | 
			
			
				
				-		memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ), 
			 | 
		
		
	
		
			
			| 
				227
			 | 
			
				
			 | 
			
			
				
				-			 arphdr->ar_hln ); 
			 | 
		
		
	
		
			
			| 
				228
			 | 
			
				
			 | 
			
			
				
				-		merge = 1; 
			 | 
		
		
	
		
			
			| 
				229
			 | 
			
				
			 | 
			
			
				
				-		DBG ( "ARP cache update: %s %s => %s %s\n", 
			 | 
		
		
	
		
			
			| 
				230
			 | 
			
				
			 | 
			
			
				
				-		      net_protocol->name, net_protocol->ntoa ( arp->net_addr ), 
			 | 
		
		
	
		
			
			| 
				231
			 | 
			
				
			 | 
			
			
				
				-		      ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				388
			 | 
			
			
				
				+		arp_update ( arp, arp_sender_ha ( arphdr ) ); 
			 | 
		
		
	
		
			
			| 
				232
			 | 
			
				389
			 | 
			
			
				
				 	} 
			 | 
		
		
	
		
			
			| 
				233
			 | 
			
				390
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				234
			 | 
			
				
			 | 
			
			
				
				-	/* See if we own the target protocol address */ 
			 | 
		
		
	
		
			
			| 
				235
			 | 
			
				
			 | 
			
			
				
				-	if ( arp_net_protocol->check ( netdev, arp_target_pa ( arphdr ) ) != 0) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				391
			 | 
			
			
				
				+	/* If it's not a request, there's nothing more to do */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				392
			 | 
			
			
				
				+	if ( arphdr->ar_op != htons ( ARPOP_REQUEST ) ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				393
			 | 
			
			
				
				+		rc = 0; 
			 | 
		
		
	
		
			
			| 
				236
			 | 
			
				394
			 | 
			
			
				
				 		goto done; 
			 | 
		
		
	
		
			
			| 
				237
			 | 
			
				
			 | 
			
			
				
				-	 
			 | 
		
		
	
		
			
			| 
				238
			 | 
			
				
			 | 
			
			
				
				-	/* Create new ARP table entry if necessary */ 
			 | 
		
		
	
		
			
			| 
				239
			 | 
			
				
			 | 
			
			
				
				-	if ( ! merge ) { 
			 | 
		
		
	
		
			
			| 
				240
			 | 
			
				
			 | 
			
			
				
				-		arp = &arp_table[next_new_arp_entry++ % NUM_ARP_ENTRIES]; 
			 | 
		
		
	
		
			
			| 
				241
			 | 
			
				
			 | 
			
			
				
				-		arp->ll_protocol = ll_protocol; 
			 | 
		
		
	
		
			
			| 
				242
			 | 
			
				
			 | 
			
			
				
				-		arp->net_protocol = net_protocol; 
			 | 
		
		
	
		
			
			| 
				243
			 | 
			
				
			 | 
			
			
				
				-		memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ), 
			 | 
		
		
	
		
			
			| 
				244
			 | 
			
				
			 | 
			
			
				
				-			 arphdr->ar_hln ); 
			 | 
		
		
	
		
			
			| 
				245
			 | 
			
				
			 | 
			
			
				
				-		memcpy ( arp->net_addr, arp_sender_pa ( arphdr ), 
			 | 
		
		
	
		
			
			| 
				246
			 | 
			
				
			 | 
			
			
				
				-			 arphdr->ar_pln); 
			 | 
		
		
	
		
			
			| 
				247
			 | 
			
				
			 | 
			
			
				
				-		DBG ( "ARP cache add: %s %s => %s %s\n", 
			 | 
		
		
	
		
			
			| 
				248
			 | 
			
				
			 | 
			
			
				
				-		      net_protocol->name, net_protocol->ntoa ( arp->net_addr ), 
			 | 
		
		
	
		
			
			| 
				249
			 | 
			
				
			 | 
			
			
				
				-		      ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) ); 
			 | 
		
		
	
		
			
			| 
				250
			 | 
			
				395
			 | 
			
			
				
				 	} 
			 | 
		
		
	
		
			
			| 
				251
			 | 
			
				396
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				252
			 | 
			
				
			 | 
			
			
				
				-	/* If it's not a request, there's nothing more to do */ 
			 | 
		
		
	
		
			
			| 
				253
			 | 
			
				
			 | 
			
			
				
				-	if ( arphdr->ar_op != htons ( ARPOP_REQUEST ) ) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				397
			 | 
			
			
				
				+	/* See if we own the target protocol address */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				398
			 | 
			
			
				
				+	if ( arp_net_protocol->check ( netdev, arp_target_pa ( arphdr ) ) != 0){ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				399
			 | 
			
			
				
				+		rc = 0; 
			 | 
		
		
	
		
			
			| 
				254
			 | 
			
				400
			 | 
			
			
				
				 		goto done; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				401
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				255
			 | 
			
				402
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				256
			 | 
			
				403
			 | 
			
			
				
				 	/* Change request to a reply */ 
			 | 
		
		
	
		
			
			| 
				257
			 | 
			
				
			 | 
			
			
				
				-	DBG ( "ARP reply: %s %s => %s %s\n", net_protocol->name, 
			 | 
		
		
	
		
			
			| 
				258
			 | 
			
				
			 | 
			
			
				
				-	      net_protocol->ntoa ( arp_target_pa ( arphdr ) ), 
			 | 
		
		
	
		
			
			| 
				259
			 | 
			
				
			 | 
			
			
				
				-	      ll_protocol->name, ll_protocol->ntoa ( netdev->ll_addr ) ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				404
			 | 
			
			
				
				+	DBGC ( netdev, "ARP reply %s %s %s => %s %s\n", 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				405
			 | 
			
			
				
				+	       netdev->name, net_protocol->name, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				406
			 | 
			
			
				
				+	       net_protocol->ntoa ( arp_target_pa ( arphdr ) ), 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				407
			 | 
			
			
				
				+	       ll_protocol->name, ll_protocol->ntoa ( netdev->ll_addr ) ); 
			 | 
		
		
	
		
			
			| 
				260
			 | 
			
				408
			 | 
			
			
				
				 	arphdr->ar_op = htons ( ARPOP_REPLY ); 
			 | 
		
		
	
		
			
			| 
				261
			 | 
			
				409
			 | 
			
			
				
				 	memswap ( arp_sender_ha ( arphdr ), arp_target_ha ( arphdr ), 
			 | 
		
		
	
		
			
			| 
				262
			 | 
			
				410
			 | 
			
			
				
				 		 arphdr->ar_hln + arphdr->ar_pln ); 
			 | 
		
		
	
		
			
			| 
				263
			 | 
			
				411
			 | 
			
			
				
				 	memcpy ( arp_sender_ha ( arphdr ), netdev->ll_addr, arphdr->ar_hln ); 
			 | 
		
		
	
		
			
			| 
				264
			 | 
			
				412
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				265
			 | 
			
				413
			 | 
			
			
				
				 	/* Send reply */ 
			 | 
		
		
	
		
			
			| 
				266
			 | 
			
				
			 | 
			
			
				
				-	net_tx ( iob_disown ( iobuf ), netdev, &arp_protocol, 
			 | 
		
		
	
		
			
			| 
				267
			 | 
			
				
			 | 
			
			
				
				-		 arp_target_ha ( arphdr ), netdev->ll_addr ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				414
			 | 
			
			
				
				+	if ( ( rc = net_tx ( iob_disown ( iobuf ), netdev, &arp_protocol, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				415
			 | 
			
			
				
				+			     arp_target_ha ( arphdr ), 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				416
			 | 
			
			
				
				+			     netdev->ll_addr ) ) != 0 ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				417
			 | 
			
			
				
				+		DBGC ( netdev, "ARP could not transmit reply via %s: %s\n", 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				418
			 | 
			
			
				
				+		       netdev->name, strerror ( rc ) ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				419
			 | 
			
			
				
				+		goto done; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				420
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				421
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				422
			 | 
			
			
				
				+	/* Success */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				423
			 | 
			
			
				
				+	rc = 0; 
			 | 
		
		
	
		
			
			| 
				268
			 | 
			
				424
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				269
			 | 
			
				425
			 | 
			
			
				
				  done: 
			 | 
		
		
	
		
			
			| 
				270
			 | 
			
				426
			 | 
			
			
				
				 	free_iob ( iobuf ); 
			 | 
		
		
	
		
			
			| 
				271
			 | 
			
				
			 | 
			
			
				
				-	return 0; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				427
			 | 
			
			
				
				+	return rc; 
			 | 
		
		
	
		
			
			| 
				272
			 | 
			
				428
			 | 
			
			
				
				 } 
			 | 
		
		
	
		
			
			| 
				273
			 | 
			
				429
			 | 
			
			
				
				  
			 | 
		
		
	
		
			
			| 
				274
			 | 
			
				430
			 | 
			
			
				
				 /** 
			 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			
				
				@@ -290,3 +446,59 @@ struct net_protocol arp_protocol __net_protocol = { 
			 | 
		
		
	
		
			
			| 
				290
			 | 
			
				446
			 | 
			
			
				
				 	.rx = arp_rx, 
			 | 
		
		
	
		
			
			| 
				291
			 | 
			
				447
			 | 
			
			
				
				 	.ntoa = arp_ntoa, 
			 | 
		
		
	
		
			
			| 
				292
			 | 
			
				448
			 | 
			
			
				
				 }; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				449
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				450
			 | 
			
			
				
				+/** 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				451
			 | 
			
			
				
				+ * Update ARP cache on network device creation 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				452
			 | 
			
			
				
				+ * 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				453
			 | 
			
			
				
				+ * @v netdev		Network device 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				454
			 | 
			
			
				
				+ */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				455
			 | 
			
			
				
				+static int arp_probe ( struct net_device *netdev __unused ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				456
			 | 
			
			
				
				+	/* Nothing to do */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				457
			 | 
			
			
				
				+	return 0; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				458
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				459
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				460
			 | 
			
			
				
				+/** 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				461
			 | 
			
			
				
				+ * Update ARP cache on network device state change or removal 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				462
			 | 
			
			
				
				+ * 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				463
			 | 
			
			
				
				+ * @v netdev		Network device 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				464
			 | 
			
			
				
				+ */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				465
			 | 
			
			
				
				+static void arp_flush ( struct net_device *netdev ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				466
			 | 
			
			
				
				+	struct arp_entry *arp; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				467
			 | 
			
			
				
				+	struct arp_entry *tmp; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				468
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				469
			 | 
			
			
				
				+	/* Remove all ARP cache entries when a network device is closed */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				470
			 | 
			
			
				
				+	if ( ! netdev_is_open ( netdev ) ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				471
			 | 
			
			
				
				+		list_for_each_entry_safe ( arp, tmp, &arp_entries, list ) 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				472
			 | 
			
			
				
				+			arp_destroy ( arp, -ENODEV ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				473
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				474
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				475
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				476
			 | 
			
			
				
				+/** ARP driver (for net device notifications) */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				477
			 | 
			
			
				
				+struct net_driver arp_net_driver __net_driver = { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				478
			 | 
			
			
				
				+	.name = "ARP", 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				479
			 | 
			
			
				
				+	.probe = arp_probe, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				480
			 | 
			
			
				
				+	.notify = arp_flush, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				481
			 | 
			
			
				
				+	.remove = arp_flush, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				482
			 | 
			
			
				
				+}; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				483
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				484
			 | 
			
			
				
				+/** 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				485
			 | 
			
			
				
				+ * Discard some cached ARP entries 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				486
			 | 
			
			
				
				+ * 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				487
			 | 
			
			
				
				+ * @ret discarded	Number of cached items discarded 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				488
			 | 
			
			
				
				+ */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				489
			 | 
			
			
				
				+static unsigned int arp_discard ( void ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				490
			 | 
			
			
				
				+	struct arp_entry *arp; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				491
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				492
			 | 
			
			
				
				+	/* Drop oldest cache entry, if any */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				493
			 | 
			
			
				
				+	list_for_each_entry_reverse ( arp, &arp_entries, list ) { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				494
			 | 
			
			
				
				+		arp_destroy ( arp, -ENOBUFS ); 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				495
			 | 
			
			
				
				+		return 1; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				496
			 | 
			
			
				
				+	} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				497
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				498
			 | 
			
			
				
				+	return 0; 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				499
			 | 
			
			
				
				+} 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				500
			 | 
			
			
				
				+ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				501
			 | 
			
			
				
				+/** ARP cache discarder */ 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				502
			 | 
			
			
				
				+struct cache_discarder arp_cache_discarder __cache_discarder = { 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				503
			 | 
			
			
				
				+	.discard = arp_discard, 
			 | 
		
		
	
		
			
			| 
				
			 | 
			
				504
			 | 
			
			
				
				+}; 
			 |