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