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