66f9bd4cf398f35355ee6b365f7902abce2bf75e
[people/xl0/gpxe.git] / src / net / arp.c
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/netdevice.h>
27 #include <gpxe/arp.h>
28
29 /** @file
30  *
31  * Address Resolution Protocol
32  *
33  * This file implements the address resolution protocol as defined in
34  * RFC826.  The implementation is media-independent and
35  * protocol-independent; it is not limited to Ethernet or to IPv4.
36  *
37  */
38
39 /** An ARP cache entry */
40 struct arp_entry {
41         /** Network-layer protocol */
42         struct net_protocol *net_protocol;
43         /** Link-layer protocol */
44         struct ll_protocol *ll_protocol;
45         /** Network-layer address */
46         uint8_t net_addr[MAX_NET_ADDR_LEN];
47         /** Link-layer address */
48         uint8_t ll_addr[MAX_LL_ADDR_LEN];
49 };
50
51 /** Number of entries in the ARP cache
52  *
53  * This is a global cache, covering all network interfaces,
54  * network-layer protocols and link-layer protocols.
55  */
56 #define NUM_ARP_ENTRIES 4
57
58 /** The ARP cache */
59 static struct arp_entry arp_table[NUM_ARP_ENTRIES];
60 #define arp_table_end &arp_table[NUM_ARP_ENTRIES]
61
62 static unsigned int next_new_arp_entry = 0;
63
64 struct net_protocol arp_protocol;
65
66 /**
67  * Find entry in the ARP cache
68  *
69  * @v ll_protocol       Link-layer protocol
70  * @v net_protocol      Network-layer protocol
71  * @v net_addr          Network-layer address
72  * @ret arp             ARP cache entry, or NULL if not found
73  *
74  */
75 static struct arp_entry *
76 arp_find_entry ( struct ll_protocol *ll_protocol,
77                  struct net_protocol *net_protocol,
78                  const void *net_addr ) {
79         struct arp_entry *arp;
80
81         for ( arp = arp_table ; arp < arp_table_end ; arp++ ) {
82                 if ( ( arp->ll_protocol == ll_protocol ) &&
83                      ( arp->net_protocol == net_protocol ) &&
84                      ( memcmp ( arp->net_addr, net_addr,
85                                 net_protocol->net_addr_len ) == 0 ) )
86                         return arp;
87         }
88         return NULL;
89 }
90
91 /**
92  * Look up media-specific link-layer address in the ARP cache
93  *
94  * @v netdev            Network device
95  * @v net_protocol      Network-layer protocol
96  * @v dest_net_addr     Destination network-layer address
97  * @v source_net_addr   Source network-layer address
98  * @ret dest_ll_addr    Destination link layer address
99  * @ret rc              Return status code
100  *
101  * This function will use the ARP cache to look up the link-layer
102  * address for the link-layer protocol associated with the network
103  * device and the given network-layer protocol and addresses.  If
104  * found, the destination link-layer address will be filled in in @c
105  * dest_ll_addr.
106  *
107  * If no address is found in the ARP cache, an ARP request will be
108  * transmitted on the specified network device and -ENOENT will be
109  * returned.
110  */
111 int arp_resolve ( struct net_device *netdev, struct net_protocol *net_protocol,
112                   const void *dest_net_addr, const void *source_net_addr,
113                   void *dest_ll_addr ) {
114         struct ll_protocol *ll_protocol = netdev->ll_protocol;
115         const struct arp_entry *arp;
116         struct pk_buff *pkb;
117         struct arphdr *arphdr;
118         int rc;
119
120         /* Look for existing entry in ARP table */
121         arp = arp_find_entry ( ll_protocol, net_protocol, dest_net_addr );
122         if ( arp ) {
123                 DBG ( "ARP cache hit: %s %s => %s %s\n",
124                       net_protocol->name, net_protocol->ntoa ( arp->net_addr ),
125                       ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) );
126                 memcpy ( dest_ll_addr, arp->ll_addr, ll_protocol->ll_addr_len);
127                 return 0;
128         }
129         DBG ( "ARP cache miss: %s %s\n", net_protocol->name,
130               net_protocol->ntoa ( dest_net_addr ) );
131
132         /* Allocate ARP packet */
133         pkb = alloc_pkb ( MAX_LL_HEADER_LEN + sizeof ( *arphdr ) +
134                           2 * ( MAX_LL_ADDR_LEN + MAX_NET_ADDR_LEN ) );
135         if ( ! pkb )
136                 return -ENOMEM;
137         pkb->net_protocol = &arp_protocol;
138         pkb_reserve ( pkb, MAX_LL_HEADER_LEN );
139
140         /* Build up ARP request */
141         arphdr = pkb_put ( pkb, sizeof ( *arphdr ) );
142         arphdr->ar_hrd = ll_protocol->ll_proto;
143         arphdr->ar_hln = ll_protocol->ll_addr_len;
144         arphdr->ar_pro = net_protocol->net_proto;
145         arphdr->ar_pln = net_protocol->net_addr_len;
146         arphdr->ar_op = htons ( ARPOP_REQUEST );
147         memcpy ( pkb_put ( pkb, ll_protocol->ll_addr_len ),
148                  netdev->ll_addr, ll_protocol->ll_addr_len );
149         memcpy ( pkb_put ( pkb, net_protocol->net_addr_len ),
150                  source_net_addr, net_protocol->net_addr_len );
151         memset ( pkb_put ( pkb, ll_protocol->ll_addr_len ),
152                  0, ll_protocol->ll_addr_len );
153         memcpy ( pkb_put ( pkb, net_protocol->net_addr_len ),
154                  dest_net_addr, net_protocol->net_addr_len );
155
156         /* Transmit ARP request */
157         if ( ( rc = net_transmit ( pkb, netdev, &arp_protocol, 
158                                    ll_protocol->ll_broadcast ) ) != 0 )
159                 return rc;
160
161         return -ENOENT;
162 }
163
164 /**
165  * Process incoming ARP packets
166  *
167  * @v pkb               Packet buffer
168  * @ret rc              Return status code
169  *
170  * This handles ARP requests and responses as detailed in RFC826.  The
171  * method detailed within the RFC is pretty optimised, handling
172  * requests and responses with basically a single code path and
173  * avoiding the need for extraneous ARP requests; read the RFC for
174  * details.
175  */
176 static int arp_rx ( struct pk_buff *pkb ) {
177         struct arphdr *arphdr = pkb->data;
178         struct ll_protocol *ll_protocol;
179         struct net_protocol *net_protocol;
180         struct arp_entry *arp;
181         struct net_device *netdev;
182         int merge = 0;
183
184         /* Identify link-layer and network-layer protocols */
185         ll_protocol = pkb->ll_protocol;
186         net_protocol = find_net_protocol ( arphdr->ar_pro );
187         if ( ! net_protocol )
188                 goto done;
189
190         /* Sanity checks */
191         if ( ( arphdr->ar_hrd != ll_protocol->ll_proto ) ||
192              ( arphdr->ar_hln != ll_protocol->ll_addr_len ) ||
193              ( arphdr->ar_pln != net_protocol->net_addr_len ) )
194                 goto done;
195
196         /* See if we have an entry for this sender, and update it if so */
197         arp = arp_find_entry ( ll_protocol, net_protocol,
198                                arp_sender_pa ( arphdr ) );
199         if ( arp ) {
200                 memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ),
201                          arphdr->ar_hln );
202                 merge = 1;
203                 DBG ( "ARP cache update: %s %s => %s %s\n",
204                       net_protocol->name, net_protocol->ntoa ( arp->net_addr ),
205                       ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) );
206         }
207
208         /* See if we own the target protocol address */
209         netdev = find_netdev_by_net_addr ( net_protocol,
210                                            arp_target_pa ( arphdr ) );
211         if ( ! netdev )
212                 goto done;
213         
214         /* Create new ARP table entry if necessary */
215         if ( ! merge ) {
216                 arp = &arp_table[next_new_arp_entry++ % NUM_ARP_ENTRIES];
217                 arp->ll_protocol = ll_protocol;
218                 arp->net_protocol = net_protocol;
219                 memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ),
220                          arphdr->ar_hln );
221                 memcpy ( arp->net_addr, arp_sender_pa ( arphdr ),
222                          arphdr->ar_pln);
223                 DBG ( "ARP cache add: %s %s => %s %s\n",
224                       net_protocol->name, net_protocol->ntoa ( arp->net_addr ),
225                       ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) );
226         }
227
228         /* If it's not a request, there's nothing more to do */
229         if ( arphdr->ar_op != htons ( ARPOP_REQUEST ) )
230                 goto done;
231
232         /* Change request to a reply */
233         DBG ( "ARP reply: %s %s => %s %s\n", net_protocol->name,
234               net_protocol->ntoa ( arp_target_pa ( arphdr ) ),
235               ll_protocol->name, ll_protocol->ntoa ( netdev->ll_addr ) );
236         arphdr->ar_op = htons ( ARPOP_REPLY );
237         memswap ( arp_sender_ha ( arphdr ), arp_target_ha ( arphdr ),
238                  arphdr->ar_hln + arphdr->ar_pln );
239         memcpy ( arp_sender_ha ( arphdr ), netdev->ll_addr, arphdr->ar_hln );
240
241         /* Send reply */
242         net_transmit ( pkb, netdev, &arp_protocol, arp_target_ha (arphdr ) );
243         pkb = NULL;
244
245  done:
246         free_pkb ( pkb );
247         return 0;
248 }
249
250 /**
251  * Transcribe ARP address
252  *
253  * @v net_addr  ARP address
254  * @ret string  "<ARP>"
255  *
256  * This operation is meaningless for the ARP protocol.
257  */
258 static const char *
259 arp_ntoa ( const void *net_addr __attribute__ (( unused )) ) {
260         return "<ARP>";
261 }
262
263 /** ARP protocol */
264 struct net_protocol arp_protocol = {
265         .name = "ARP",
266         .net_proto = htons ( ETH_P_ARP ),
267         .rx_process = arp_rx,
268         .ntoa = arp_ntoa,
269 };
270
271 NET_PROTOCOL ( arp_protocol );