VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/bootp.c@ 1052

Last change on this file since 1052 was 1033, checked in by vboxsync, 18 years ago

Big change to make slirp fully instantiatable (replace all global
variables with local ones, passing a reference to the state/config
structure to all places which are interested). You can now have as many
cards in the guest configured for NAT networking as you want.

  • Property svn:eol-style set to native
File size: 9.8 KB
Line 
1/*
2 * QEMU BOOTP/DHCP server
3 *
4 * Copyright (c) 2004 Fabrice Bellard
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#include <slirp.h>
25
26/* XXX: only DHCP is supported */
27
28#ifndef VBOX
29#define NB_ADDR 16
30
31#define START_ADDR 15
32
33#define LEASE_TIME (24 * 3600)
34
35typedef struct {
36 uint8_t allocated;
37 uint8_t macaddr[6];
38} BOOTPClient;
39
40BOOTPClient bootp_clients[NB_ADDR];
41
42const char *bootp_filename;
43#endif /* !VBOX */
44
45static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
46
47#ifndef VBOX
48#ifdef DEBUG
49#define dprintf(fmt, args...) \
50if (slirp_debug & DBG_CALL) { fprintf(dfd, fmt, ## args); fflush(dfd); }
51#else
52#define dprintf(fmt, args...)
53#endif
54#else /* VBOX */
55DECLINLINE(void) dprintf(const char *pszFormat, ...)
56{
57#ifdef LOG_ENABLED
58 va_list args;
59 va_start(args, pszFormat);
60 Log(("dhcp: %N", pszFormat, &args));
61 va_end(args);
62#endif
63}
64#endif /* VBOX */
65
66#ifdef VBOX
67static BOOTPClient *get_new_addr(PNATState pData, struct in_addr *paddr)
68#else /* !VBOX */
69static BOOTPClient *get_new_addr(struct in_addr *paddr)
70#endif /* !VBOX */
71{
72 BOOTPClient *bc;
73 int i;
74
75 for(i = 0; i < NB_ADDR; i++) {
76 if (!bootp_clients[i].allocated)
77 goto found;
78 }
79 return NULL;
80 found:
81 bc = &bootp_clients[i];
82 bc->allocated = 1;
83 paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR));
84 return bc;
85}
86
87#ifdef VBOX
88static void release_addr(PNATState pData, struct in_addr *paddr)
89{
90 int i;
91
92 i = ntohl(paddr->s_addr) - START_ADDR - ntohl(special_addr.s_addr);
93 if (i >= NB_ADDR)
94 return;
95 memset(bootp_clients[i].macaddr, '\0', 6);
96 bootp_clients[i].allocated = 0;
97}
98#endif /* VBOX */
99
100#ifdef VBOX
101static BOOTPClient *find_addr(PNATState pData, struct in_addr *paddr, const uint8_t *macaddr)
102#else /* !VBOX */
103static BOOTPClient *find_addr(struct in_addr *paddr, const uint8_t *macaddr)
104#endif /* !VBOX */
105{
106 BOOTPClient *bc;
107 int i;
108
109 for(i = 0; i < NB_ADDR; i++) {
110 if (!memcmp(macaddr, bootp_clients[i].macaddr, 6))
111 goto found;
112 }
113 return NULL;
114 found:
115 bc = &bootp_clients[i];
116 bc->allocated = 1;
117 paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR));
118 return bc;
119}
120
121static void dhcp_decode(const uint8_t *buf, int size,
122 int *pmsg_type)
123{
124 const uint8_t *p, *p_end;
125 int len, tag;
126
127 *pmsg_type = 0;
128
129 p = buf;
130 p_end = buf + size;
131 if (size < 5)
132 return;
133 if (memcmp(p, rfc1533_cookie, 4) != 0)
134 return;
135 p += 4;
136 while (p < p_end) {
137 tag = p[0];
138 if (tag == RFC1533_PAD) {
139 p++;
140 } else if (tag == RFC1533_END) {
141 break;
142 } else {
143 p++;
144 if (p >= p_end)
145 break;
146 len = *p++;
147 dprintf("dhcp: tag=0x%02x len=%d\n", tag, len);
148
149 switch(tag) {
150 case RFC2132_MSG_TYPE:
151 if (len >= 1)
152 *pmsg_type = p[0];
153 break;
154 default:
155 break;
156 }
157 p += len;
158 }
159 }
160}
161
162#ifdef VBOX
163static void bootp_reply(PNATState pData, struct bootp_t *bp)
164#else /* !VBOX */
165static void bootp_reply(struct bootp_t *bp)
166#endif /* !VBOX */
167{
168 BOOTPClient *bc;
169 struct mbuf *m;
170 struct bootp_t *rbp;
171 struct sockaddr_in saddr, daddr;
172#ifdef VBOX
173 struct in_addr dns_addr_dhcp;
174#else /* !VBOX */
175 struct in_addr dns_addr;
176#endif /* !VBOX */
177 int dhcp_msg_type, val;
178 uint8_t *q;
179
180 /* extract exact DHCP msg type */
181 dhcp_decode(bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type);
182 dprintf("bootp packet op=%d msgtype=%d\n", bp->bp_op, dhcp_msg_type);
183
184 if (dhcp_msg_type == 0)
185 dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */
186
187#ifdef VBOX
188 if (dhcp_msg_type == DHCPRELEASE) {
189 uint32_t addr = ntohl(bp->bp_ciaddr.s_addr);
190 release_addr(pData, &bp->bp_ciaddr);
191 LogRel(("NAT: DHCP released IP address %u.%u.%u.%u\n",
192 addr >> 24, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff));
193 dprintf("released addr=%08x\n", ntohl(bp->bp_ciaddr.s_addr));
194 /* This message is not to be answered in any way. */
195 return;
196 }
197#endif /* VBOX */
198 if (dhcp_msg_type != DHCPDISCOVER &&
199 dhcp_msg_type != DHCPREQUEST)
200 return;
201 /* XXX: this is a hack to get the client mac address */
202 memcpy(client_ethaddr, bp->bp_hwaddr, 6);
203
204#ifdef VBOX
205 if ((m = m_get(pData)) == NULL)
206#else /* !VBOX */
207 if ((m = m_get()) == NULL)
208#endif /* !VBOX */
209 return;
210 m->m_data += if_maxlinkhdr;
211 rbp = (struct bootp_t *)m->m_data;
212 m->m_data += sizeof(struct udpiphdr);
213 memset(rbp, 0, sizeof(struct bootp_t));
214
215 if (dhcp_msg_type == DHCPDISCOVER) {
216#ifdef VBOX
217 /* Do not allocate a new lease for clients that forgot that they had a lease. */
218 bc = find_addr(pData, &daddr.sin_addr, bp->bp_hwaddr);
219 if (bc)
220 goto reuse_lease;
221#endif /* VBOX */
222 new_addr:
223#ifdef VBOX
224 bc = get_new_addr(pData, &daddr.sin_addr);
225#else /* !VBOX */
226 bc = get_new_addr(&daddr.sin_addr);
227#endif /* !VBOX */
228 if (!bc) {
229#ifdef VBOX
230 LogRel(("NAT: DHCP no IP address left\n"));
231#endif /* VBOX */
232 dprintf("no address left\n");
233 return;
234 }
235 memcpy(bc->macaddr, client_ethaddr, 6);
236#ifdef VBOX
237 reuse_lease: ;
238#endif /* VBOX */
239 } else {
240#ifdef VBOX
241 bc = find_addr(pData, &daddr.sin_addr, bp->bp_hwaddr);
242#else /* !VBOX */
243 bc = find_addr(&daddr.sin_addr, bp->bp_hwaddr);
244#endif /* !VBOX */
245 if (!bc) {
246 /* if never assigned, behaves as if it was already
247 assigned (windows fix because it remembers its address) */
248 goto new_addr;
249 }
250 }
251
252 if (bootp_filename)
253#ifndef VBOX
254 snprintf((char*)rbp->bp_file, sizeof(rbp->bp_file), "%s", bootp_filename);
255#else
256 RTStrPrintf((char*)rbp->bp_file, sizeof(rbp->bp_file), "%s", bootp_filename);
257#endif
258
259#ifdef VBOX
260 {
261 uint32_t addr = ntohl(daddr.sin_addr.s_addr);
262 LogRel(("NAT: DHCP offered IP address %u.%u.%u.%u\n",
263 addr >> 24, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff));
264 }
265#endif /* VBOX */
266 dprintf("offered addr=%08x\n", ntohl(daddr.sin_addr.s_addr));
267
268 saddr.sin_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
269 saddr.sin_port = htons(BOOTP_SERVER);
270
271 daddr.sin_port = htons(BOOTP_CLIENT);
272
273 rbp->bp_op = BOOTP_REPLY;
274 rbp->bp_xid = bp->bp_xid;
275 rbp->bp_htype = 1;
276 rbp->bp_hlen = 6;
277 memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6);
278
279 rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
280 rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
281
282 q = rbp->bp_vend;
283 memcpy(q, rfc1533_cookie, 4);
284 q += 4;
285
286 if (dhcp_msg_type == DHCPDISCOVER) {
287 *q++ = RFC2132_MSG_TYPE;
288 *q++ = 1;
289 *q++ = DHCPOFFER;
290 } else if (dhcp_msg_type == DHCPREQUEST) {
291 *q++ = RFC2132_MSG_TYPE;
292 *q++ = 1;
293 *q++ = DHCPACK;
294 }
295
296 if (dhcp_msg_type == DHCPDISCOVER ||
297 dhcp_msg_type == DHCPREQUEST) {
298 *q++ = RFC2132_SRV_ID;
299 *q++ = 4;
300 memcpy(q, &saddr.sin_addr, 4);
301 q += 4;
302
303 *q++ = RFC1533_NETMASK;
304 *q++ = 4;
305 *q++ = 0xff;
306 *q++ = 0xff;
307 *q++ = 0xff;
308 *q++ = 0x00;
309
310 *q++ = RFC1533_GATEWAY;
311 *q++ = 4;
312 memcpy(q, &saddr.sin_addr, 4);
313 q += 4;
314
315 *q++ = RFC1533_DNS;
316 *q++ = 4;
317#ifdef VBOX
318 dns_addr_dhcp.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS);
319 memcpy(q, &dns_addr_dhcp, 4);
320#else /* !VBOX */
321 dns_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS);
322 memcpy(q, &dns_addr, 4);
323#endif /* !VBOX */
324 q += 4;
325
326 *q++ = RFC2132_LEASE_TIME;
327 *q++ = 4;
328 val = htonl(LEASE_TIME);
329 memcpy(q, &val, 4);
330 q += 4;
331
332 if (*slirp_hostname) {
333 val = strlen(slirp_hostname);
334 *q++ = RFC1533_HOSTNAME;
335 *q++ = val;
336 memcpy(q, slirp_hostname, val);
337 q += val;
338 }
339 }
340 *q++ = RFC1533_END;
341
342 m->m_len = sizeof(struct bootp_t) -
343 sizeof(struct ip) - sizeof(struct udphdr);
344#ifdef VBOX
345 /* Reply to the broadcast address, as some clients perform paranoid checks. */
346 daddr.sin_addr.s_addr = INADDR_BROADCAST;
347 udp_output2(pData, NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
348#else /* !VBOX */
349 udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
350#endif /* !VBOX */
351}
352
353#ifdef VBOX
354void bootp_input(PNATState pData, struct mbuf *m)
355#else /* !VBOX */
356void bootp_input(struct mbuf *m)
357#endif /* !VBOX */
358{
359 struct bootp_t *bp = mtod(m, struct bootp_t *);
360
361 if (bp->bp_op == BOOTP_REQUEST) {
362#ifdef VBOX
363 bootp_reply(pData, bp);
364#else /* !VBOX */
365 bootp_reply(bp);
366#endif /* !VBOX */
367 }
368}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette