Commit de806f0786ced5bc0ef67731ddece4636194406b

Authored by bellard
1 parent 89c0f643

allow SLIRP to make an ARP request to get the client MAC address. It is useful i…

…f 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
Showing 1 changed file with 52 additions and 8 deletions
slirp/slirp.c
... ... @@ -16,7 +16,11 @@ static const uint8_t special_ethaddr[6] = {
16 16 0x52, 0x54, 0x00, 0x12, 0x35, 0x00
17 17 };
18 18  
  19 +/* ARP cache for the guest IP addresses (XXX: allow many entries) */
19 20 uint8_t client_ethaddr[6];
  21 +static struct in_addr client_ipaddr;
  22 +
  23 +static const uint8_t zero_ethaddr[6] = { 0, 0, 0, 0, 0, 0 };
20 24  
21 25 int do_slowtimo;
22 26 int link_up;
... ... @@ -597,6 +601,13 @@ static void arp_input(const uint8_t *pkt, int pkt_len)
597 601 slirp_output(arp_reply, sizeof(arp_reply));
598 602 }
599 603 break;
  604 + case ARPOP_REPLY:
  605 + /* reply to request of client mac address ? */
  606 + if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN) &&
  607 + !memcmp(ah->ar_sip, &client_ipaddr.s_addr, 4)) {
  608 + memcpy(client_ethaddr, ah->ar_sha, ETH_ALEN);
  609 + }
  610 + break;
600 611 default:
601 612 break;
602 613 }
... ... @@ -641,14 +652,47 @@ void if_encap(const uint8_t *ip_data, int ip_data_len)
641 652  
642 653 if (ip_data_len + ETH_HLEN > sizeof(buf))
643 654 return;
644   -
645   - memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
646   - memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
647   - /* XXX: not correct */
648   - eh->h_source[5] = CTL_ALIAS;
649   - eh->h_proto = htons(ETH_P_IP);
650   - memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
651   - slirp_output(buf, ip_data_len + ETH_HLEN);
  655 +
  656 + if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN)) {
  657 + uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
  658 + struct ethhdr *reh = (struct ethhdr *)arp_req;
  659 + struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);
  660 + const struct ip *iph = (const struct ip *)ip_data;
  661 +
  662 + /* If the client addr is not known, there is no point in
  663 + sending the packet to it. Normally the sender should have
  664 + done an ARP request to get its MAC address. Here we do it
  665 + in place of sending the packet and we hope that the sender
  666 + will retry sending its packet. */
  667 + memset(reh->h_dest, 0xff, ETH_ALEN);
  668 + memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
  669 + reh->h_source[5] = CTL_ALIAS;
  670 + reh->h_proto = htons(ETH_P_ARP);
  671 + rah->ar_hrd = htons(1);
  672 + rah->ar_pro = htons(ETH_P_IP);
  673 + rah->ar_hln = ETH_ALEN;
  674 + rah->ar_pln = 4;
  675 + rah->ar_op = htons(ARPOP_REQUEST);
  676 + /* source hw addr */
  677 + memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 1);
  678 + rah->ar_sha[5] = CTL_ALIAS;
  679 + /* source IP */
  680 + memcpy(rah->ar_sip, &alias_addr, 4);
  681 + /* target hw addr (none) */
  682 + memset(rah->ar_tha, 0, ETH_ALEN);
  683 + /* target IP */
  684 + memcpy(rah->ar_tip, &iph->ip_dst, 4);
  685 + client_ipaddr = iph->ip_dst;
  686 + slirp_output(arp_req, sizeof(arp_req));
  687 + } else {
  688 + memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
  689 + memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
  690 + /* XXX: not correct */
  691 + eh->h_source[5] = CTL_ALIAS;
  692 + eh->h_proto = htons(ETH_P_IP);
  693 + memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
  694 + slirp_output(buf, ip_data_len + ETH_HLEN);
  695 + }
652 696 }
653 697  
654 698 int slirp_redir(int is_udp, int host_port,
... ...