mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-04 16:23:55 -06:00
Simple ARP table
This patch adds a simple ARP table in Slirp and also adds handling of gratuitous ARP requests. Signed-off-by: Fabien Chouteau <chouteau@adacore.com> Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
This commit is contained in:
parent
bafc72ab01
commit
1a0ca1e1f6
5 changed files with 169 additions and 59 deletions
|
@ -31,11 +31,11 @@
|
|||
struct in_addr loopback_addr;
|
||||
|
||||
/* emulated hosts use the MAC addr 52:55:IP:IP:IP:IP */
|
||||
static const uint8_t special_ethaddr[6] = {
|
||||
static const uint8_t special_ethaddr[ETH_ALEN] = {
|
||||
0x52, 0x55, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static const uint8_t zero_ethaddr[6] = { 0, 0, 0, 0, 0, 0 };
|
||||
static const uint8_t zero_ethaddr[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
/* XXX: suppress those select globals */
|
||||
fd_set *global_readfds, *global_writefds, *global_xfds;
|
||||
|
@ -599,42 +599,8 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
|
|||
global_xfds = NULL;
|
||||
}
|
||||
|
||||
#define ETH_ALEN 6
|
||||
#define ETH_HLEN 14
|
||||
|
||||
#define ETH_P_IP 0x0800 /* Internet Protocol packet */
|
||||
#define ETH_P_ARP 0x0806 /* Address Resolution packet */
|
||||
|
||||
#define ARPOP_REQUEST 1 /* ARP request */
|
||||
#define ARPOP_REPLY 2 /* ARP reply */
|
||||
|
||||
struct ethhdr
|
||||
{
|
||||
unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
|
||||
unsigned char h_source[ETH_ALEN]; /* source ether addr */
|
||||
unsigned short h_proto; /* packet type ID field */
|
||||
};
|
||||
|
||||
struct arphdr
|
||||
{
|
||||
unsigned short ar_hrd; /* format of hardware address */
|
||||
unsigned short ar_pro; /* format of protocol address */
|
||||
unsigned char ar_hln; /* length of hardware address */
|
||||
unsigned char ar_pln; /* length of protocol address */
|
||||
unsigned short ar_op; /* ARP opcode (command) */
|
||||
|
||||
/*
|
||||
* Ethernet looks like this : This bit is variable sized however...
|
||||
*/
|
||||
unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
|
||||
uint32_t ar_sip; /* sender IP address */
|
||||
unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
|
||||
uint32_t ar_tip ; /* target IP address */
|
||||
} __attribute__((packed));
|
||||
|
||||
static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
|
||||
{
|
||||
struct ethhdr *eh = (struct ethhdr *)pkt;
|
||||
struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
|
||||
uint8_t arp_reply[max(ETH_HLEN + sizeof(struct arphdr), 64)];
|
||||
struct ethhdr *reh = (struct ethhdr *)arp_reply;
|
||||
|
@ -645,6 +611,12 @@ static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
|
|||
ar_op = ntohs(ah->ar_op);
|
||||
switch(ar_op) {
|
||||
case ARPOP_REQUEST:
|
||||
if (ah->ar_tip == ah->ar_sip) {
|
||||
/* Gratuitous ARP */
|
||||
arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ah->ar_tip & slirp->vnetwork_mask.s_addr) ==
|
||||
slirp->vnetwork_addr.s_addr) {
|
||||
if (ah->ar_tip == slirp->vnameserver_addr.s_addr ||
|
||||
|
@ -657,8 +629,8 @@ static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
|
|||
return;
|
||||
arp_ok:
|
||||
memset(arp_reply, 0, sizeof(arp_reply));
|
||||
/* XXX: make an ARP request to have the client address */
|
||||
memcpy(slirp->client_ethaddr, eh->h_source, ETH_ALEN);
|
||||
|
||||
arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
|
||||
|
||||
/* ARP request for alias/dns mac address */
|
||||
memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
|
||||
|
@ -679,11 +651,7 @@ static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
|
|||
}
|
||||
break;
|
||||
case ARPOP_REPLY:
|
||||
/* reply to request of client mac address ? */
|
||||
if (!memcmp(slirp->client_ethaddr, zero_ethaddr, ETH_ALEN) &&
|
||||
ah->ar_sip == slirp->client_ipaddr.s_addr) {
|
||||
memcpy(slirp->client_ethaddr, ah->ar_sha, ETH_ALEN);
|
||||
}
|
||||
arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -729,15 +697,16 @@ void if_encap(Slirp *slirp, const uint8_t *ip_data, int ip_data_len)
|
|||
{
|
||||
uint8_t buf[1600];
|
||||
struct ethhdr *eh = (struct ethhdr *)buf;
|
||||
uint8_t ethaddr[ETH_ALEN];
|
||||
const struct ip *iph = (const struct ip *)ip_data;
|
||||
|
||||
if (ip_data_len + ETH_HLEN > sizeof(buf))
|
||||
return;
|
||||
|
||||
if (!memcmp(slirp->client_ethaddr, zero_ethaddr, ETH_ALEN)) {
|
||||
|
||||
if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
|
||||
uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
|
||||
struct ethhdr *reh = (struct ethhdr *)arp_req;
|
||||
struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);
|
||||
const struct ip *iph = (const struct ip *)ip_data;
|
||||
|
||||
/* If the client addr is not known, there is no point in
|
||||
sending the packet to it. Normally the sender should have
|
||||
|
@ -765,7 +734,7 @@ void if_encap(Slirp *slirp, const uint8_t *ip_data, int ip_data_len)
|
|||
slirp->client_ipaddr = iph->ip_dst;
|
||||
slirp_output(slirp->opaque, arp_req, sizeof(arp_req));
|
||||
} else {
|
||||
memcpy(eh->h_dest, slirp->client_ethaddr, ETH_ALEN);
|
||||
memcpy(eh->h_dest, ethaddr, ETH_ALEN);
|
||||
memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
|
||||
/* XXX: not correct */
|
||||
memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue