allow SLIRP to make an ARP request to get the client MAC address. It is useful if an inbound connection is done to a VM which did not send outbound IP packets
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5498 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
89c0f6438d
commit
de806f0786
@ -16,7 +16,11 @@ static const uint8_t special_ethaddr[6] = {
|
|||||||
0x52, 0x54, 0x00, 0x12, 0x35, 0x00
|
0x52, 0x54, 0x00, 0x12, 0x35, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* ARP cache for the guest IP addresses (XXX: allow many entries) */
|
||||||
uint8_t client_ethaddr[6];
|
uint8_t client_ethaddr[6];
|
||||||
|
static struct in_addr client_ipaddr;
|
||||||
|
|
||||||
|
static const uint8_t zero_ethaddr[6] = { 0, 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
int do_slowtimo;
|
int do_slowtimo;
|
||||||
int link_up;
|
int link_up;
|
||||||
@ -597,6 +601,13 @@ static void arp_input(const uint8_t *pkt, int pkt_len)
|
|||||||
slirp_output(arp_reply, sizeof(arp_reply));
|
slirp_output(arp_reply, sizeof(arp_reply));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ARPOP_REPLY:
|
||||||
|
/* reply to request of client mac address ? */
|
||||||
|
if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN) &&
|
||||||
|
!memcmp(ah->ar_sip, &client_ipaddr.s_addr, 4)) {
|
||||||
|
memcpy(client_ethaddr, ah->ar_sha, ETH_ALEN);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -641,14 +652,47 @@ void if_encap(const uint8_t *ip_data, int ip_data_len)
|
|||||||
|
|
||||||
if (ip_data_len + ETH_HLEN > sizeof(buf))
|
if (ip_data_len + ETH_HLEN > sizeof(buf))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN)) {
|
||||||
|
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;
|
||||||
|
|
||||||
memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
|
/* If the client addr is not known, there is no point in
|
||||||
memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
|
sending the packet to it. Normally the sender should have
|
||||||
/* XXX: not correct */
|
done an ARP request to get its MAC address. Here we do it
|
||||||
eh->h_source[5] = CTL_ALIAS;
|
in place of sending the packet and we hope that the sender
|
||||||
eh->h_proto = htons(ETH_P_IP);
|
will retry sending its packet. */
|
||||||
memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
|
memset(reh->h_dest, 0xff, ETH_ALEN);
|
||||||
slirp_output(buf, ip_data_len + ETH_HLEN);
|
memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
|
||||||
|
reh->h_source[5] = CTL_ALIAS;
|
||||||
|
reh->h_proto = htons(ETH_P_ARP);
|
||||||
|
rah->ar_hrd = htons(1);
|
||||||
|
rah->ar_pro = htons(ETH_P_IP);
|
||||||
|
rah->ar_hln = ETH_ALEN;
|
||||||
|
rah->ar_pln = 4;
|
||||||
|
rah->ar_op = htons(ARPOP_REQUEST);
|
||||||
|
/* source hw addr */
|
||||||
|
memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 1);
|
||||||
|
rah->ar_sha[5] = CTL_ALIAS;
|
||||||
|
/* source IP */
|
||||||
|
memcpy(rah->ar_sip, &alias_addr, 4);
|
||||||
|
/* target hw addr (none) */
|
||||||
|
memset(rah->ar_tha, 0, ETH_ALEN);
|
||||||
|
/* target IP */
|
||||||
|
memcpy(rah->ar_tip, &iph->ip_dst, 4);
|
||||||
|
client_ipaddr = iph->ip_dst;
|
||||||
|
slirp_output(arp_req, sizeof(arp_req));
|
||||||
|
} else {
|
||||||
|
memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
|
||||||
|
memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
|
||||||
|
/* XXX: not correct */
|
||||||
|
eh->h_source[5] = CTL_ALIAS;
|
||||||
|
eh->h_proto = htons(ETH_P_IP);
|
||||||
|
memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
|
||||||
|
slirp_output(buf, ip_data_len + ETH_HLEN);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int slirp_redir(int is_udp, int host_port,
|
int slirp_redir(int is_udp, int host_port,
|
||||||
|
Loading…
Reference in New Issue
Block a user