Revision 1a0ca1e1

b/Makefile.objs
151 151

  
152 152
slirp-obj-y = cksum.o if.o ip_icmp.o ip_input.o ip_output.o
153 153
slirp-obj-y += slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o
154
slirp-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o
154
slirp-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o arp_table.o
155 155
common-obj-$(CONFIG_SLIRP) += $(addprefix slirp/, $(slirp-obj-y))
156 156

  
157 157
# xen backend driver support
b/slirp/arp_table.c
1
/*
2
 * ARP table
3
 *
4
 * Copyright (c) 2011 AdaCore
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24

  
25
#include "slirp.h"
26

  
27
void arp_table_add(Slirp *slirp, int ip_addr, uint8_t ethaddr[ETH_ALEN])
28
{
29
    const in_addr_t broadcast_addr =
30
        ~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr;
31
    ArpTable *arptbl = &slirp->arp_table;
32
    int i;
33

  
34
    DEBUG_CALL("arp_table_add");
35
    DEBUG_ARG("ip = 0x%x", ip_addr);
36
    DEBUG_ARGS((dfd, " hw addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
37
                ethaddr[0], ethaddr[1], ethaddr[2],
38
                ethaddr[3], ethaddr[4], ethaddr[5]));
39

  
40
    /* Check 0.0.0.0/8 invalid source-only addresses */
41
    assert((ip_addr & htonl(~(0xf << 28))) != 0);
42

  
43
    if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
44
        /* Do not register broadcast addresses */
45
        return;
46
    }
47

  
48
    /* Search for an entry */
49
    for (i = 0; i < ARP_TABLE_SIZE; i++) {
50
        if (arptbl->table[i].ar_sip == ip_addr) {
51
            /* Update the entry */
52
            memcpy(arptbl->table[i].ar_sha, ethaddr, ETH_ALEN);
53
            return;
54
        }
55
    }
56

  
57
    /* No entry found, create a new one */
58
    arptbl->table[arptbl->next_victim].ar_sip = ip_addr;
59
    memcpy(arptbl->table[arptbl->next_victim].ar_sha,  ethaddr, ETH_ALEN);
60
    arptbl->next_victim = (arptbl->next_victim + 1) % ARP_TABLE_SIZE;
61
}
62

  
63
bool arp_table_search(Slirp *slirp, int in_ip_addr,
64
                      uint8_t out_ethaddr[ETH_ALEN])
65
{
66
    const in_addr_t broadcast_addr =
67
        ~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr;
68
    ArpTable *arptbl = &slirp->arp_table;
69
    int i;
70

  
71
    DEBUG_CALL("arp_table_search");
72
    DEBUG_ARG("ip = 0x%x", in_ip_addr);
73

  
74
    /* Check 0.0.0.0/8 invalid source-only addresses */
75
    assert((in_ip_addr & htonl(~(0xf << 28))) != 0);
76

  
77
    /* If broadcast address */
78
    if (in_ip_addr == 0xffffffff || in_ip_addr == broadcast_addr) {
79
        /* return Ethernet broadcast address */
80
        memset(out_ethaddr, 0xff, ETH_ALEN);
81
        return 1;
82
    }
83

  
84
    for (i = 0; i < ARP_TABLE_SIZE; i++) {
85
        if (arptbl->table[i].ar_sip == in_ip_addr) {
86
            memcpy(out_ethaddr, arptbl->table[i].ar_sha,  ETH_ALEN);
87
            DEBUG_ARGS((dfd, " found hw addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
88
                        out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
89
                        out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]));
90
            return 1;
91
        }
92
    }
93

  
94
    return 0;
95
}
b/slirp/bootp.c
149 149
    struct in_addr preq_addr;
150 150
    int dhcp_msg_type, val;
151 151
    uint8_t *q;
152
    uint8_t client_ethaddr[ETH_ALEN];
152 153

  
153 154
    /* extract exact DHCP msg type */
154 155
    dhcp_decode(bp, &dhcp_msg_type, &preq_addr);
......
164 165
    if (dhcp_msg_type != DHCPDISCOVER &&
165 166
        dhcp_msg_type != DHCPREQUEST)
166 167
        return;
167
    /* XXX: this is a hack to get the client mac address */
168
    memcpy(slirp->client_ethaddr, bp->bp_hwaddr, 6);
168

  
169
    /* Get client's hardware address from bootp request */
170
    memcpy(client_ethaddr, bp->bp_hwaddr, ETH_ALEN);
169 171

  
170 172
    m = m_get(slirp);
171 173
    if (!m) {
......
178 180

  
179 181
    if (dhcp_msg_type == DHCPDISCOVER) {
180 182
        if (preq_addr.s_addr != htonl(0L)) {
181
            bc = request_addr(slirp, &preq_addr, slirp->client_ethaddr);
183
            bc = request_addr(slirp, &preq_addr, client_ethaddr);
182 184
            if (bc) {
183 185
                daddr.sin_addr = preq_addr;
184 186
            }
185 187
        }
186 188
        if (!bc) {
187 189
         new_addr:
188
            bc = get_new_addr(slirp, &daddr.sin_addr, slirp->client_ethaddr);
190
            bc = get_new_addr(slirp, &daddr.sin_addr, client_ethaddr);
189 191
            if (!bc) {
190 192
                DPRINTF("no address left\n");
191 193
                return;
192 194
            }
193 195
        }
194
        memcpy(bc->macaddr, slirp->client_ethaddr, 6);
196
        memcpy(bc->macaddr, client_ethaddr, ETH_ALEN);
195 197
    } else if (preq_addr.s_addr != htonl(0L)) {
196
        bc = request_addr(slirp, &preq_addr, slirp->client_ethaddr);
198
        bc = request_addr(slirp, &preq_addr, client_ethaddr);
197 199
        if (bc) {
198 200
            daddr.sin_addr = preq_addr;
199
            memcpy(bc->macaddr, slirp->client_ethaddr, 6);
201
            memcpy(bc->macaddr, client_ethaddr, ETH_ALEN);
200 202
        } else {
201 203
            daddr.sin_addr.s_addr = 0;
202 204
        }
......
209 211
        }
210 212
    }
211 213

  
214
    /* Update ARP table for this IP address */
215
    arp_table_add(slirp, daddr.sin_addr.s_addr, client_ethaddr);
216

  
212 217
    saddr.sin_addr = slirp->vhost_addr;
213 218
    saddr.sin_port = htons(BOOTP_SERVER);
214 219

  
......
218 223
    rbp->bp_xid = bp->bp_xid;
219 224
    rbp->bp_htype = 1;
220 225
    rbp->bp_hlen = 6;
221
    memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6);
226
    memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, ETH_ALEN);
222 227

  
223 228
    rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
224 229
    rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
b/slirp/slirp.c
31 31
struct in_addr loopback_addr;
32 32

  
33 33
/* emulated hosts use the MAC addr 52:55:IP:IP:IP:IP */
34
static const uint8_t special_ethaddr[6] = {
34
static const uint8_t special_ethaddr[ETH_ALEN] = {
35 35
    0x52, 0x55, 0x00, 0x00, 0x00, 0x00
36 36
};
37 37

  
38
static const uint8_t zero_ethaddr[6] = { 0, 0, 0, 0, 0, 0 };
38
static const uint8_t zero_ethaddr[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
39 39

  
40 40
/* XXX: suppress those select globals */
41 41
fd_set *global_readfds, *global_writefds, *global_xfds;
......
599 599
	 global_xfds = NULL;
600 600
}
601 601

  
602
#define ETH_ALEN 6
603
#define ETH_HLEN 14
604

  
605
#define ETH_P_IP	0x0800		/* Internet Protocol packet	*/
606
#define ETH_P_ARP	0x0806		/* Address Resolution packet	*/
607

  
608
#define	ARPOP_REQUEST	1		/* ARP request			*/
609
#define	ARPOP_REPLY	2		/* ARP reply			*/
610

  
611
struct ethhdr
612
{
613
	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
614
	unsigned char	h_source[ETH_ALEN];	/* source ether addr	*/
615
	unsigned short	h_proto;		/* packet type ID field	*/
616
};
617

  
618
struct arphdr
619
{
620
	unsigned short	ar_hrd;		/* format of hardware address	*/
621
	unsigned short	ar_pro;		/* format of protocol address	*/
622
	unsigned char	ar_hln;		/* length of hardware address	*/
623
	unsigned char	ar_pln;		/* length of protocol address	*/
624
	unsigned short	ar_op;		/* ARP opcode (command)		*/
625

  
626
	 /*
627
	  *	 Ethernet looks like this : This bit is variable sized however...
628
	  */
629
	unsigned char		ar_sha[ETH_ALEN];	/* sender hardware address	*/
630
	uint32_t		ar_sip;			/* sender IP address		*/
631
	unsigned char		ar_tha[ETH_ALEN];	/* target hardware address	*/
632
	uint32_t		ar_tip	;		/* target IP address		*/
633
} __attribute__((packed));
634

  
635 602
static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
636 603
{
637
    struct ethhdr *eh = (struct ethhdr *)pkt;
638 604
    struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
639 605
    uint8_t arp_reply[max(ETH_HLEN + sizeof(struct arphdr), 64)];
640 606
    struct ethhdr *reh = (struct ethhdr *)arp_reply;
......
645 611
    ar_op = ntohs(ah->ar_op);
646 612
    switch(ar_op) {
647 613
    case ARPOP_REQUEST:
614
        if (ah->ar_tip == ah->ar_sip) {
615
            /* Gratuitous ARP */
616
            arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
617
            return;
618
        }
619

  
648 620
        if ((ah->ar_tip & slirp->vnetwork_mask.s_addr) ==
649 621
            slirp->vnetwork_addr.s_addr) {
650 622
            if (ah->ar_tip == slirp->vnameserver_addr.s_addr ||
......
657 629
            return;
658 630
        arp_ok:
659 631
            memset(arp_reply, 0, sizeof(arp_reply));
660
            /* XXX: make an ARP request to have the client address */
661
            memcpy(slirp->client_ethaddr, eh->h_source, ETH_ALEN);
632

  
633
            arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
662 634

  
663 635
            /* ARP request for alias/dns mac address */
664 636
            memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
......
679 651
        }
680 652
        break;
681 653
    case ARPOP_REPLY:
682
        /* reply to request of client mac address ? */
683
        if (!memcmp(slirp->client_ethaddr, zero_ethaddr, ETH_ALEN) &&
684
            ah->ar_sip == slirp->client_ipaddr.s_addr) {
685
            memcpy(slirp->client_ethaddr, ah->ar_sha, ETH_ALEN);
686
        }
654
        arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
687 655
        break;
688 656
    default:
689 657
        break;
......
729 697
{
730 698
    uint8_t buf[1600];
731 699
    struct ethhdr *eh = (struct ethhdr *)buf;
700
    uint8_t ethaddr[ETH_ALEN];
701
    const struct ip *iph = (const struct ip *)ip_data;
732 702

  
733 703
    if (ip_data_len + ETH_HLEN > sizeof(buf))
734 704
        return;
735
    
736
    if (!memcmp(slirp->client_ethaddr, zero_ethaddr, ETH_ALEN)) {
705

  
706
    if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
737 707
        uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
738 708
        struct ethhdr *reh = (struct ethhdr *)arp_req;
739 709
        struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);
740
        const struct ip *iph = (const struct ip *)ip_data;
741 710

  
742 711
        /* If the client addr is not known, there is no point in
743 712
           sending the packet to it. Normally the sender should have
......
765 734
        slirp->client_ipaddr = iph->ip_dst;
766 735
        slirp_output(slirp->opaque, arp_req, sizeof(arp_req));
767 736
    } else {
768
        memcpy(eh->h_dest, slirp->client_ethaddr, ETH_ALEN);
737
        memcpy(eh->h_dest, ethaddr, ETH_ALEN);
769 738
        memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
770 739
        /* XXX: not correct */
771 740
        memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
b/slirp/slirp.h
170 170
/* osdep.c */
171 171
int qemu_socket(int domain, int type, int protocol);
172 172

  
173
#define ETH_ALEN 6
174
#define ETH_HLEN 14
175

  
176
#define ETH_P_IP  0x0800        /* Internet Protocol packet  */
177
#define ETH_P_ARP 0x0806        /* Address Resolution packet */
178

  
179
#define ARPOP_REQUEST 1         /* ARP request */
180
#define ARPOP_REPLY   2         /* ARP reply   */
181

  
182
struct ethhdr {
183
    unsigned char  h_dest[ETH_ALEN];   /* destination eth addr */
184
    unsigned char  h_source[ETH_ALEN]; /* source ether addr    */
185
    unsigned short h_proto;            /* packet type ID field */
186
};
187

  
188
struct arphdr {
189
    unsigned short ar_hrd;      /* format of hardware address */
190
    unsigned short ar_pro;      /* format of protocol address */
191
    unsigned char  ar_hln;      /* length of hardware address */
192
    unsigned char  ar_pln;      /* length of protocol address */
193
    unsigned short ar_op;       /* ARP opcode (command)       */
194

  
195
    /*
196
     *  Ethernet looks like this : This bit is variable sized however...
197
     */
198
    unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
199
    uint32_t      ar_sip;           /* sender IP address       */
200
    unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
201
    uint32_t      ar_tip;           /* target IP address       */
202
} __attribute__((packed));
203

  
204
#define ARP_TABLE_SIZE 16
205

  
206
typedef struct ArpTable {
207
    struct arphdr table[ARP_TABLE_SIZE];
208
    int next_victim;
209
} ArpTable;
210

  
211
void arp_table_add(Slirp *slirp, int ip_addr, uint8_t ethaddr[ETH_ALEN]);
212

  
213
bool arp_table_search(Slirp *slirp, int in_ip_addr,
214
                      uint8_t out_ethaddr[ETH_ALEN]);
173 215

  
174 216
struct Slirp {
175 217
    QTAILQ_ENTRY(Slirp) entry;
......
181 223
    struct in_addr vdhcp_startaddr;
182 224
    struct in_addr vnameserver_addr;
183 225

  
184
    /* ARP cache for the guest IP addresses (XXX: allow many entries) */
185
    uint8_t client_ethaddr[6];
186

  
187 226
    struct in_addr client_ipaddr;
188 227
    char client_hostname[33];
189 228

  
......
227 266
    char *tftp_prefix;
228 267
    struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX];
229 268

  
269
    ArpTable arp_table;
270

  
230 271
    void *opaque;
231 272
};
232 273

  

Also available in: Unified diff