00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020
00021 #include <stdint.h>
00022 #include <string.h>
00023 #include <byteswap.h>
00024 #include <errno.h>
00025 #include <gpxe/if_ether.h>
00026 #include <gpxe/if_arp.h>
00027 #include <gpxe/iobuf.h>
00028 #include <gpxe/netdevice.h>
00029 #include <gpxe/arp.h>
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 struct arp_entry {
00043
00044 struct net_protocol *net_protocol;
00045
00046 struct ll_protocol *ll_protocol;
00047
00048 uint8_t net_addr[MAX_NET_ADDR_LEN];
00049
00050 uint8_t ll_addr[MAX_LL_ADDR_LEN];
00051 };
00052
00053
00054
00055
00056
00057
00058 #define NUM_ARP_ENTRIES 4
00059
00060
00061 static struct arp_entry arp_table[NUM_ARP_ENTRIES];
00062 #define arp_table_end &arp_table[NUM_ARP_ENTRIES]
00063
00064 static unsigned int next_new_arp_entry = 0;
00065
00066 struct net_protocol arp_protocol;
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077 static struct arp_entry *
00078 arp_find_entry ( struct ll_protocol *ll_protocol,
00079 struct net_protocol *net_protocol,
00080 const void *net_addr ) {
00081 struct arp_entry *arp;
00082
00083 for ( arp = arp_table ; arp < arp_table_end ; arp++ ) {
00084 if ( ( arp->ll_protocol == ll_protocol ) &&
00085 ( arp->net_protocol == net_protocol ) &&
00086 ( memcmp ( arp->net_addr, net_addr,
00087 net_protocol->net_addr_len ) == 0 ) )
00088 return arp;
00089 }
00090 return NULL;
00091 }
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113 int arp_resolve ( struct net_device *netdev, struct net_protocol *net_protocol,
00114 const void *dest_net_addr, const void *source_net_addr,
00115 void *dest_ll_addr ) {
00116 struct ll_protocol *ll_protocol = netdev->ll_protocol;
00117 const struct arp_entry *arp;
00118 struct io_buffer *iobuf;
00119 struct arphdr *arphdr;
00120 int rc;
00121
00122
00123 arp = arp_find_entry ( ll_protocol, net_protocol, dest_net_addr );
00124 if ( arp ) {
00125 DBG ( "ARP cache hit: %s %s => %s %s\n",
00126 net_protocol->name, net_protocol->ntoa ( arp->net_addr ),
00127 ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) );
00128 memcpy ( dest_ll_addr, arp->ll_addr, ll_protocol->ll_addr_len);
00129 return 0;
00130 }
00131 DBG ( "ARP cache miss: %s %s\n", net_protocol->name,
00132 net_protocol->ntoa ( dest_net_addr ) );
00133
00134
00135 iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *arphdr ) +
00136 2 * ( MAX_LL_ADDR_LEN + MAX_NET_ADDR_LEN ) );
00137 if ( ! iobuf )
00138 return -ENOMEM;
00139 iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
00140
00141
00142 arphdr = iob_put ( iobuf, sizeof ( *arphdr ) );
00143 arphdr->ar_hrd = ll_protocol->ll_proto;
00144 arphdr->ar_hln = ll_protocol->ll_addr_len;
00145 arphdr->ar_pro = net_protocol->net_proto;
00146 arphdr->ar_pln = net_protocol->net_addr_len;
00147 arphdr->ar_op = htons ( ARPOP_REQUEST );
00148 memcpy ( iob_put ( iobuf, ll_protocol->ll_addr_len ),
00149 netdev->ll_addr, ll_protocol->ll_addr_len );
00150 memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ),
00151 source_net_addr, net_protocol->net_addr_len );
00152 memset ( iob_put ( iobuf, ll_protocol->ll_addr_len ),
00153 0, ll_protocol->ll_addr_len );
00154 memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ),
00155 dest_net_addr, net_protocol->net_addr_len );
00156
00157
00158 if ( ( rc = net_tx ( iobuf, netdev, &arp_protocol,
00159 netdev->ll_broadcast ) ) != 0 )
00160 return rc;
00161
00162 return -ENOENT;
00163 }
00164
00165
00166
00167
00168
00169
00170
00171
00172 static struct arp_net_protocol * arp_find_protocol ( uint16_t net_proto ) {
00173 struct arp_net_protocol *arp_net_protocol;
00174
00175 for_each_table_entry ( arp_net_protocol, ARP_NET_PROTOCOLS ) {
00176 if ( arp_net_protocol->net_protocol->net_proto == net_proto ) {
00177 return arp_net_protocol;
00178 }
00179 }
00180 return NULL;
00181 }
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197 static int arp_rx ( struct io_buffer *iobuf, struct net_device *netdev,
00198 const void *ll_source __unused ) {
00199 struct arphdr *arphdr = iobuf->data;
00200 struct arp_net_protocol *arp_net_protocol;
00201 struct net_protocol *net_protocol;
00202 struct ll_protocol *ll_protocol;
00203 struct arp_entry *arp;
00204 int merge = 0;
00205
00206
00207 arp_net_protocol = arp_find_protocol ( arphdr->ar_pro );
00208 if ( ! arp_net_protocol )
00209 goto done;
00210 net_protocol = arp_net_protocol->net_protocol;
00211 ll_protocol = netdev->ll_protocol;
00212
00213
00214 if ( ( arphdr->ar_hrd != ll_protocol->ll_proto ) ||
00215 ( arphdr->ar_hln != ll_protocol->ll_addr_len ) ||
00216 ( arphdr->ar_pln != net_protocol->net_addr_len ) )
00217 goto done;
00218
00219
00220 arp = arp_find_entry ( ll_protocol, net_protocol,
00221 arp_sender_pa ( arphdr ) );
00222 if ( arp ) {
00223 memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ),
00224 arphdr->ar_hln );
00225 merge = 1;
00226 DBG ( "ARP cache update: %s %s => %s %s\n",
00227 net_protocol->name, net_protocol->ntoa ( arp->net_addr ),
00228 ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) );
00229 }
00230
00231
00232 if ( arp_net_protocol->check ( netdev, arp_target_pa ( arphdr ) ) != 0)
00233 goto done;
00234
00235
00236 if ( ! merge ) {
00237 arp = &arp_table[next_new_arp_entry++ % NUM_ARP_ENTRIES];
00238 arp->ll_protocol = ll_protocol;
00239 arp->net_protocol = net_protocol;
00240 memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ),
00241 arphdr->ar_hln );
00242 memcpy ( arp->net_addr, arp_sender_pa ( arphdr ),
00243 arphdr->ar_pln);
00244 DBG ( "ARP cache add: %s %s => %s %s\n",
00245 net_protocol->name, net_protocol->ntoa ( arp->net_addr ),
00246 ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) );
00247 }
00248
00249
00250 if ( arphdr->ar_op != htons ( ARPOP_REQUEST ) )
00251 goto done;
00252
00253
00254 DBG ( "ARP reply: %s %s => %s %s\n", net_protocol->name,
00255 net_protocol->ntoa ( arp_target_pa ( arphdr ) ),
00256 ll_protocol->name, ll_protocol->ntoa ( netdev->ll_addr ) );
00257 arphdr->ar_op = htons ( ARPOP_REPLY );
00258 memswap ( arp_sender_ha ( arphdr ), arp_target_ha ( arphdr ),
00259 arphdr->ar_hln + arphdr->ar_pln );
00260 memcpy ( arp_sender_ha ( arphdr ), netdev->ll_addr, arphdr->ar_hln );
00261
00262
00263 net_tx ( iob_disown ( iobuf ), netdev, &arp_protocol,
00264 arp_target_ha ( arphdr ) );
00265
00266 done:
00267 free_iob ( iobuf );
00268 return 0;
00269 }
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279 static const char * arp_ntoa ( const void *net_addr __unused ) {
00280 return "<ARP>";
00281 }
00282
00283
00284 struct net_protocol arp_protocol __net_protocol = {
00285 .name = "ARP",
00286 .net_proto = htons ( ETH_P_ARP ),
00287 .rx = arp_rx,
00288 .ntoa = arp_ntoa,
00289 };