Commit de806f0786ced5bc0ef67731ddece4636194406b
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, | ... | ... |