Browse Source

First version. ARP protocol independence in less than the size of uIP's

Ethernet-and-IPv4-only ARP module.  :)
tags/v0.9.3
Michael Brown 18 years ago
parent
commit
9f67ad9db0
1 changed files with 244 additions and 0 deletions
  1. 244
    0
      src/net/arp.c

+ 244
- 0
src/net/arp.c View File

@@ -0,0 +1,244 @@
1
+/*
2
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+#include <stdint.h>
20
+#include <string.h>
21
+#include <byteswap.h>
22
+#include <errno.h>
23
+#include <gpxe/if_ether.h>
24
+#include <gpxe/if_arp.h>
25
+#include <gpxe/pkbuff.h>
26
+#include <gpxe/llh.h>
27
+#include <gpxe/netdevice.h>
28
+#include <gpxe/arp.h>
29
+
30
+/** @file
31
+ *
32
+ * Address Resolution Protocol
33
+ *
34
+ * This file implements the address resolution protocol as defined in
35
+ * RFC826.  The implementation is media-independent and
36
+ * protocol-independent; it is not limited to Ethernet or to IPv4.
37
+ *
38
+ */
39
+
40
+/** An ARP cache entry */
41
+struct arp_entry {
42
+	/** Network-layer protocol */
43
+	uint16_t net_proto;
44
+	/** Link-layer protocol */
45
+	uint16_t ll_proto;
46
+	/** Network-layer address */
47
+	uint8_t net_addr[MAX_NET_ADDR_LEN];
48
+	/** Link-layer address */
49
+	uint8_t ll_addr[MAX_LLH_ADDR_LEN];
50
+};
51
+
52
+/** Number of entries in the ARP cache
53
+ *
54
+ * This is a global cache, covering all network interfaces,
55
+ * network-layer protocols and link-layer protocols.
56
+ */
57
+#define NUM_ARP_ENTRIES 4
58
+
59
+/** The ARP cache */
60
+static struct arp_entry arp_table[NUM_ARP_ENTRIES];
61
+#define arp_table_end &arp_table[NUM_ARP_ENTRIES]
62
+
63
+static unsigned int next_new_arp_entry = 0;
64
+
65
+/**
66
+ * Find entry in the ARP cache
67
+ *
68
+ * @v ll_proto		Link-layer protocol
69
+ * @v net_proto		Network-layer protocol
70
+ * @v net_addr		Network-layer address
71
+ * @v net_addr_len	Network-layer address length
72
+ * @ret arp		ARP cache entry, or NULL if not found
73
+ *
74
+ */
75
+static struct arp_entry *
76
+arp_find_entry ( uint16_t ll_proto, uint16_t net_proto, const void *net_addr,
77
+		 size_t net_addr_len ) {
78
+	struct arp_entry *arp;
79
+
80
+	for ( arp = arp_table ; arp < arp_table_end ; arp++ ) {
81
+		if ( ( arp->ll_proto == ll_proto ) &&
82
+		     ( arp->net_proto == net_proto ) &&
83
+		     ( memcmp ( arp->net_addr, net_addr, net_addr_len ) == 0 ))
84
+			return arp;
85
+	}
86
+	return NULL;
87
+}
88
+
89
+/**
90
+ * Look up media-specific link-layer address in the ARP cache
91
+ *
92
+ * @v netdev		Network device
93
+ * @v pkb		Packet buffer
94
+ * @v ll_addr		Buffer to contain link-layer address
95
+ * @ret rc		Return status code
96
+ *
97
+ * The packet buffer must start with a media-independent link-layer
98
+ * header (a struct @c gpxehdr).  This function will use the ARP cache
99
+ * to look up the link-layer address for the media corresponding to
100
+ * @c netdev and the network-layer address as specified in @c gpxehdr.
101
+ *
102
+ * If no address is found in the ARP cache, an ARP request will be
103
+ * transmitted, -ENOENT will be returned, and the packet buffer
104
+ * contents will be undefined.
105
+ */
106
+int arp_resolve ( struct net_device *netdev, struct pk_buff *pkb,
107
+		  void *ll_addr ) {
108
+	struct gpxehdr *gpxehdr = pkb->data;
109
+	const struct arp_entry *arp;
110
+	struct net_interface *netif;
111
+	struct arphdr *arphdr;
112
+
113
+	/* Look for existing entry in ARP table */
114
+	arp = arp_find_entry ( netdev->ll_proto, gpxehdr->net_proto,
115
+			       gpxehdr->net_addr, gpxehdr->net_addr_len );
116
+	if ( arp ) {
117
+		memcpy ( ll_addr, arp->ll_addr, netdev->ll_addr_len );
118
+		return 0;
119
+	}
120
+
121
+	/* Find interface for this protocol */
122
+	netif = netdev_find_netif ( netdev, gpxehdr->net_proto );
123
+	if ( ! netif )
124
+		return -EAFNOSUPPORT;
125
+
126
+	/* Build up ARP request */
127
+	pkb_unput ( pkb, pkb_len ( pkb ) - sizeof ( *gpxehdr ) );
128
+	arphdr = pkb_put ( pkb, sizeof ( *arphdr ) );
129
+	arphdr->ar_hrd = netdev->ll_proto;
130
+	arphdr->ar_hln = netdev->ll_addr_len;
131
+	arphdr->ar_pro = gpxehdr->net_proto;
132
+	arphdr->ar_pln = gpxehdr->net_addr_len;
133
+	arphdr->ar_op = htons ( ARPOP_REQUEST );
134
+	memcpy ( pkb_put ( pkb, netdev->ll_addr_len ),
135
+		 netdev->ll_addr, netdev->ll_addr_len );
136
+	memcpy ( pkb_put ( pkb, netif->net_addr_len ),
137
+		 netif->net_addr, netif->net_addr_len );
138
+	memset ( pkb_put ( pkb, netdev->ll_addr_len ),
139
+		 0xff, netdev->ll_addr_len );
140
+	memcpy ( pkb_put ( pkb, netif->net_addr_len ),
141
+		 gpxehdr->net_addr, netif->net_addr_len );
142
+	pkb_pull ( pkb, sizeof ( *gpxehdr ) );
143
+
144
+	/* Locate ARP interface and send ARP request */
145
+	netif = netdev_find_netif ( netdev, htons ( ETH_P_ARP ) );
146
+	assert ( netif != NULL );
147
+	netif_send ( netif, pkb );
148
+
149
+	return -ENOENT;
150
+}
151
+
152
+/**
153
+ * Process incoming ARP packets
154
+ *
155
+ * @v arp_netif		Network interface for ARP packets
156
+ * @v pkb		Packet buffer
157
+ * @ret rc		Return status code
158
+ *
159
+ * This handles ARP requests and responses as detailed in RFC826.  The
160
+ * method detailed within the RFC is pretty optimised, handling
161
+ * requests and responses with basically a single code path and
162
+ * avoiding the need for extraneous ARP requests; read the RFC for
163
+ * details.
164
+ */
165
+int arp_process ( struct net_interface *arp_netif, struct pk_buff *pkb ) {
166
+	struct arphdr *arphdr = pkb->data;
167
+	struct net_device *netdev = arp_netif->netdev;
168
+	struct net_interface *netif;
169
+	struct arp_entry *arp;
170
+	int merge = 0;
171
+
172
+	/* Check for correct link-layer protocol and length */
173
+	if ( ( arphdr->ar_hrd != netdev->ll_proto ) ||
174
+	     ( arphdr->ar_hln != netdev->ll_addr_len ) )
175
+		return 0;
176
+
177
+	/* See if we have an interface for this network-layer protocol */
178
+	netif = netdev_find_netif ( netdev, arphdr->ar_pro );
179
+	if ( ! netif )
180
+		return 0;
181
+	if ( arphdr->ar_pln != netif->net_addr_len )
182
+		return 0;
183
+
184
+	/* See if we have an entry for this sender, and update it if so */
185
+	arp = arp_find_entry ( arphdr->ar_hrd, arphdr->ar_pro,
186
+			       arp_sender_pa ( arphdr ), arphdr->ar_pln );
187
+	if ( arp ) {
188
+		memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ),
189
+			 arphdr->ar_hln );
190
+		merge = 1;
191
+	}
192
+
193
+	/* See if we are the target protocol address */
194
+	if ( memcmp ( arp_target_pa ( arphdr ), netif->net_addr,
195
+		      arphdr->ar_pln ) != 0 )
196
+		return 0;
197
+
198
+	/* Create new ARP table entry if necessary */
199
+	if ( ! merge ) {
200
+		arp = &arp_table[next_new_arp_entry++ % NUM_ARP_ENTRIES];
201
+		arp->ll_proto = arphdr->ar_hrd;
202
+		arp->net_proto = arphdr->ar_pro;
203
+		memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ),
204
+			 arphdr->ar_hln );
205
+		memcpy ( arp->net_addr, arp_sender_pa ( arphdr ),
206
+			 arphdr->ar_pln );
207
+	}
208
+
209
+	/* If it's not a request, there's nothing more to do */
210
+	if ( arphdr->ar_op != htons ( ARPOP_REQUEST ) )
211
+		return 0;
212
+
213
+	/* Change request to a reply, and send it */
214
+	arphdr->ar_op = htons ( ARPOP_REPLY );
215
+	memcpy ( arp_sender_ha ( arphdr ), arp_target_ha ( arphdr ),
216
+		 arphdr->ar_hln + arphdr->ar_pln );
217
+	memcpy ( arp_target_ha ( arphdr ), netdev->ll_addr, arphdr->ar_hln );
218
+	memcpy ( arp_target_pa ( arphdr ), netif->net_addr, arphdr->ar_pln );
219
+	netif_send ( arp_netif, pkb );
220
+
221
+	return 0;
222
+}
223
+
224
+/**
225
+ * Add media-independent link-layer header
226
+ *
227
+ * @v arp_netif		Network interface for ARP packets
228
+ * @v pkb		Packet buffer
229
+ * @ret rc		Return status code
230
+ */
231
+int arp_add_generic_header ( struct net_interface *arp_netif __unused,
232
+			     struct pk_buff *pkb ) {
233
+	struct arphdr *arphdr = pkb->data;
234
+	struct gpxehdr *gpxehdr;
235
+
236
+	/* We're ARP; we always know the raw link-layer address we want */
237
+	gpxehdr = pkb_push ( pkb, sizeof ( *gpxehdr ) );
238
+	gpxehdr->net_proto = htons ( ETH_P_ARP );
239
+	gpxehdr->flags = GPXE_FL_RAW;
240
+	gpxehdr->net_addr_len = arphdr->ar_hln;
241
+	memcpy ( gpxehdr->net_addr, arp_target_ha ( arphdr ), arphdr->ar_hln );
242
+	
243
+	return 0;
244
+}

Loading…
Cancel
Save