VirtualBox

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

Last change on this file since 22315 was 22225, checked in by vboxsync, 16 years ago

NAT: typo

  • Property svn:eol-style set to native
File size: 23.7 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
28static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
29static void bootp_reply(PNATState pData, struct mbuf *m0, int off, uint16_t flags);
30
31static uint8_t *dhcp_find_option(uint8_t *vend, uint8_t tag)
32{
33 uint8_t *q = vend;
34 uint8_t len;
35 /*@todo magic validation */
36 q += 4; /*magic*/
37 while(*q != RFC1533_END)
38 {
39 if (*q == RFC1533_PAD)
40 continue;
41 if (*q == tag)
42 return q;
43 q++;
44 len = *q;
45 q += 1 + len;
46 }
47 return NULL;
48}
49static BOOTPClient *alloc_addr(PNATState pData)
50{
51 int i;
52 for (i = 0; i < NB_ADDR; i++)
53 {
54 if (!bootp_clients[i].allocated)
55 {
56 BOOTPClient *bc;
57
58 bc = &bootp_clients[i];
59 memset(bc, 0, sizeof(BOOTPClient));
60 bc->allocated = 1;
61 bc->number = i;
62 return bc;
63 }
64 }
65 return NULL;
66}
67static BOOTPClient *get_new_addr(PNATState pData, struct in_addr *paddr)
68{
69 BOOTPClient *bc;
70 bc = alloc_addr(pData);
71 if (bc == NULL)
72 return NULL;
73 paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (bc->number + START_ADDR));
74 bc->addr.s_addr = paddr->s_addr;
75 return bc;
76 return NULL;
77}
78
79static int release_addr(PNATState pData, struct in_addr *paddr)
80{
81 unsigned i;
82 for (i = 0; i < NB_ADDR; i++)
83 {
84 if (paddr->s_addr == bootp_clients[i].addr.s_addr)
85 {
86 memset(&bootp_clients[i], 0, sizeof(BOOTPClient));
87 return 1;
88 }
89 }
90 return 0;
91}
92
93/*
94 * from RFC 2131 4.3.1
95 * Field DHCPOFFER DHCPACK DHCPNAK
96 * ----- --------- ------- -------
97 * 'op' BOOTREPLY BOOTREPLY BOOTREPLY
98 * 'htype' (From "Assigned Numbers" RFC)
99 * 'hlen' (Hardware address length in octets)
100 * 'hops' 0 0 0
101 * 'xid' 'xid' from client 'xid' from client 'xid' from client
102 * DHCPDISCOVER DHCPREQUEST DHCPREQUEST
103 * message message message
104 * 'secs' 0 0 0
105 * 'ciaddr' 0 'ciaddr' from 0
106 * DHCPREQUEST or 0
107 * 'yiaddr' IP address offered IP address 0
108 * to client assigned to client
109 * 'siaddr' IP address of next IP address of next 0
110 * bootstrap server bootstrap server
111 * 'flags' 'flags' from 'flags' from 'flags' from
112 * client DHCPDISCOVER client DHCPREQUEST client DHCPREQUEST
113 * message message message
114 * 'giaddr' 'giaddr' from 'giaddr' from 'giaddr' from
115 * client DHCPDISCOVER client DHCPREQUEST client DHCPREQUEST
116 * message message message
117 * 'chaddr' 'chaddr' from 'chaddr' from 'chaddr' from
118 * client DHCPDISCOVER client DHCPREQUEST client DHCPREQUEST
119 * message message message
120 * 'sname' Server host name Server host name (unused)
121 * or options or options
122 * 'file' Client boot file Client boot file (unused)
123 * name or options name or options
124 * 'options' options options
125 *
126 * Option DHCPOFFER DHCPACK DHCPNAK
127 * ------ --------- ------- -------
128 * Requested IP address MUST NOT MUST NOT MUST NOT
129 * IP address lease time MUST MUST (DHCPREQUEST) MUST NOT
130 * MUST NOT (DHCPINFORM)
131 * Use 'file'/'sname' fields MAY MAY MUST NOT
132 * DHCP message type DHCPOFFER DHCPACK DHCPNAK
133 * Parameter request list MUST NOT MUST NOT MUST NOT
134 * Message SHOULD SHOULD SHOULD
135 * Client identifier MUST NOT MUST NOT MAY
136 * Vendor class identifier MAY MAY MAY
137 * Server identifier MUST MUST MUST
138 * Maximum message size MUST NOT MUST NOT MUST NOT
139 * All others MAY MAY MUST NOT
140 */
141static BOOTPClient *find_addr(PNATState pData, struct in_addr *paddr, const uint8_t *macaddr)
142{
143 int i;
144
145 for (i = 0; i < NB_ADDR; i++)
146 {
147 if (!memcmp(macaddr, bootp_clients[i].macaddr, 6))
148 {
149 BOOTPClient *bc;
150
151 bc = &bootp_clients[i];
152 bc->allocated = 1;
153 paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR));
154 return bc;
155 }
156 }
157 return NULL;
158}
159
160static struct mbuf *dhcp_create_msg(PNATState pData, struct bootp_t *bp, struct mbuf *m, uint8_t type)
161{
162 struct bootp_t *rbp;
163 struct ethhdr *eh;
164 uint8_t *q;
165
166 rbp = mtod(m, struct bootp_t *);
167 memset(rbp, 0, sizeof(struct bootp_t));
168 eh = mtod(m, struct ethhdr *);
169 memcpy(eh->h_source, bp->bp_hwaddr, ETH_ALEN); /* XXX: if_encap just swap source with dest*/
170 m->m_data += if_maxlinkhdr; /*reserve ether header */
171 rbp = mtod(m, struct bootp_t *);
172 rbp->bp_op = BOOTP_REPLY;
173 rbp->bp_xid = bp->bp_xid; /* see table 3 of rfc2131*/
174 rbp->bp_flags = bp->bp_flags;
175 rbp->bp_giaddr.s_addr = bp->bp_giaddr.s_addr;
176#if 0 /*check flags*/
177 saddr.sin_port = htons(BOOTP_SERVER);
178 daddr.sin_port = htons(BOOTP_CLIENT);
179#endif
180 rbp->bp_htype = 1;
181 rbp->bp_hlen = 6;
182 memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6);
183
184 memcpy(rbp->bp_vend, rfc1533_cookie, 4); /* cookie */
185 q = rbp->bp_vend;
186 q += 4;
187 *q++ = RFC2132_MSG_TYPE;
188 *q++ = 1;
189 *q++ = type;
190
191 return m;
192}
193
194static int dhcp_do_ack_offer(PNATState pData, struct mbuf *m, BOOTPClient *bc, int is_from_request)
195{
196 int off = 0;
197 struct bootp_t *rbp = NULL;
198 uint8_t *q;
199 struct in_addr saddr;
200 int val;
201
202 struct dns_entry *de = NULL;
203 struct dns_domain_entry *dd = NULL;
204 int added = 0;
205 uint8_t *q_dns_header = NULL;
206 uint32_t lease_time = htonl(LEASE_TIME);
207 uint32_t netmask = htonl(pData->netmask);
208
209 rbp = mtod(m, struct bootp_t *);
210 q = &rbp->bp_vend[0];
211 q += 7; /* !cookie rfc 2132 + TYPE*/
212
213 /*DHCP Offer specific*/
214 if ( tftp_prefix
215 && RTDirExists(tftp_prefix)
216 && bootp_filename)
217 RTStrPrintf((char*)rbp->bp_file, sizeof(rbp->bp_file), "%s", bootp_filename);
218
219 Log(("NAT: DHCP: bp_file:%s\n", &rbp->bp_file));
220 /* Address/port of the DHCP server. */
221 rbp->bp_yiaddr = bc->addr; /* Client IP address */
222 Log(("NAT: DHCP: bp_yiaddr:%R[IP4]\n", &rbp->bp_yiaddr));
223 rbp->bp_siaddr = pData->tftp_server; /* Next Server IP address, i.e. TFTP */
224 Log(("NAT: DHCP: bp_siaddr:%R[IP4]\n", &rbp->bp_siaddr));
225 if (is_from_request)
226 {
227 rbp->bp_ciaddr.s_addr = bc->addr.s_addr; /* Client IP address */
228 }
229#ifndef VBOX_WITH_NAT_SERVICE
230 saddr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
231#else
232 saddr.s_addr = special_addr.s_addr;
233#endif
234 Log(("NAT: DHCP: s_addr:%R[IP4]\n", &saddr));
235
236#define FILL_BOOTP_EXT(q, tag, len, pvalue) \
237 do { \
238 struct bootp_ext *be = (struct bootp_ext *)(q); \
239 be->bpe_tag = (tag); \
240 be->bpe_len = (len); \
241 memcpy(&be[1], (pvalue), (len)); \
242 (q) = (uint8_t *)(&be[1]) + (len); \
243 }while(0)
244/* appending another value to tag, calculates len of whole block*/
245#define FILL_BOOTP_APP(head, q, tag, len, pvalue) \
246 do { \
247 struct bootp_ext *be = (struct bootp_ext *)(head); \
248 memcpy(q, (pvalue), (len)); \
249 (q) += (len); \
250 Assert(be->bpe_tag == (tag)); \
251 be->bpe_len += (len); \
252 }while(0)
253
254
255
256 FILL_BOOTP_EXT(q, RFC1533_NETMASK, 4, &netmask);
257 FILL_BOOTP_EXT(q, RFC1533_GATEWAY, 4, &saddr);
258
259 if (pData->use_dns_proxy)
260 {
261 uint32_t addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS);
262 FILL_BOOTP_EXT(q, RFC1533_DNS, 4, &addr);
263 goto skip_dns_servers;
264 }
265
266 if (!TAILQ_EMPTY(&pData->dns_list_head))
267 {
268 de = TAILQ_LAST(&pData->dns_list_head, dns_list_head);
269 q_dns_header = q;
270 FILL_BOOTP_EXT(q, RFC1533_DNS, 4, &de->de_addr.s_addr);
271 }
272
273 TAILQ_FOREACH_REVERSE(de, &pData->dns_list_head, dns_list_head, de_list)
274 {
275 if (TAILQ_LAST(&pData->dns_list_head, dns_list_head) == de)
276 continue; /* first value with head we've ingected before */
277 FILL_BOOTP_APP(q_dns_header, q, RFC1533_DNS, 4, &de->de_addr.s_addr);
278 }
279
280skip_dns_servers:
281 if (LIST_EMPTY(&pData->dns_domain_list_head))
282 {
283 /* Microsoft dhcp client doen't like domain-less dhcp and trimmed packets*/
284 /* dhcpcd client very sad if no domain name is passed */
285 FILL_BOOTP_EXT(q, RFC1533_DOMAINNAME, 1, " ");
286 }
287 if (pData->fPassDomain)
288 {
289 LIST_FOREACH(dd, &pData->dns_domain_list_head, dd_list)
290 {
291
292 if (dd->dd_pszDomain == NULL)
293 continue;
294 /* never meet valid separator here in RFC1533*/
295 if (added != 0)
296 FILL_BOOTP_EXT(q, RFC1533_DOMAINNAME, 1, ",");
297 else
298 added = 1;
299 val = (int)strlen(dd->dd_pszDomain);
300 FILL_BOOTP_EXT(q, RFC1533_DOMAINNAME, val, dd->dd_pszDomain);
301 }
302 }
303
304 FILL_BOOTP_EXT(q, RFC2132_LEASE_TIME, 4, &lease_time);
305
306 if (*slirp_hostname)
307 {
308 val = (int)strlen(slirp_hostname);
309 FILL_BOOTP_EXT(q, RFC1533_HOSTNAME, val, slirp_hostname);
310 }
311 return q - rbp->bp_vend; /*return offset */
312}
313
314static int dhcp_send_nack(PNATState pData, struct bootp_t *bp, BOOTPClient *bc, struct mbuf *m)
315{
316 struct bootp_t *rbp;
317 uint8_t *q = NULL;
318 rbp = mtod(m, struct bootp_t *);
319
320 dhcp_create_msg(pData, bp, m, DHCPNAK);
321
322 return 7;
323}
324static int dhcp_send_ack(PNATState pData, struct bootp_t *bp, BOOTPClient *bc, struct mbuf *m, int is_from_request)
325{
326 struct bootp_t *rbp;
327 int off = 0; /* boot_reply will fill general options and add END before sending response*/
328
329 dhcp_create_msg(pData, bp, m, DHCPACK);
330 off = dhcp_do_ack_offer(pData, m, bc, is_from_request);
331 return off;
332}
333static int dhcp_send_offer(PNATState pData, struct bootp_t *bp, BOOTPClient *bc, struct mbuf *m)
334{
335 int off = 0; /* boot_reply will fill general options and add END before sending response*/
336
337 dhcp_create_msg(pData, bp, m, DHCPOFFER);
338 off = dhcp_do_ack_offer(pData, m, bc, 0);
339 return off;
340}
341
342/**
343 * decoding client messages RFC2131 (4.3.6)
344 * ---------------------------------------------------------------------
345 * | |INIT-REBOOT |SELECTING |RENEWING |REBINDING |
346 * ---------------------------------------------------------------------
347 * |broad/unicast |broadcast |broadcast |unicast |broadcast |
348 * |server-ip |MUST NOT |MUST |MUST NOT |MUST NOT |
349 * |requested-ip |MUST |MUST |MUST NOT |MUST NOT |
350 * |ciaddr |zero |zero |IP address |IP address|
351 * ---------------------------------------------------------------------
352 *
353 */
354enum DHCP_REQUEST_STATES{INIT_REBOOT, SELECTING, RENEWING, REBINDING, NONE};
355static int dhcp_decode_request(PNATState pData, struct bootp_t *bp, const uint8_t *buf, int size, struct mbuf *m)
356{
357 BOOTPClient *bc = NULL;
358 struct in_addr daddr;
359 int off;
360 uint8_t *opt;
361 uint8_t *req_ip = NULL;
362 uint8_t *server_ip = NULL;
363 uint32_t ui32;
364 enum DHCP_REQUEST_STATES dhcp_stat = NONE;
365 /*need to understand which type of request we get */
366 req_ip = dhcp_find_option(&bp->bp_vend[0], RFC2132_REQ_ADDR);
367 server_ip = dhcp_find_option(&bp->bp_vend[0], RFC2132_SRV_ID);
368 bc = find_addr(pData, &daddr, bp->bp_hwaddr);
369
370 if (server_ip != NULL)
371 {
372 /*selecting*/
373 if (!bc)
374 {
375 LogRel(("NAT: DHCP no IP wasn't allocated\n"));
376 return -1;
377 }
378 dhcp_stat = SELECTING;
379 Assert((bp->bp_ciaddr.s_addr == INADDR_ANY));
380 Assert((*(uint32_t *)(req_ip + 2) == bc->addr.s_addr)); /*the same address as in offer*/
381#if 0
382 /* DSL xid in request differ from offer */
383 Assert((bp->bp_xid == bc->xid));
384#endif
385 }
386 else
387 {
388 if (req_ip != NULL)
389 {
390 /* init-reboot */
391 dhcp_stat = INIT_REBOOT;
392 }
393 else
394 {
395 /*see table 4 rfc2131*/
396 if (bp->bp_flags & DHCP_FLAGS_B)
397 dhcp_stat = REBINDING;
398 else
399 dhcp_stat = RENEWING;
400 }
401 }
402 /*?? renewing ??*/
403 switch (dhcp_stat)
404 {
405 case RENEWING:
406 {
407 Assert(( server_ip == NULL
408 && req_ip == NULL
409 && bp->bp_ciaddr.s_addr != INADDR_ANY));
410 if (bc != NULL)
411 {
412 Assert((bc->addr.s_addr == bp->bp_ciaddr.s_addr));
413 /*if it already here well just do ack, we aren't aware of dhcp time expiration*/
414 }
415 else
416 {
417 if ((bp->bp_ciaddr.s_addr & htonl(pData->netmask)) != special_addr.s_addr)
418 {
419 off = dhcp_send_nack(pData, bp, bc, m);
420 return off;
421 }
422 bc = alloc_addr(pData);
423 if (bc == NULL)
424 {
425 LogRel(("NAT: can't alloc address. RENEW has been silently ignored\n"));
426 return -1;
427 }
428 Assert((bp->bp_hlen == ETH_ALEN));
429 memcpy(bc->macaddr, bp->bp_hwaddr, bp->bp_hlen);
430 bc->addr.s_addr = bp->bp_ciaddr.s_addr;
431 }
432 }
433 break;
434 case INIT_REBOOT:
435 Assert(server_ip == NULL);
436 Assert(req_ip != NULL);
437 ui32 = *(uint32_t *)(req_ip + 2);
438 if ((ui32 & htonl(pData->netmask)) != special_addr.s_addr)
439 {
440 LogRel(("NAT: address %R[IP4] has been req.\n", &ui32));
441 off = dhcp_send_nack(pData, bp, bc, m);
442 return off;
443 }
444 bc = alloc_addr(pData);
445 if (bc == NULL)
446 {
447 LogRel(("NAT: can't alloc address. RENEW has been silently ignored\n"));
448 return -1;
449 }
450 Assert((bp->bp_hlen == ETH_ALEN));
451 memcpy(bc->macaddr, bp->bp_hwaddr, bp->bp_hlen);
452 bc->addr.s_addr = ui32;
453 break;
454 case NONE:
455 Assert((dhcp_stat != NONE));
456 return -1;
457 default:
458 break;
459 }
460 off = dhcp_send_ack(pData, bp, bc, m, 1);
461 return off;
462}
463
464static int dhcp_decode_discover(PNATState pData, struct bootp_t *bp, const uint8_t *buf, int size, int flag, struct mbuf *m)
465{
466 BOOTPClient *bc;
467 struct in_addr daddr;
468 int off;
469 /* flag == 1 discover */
470 if (flag == 1)
471 {
472 bc = find_addr(pData, &daddr, bp->bp_hwaddr);
473 if (!bc)
474 {
475 bc = get_new_addr(pData, &daddr);
476 if (!bc)
477 {
478 LogRel(("NAT: DHCP no IP address left\n"));
479 Log(("no address left\n"));
480 return -1;
481 }
482 memcpy(bc->macaddr, bp->bp_hwaddr, 6);
483 }
484 bc->xid = bp->bp_xid;
485 /*bc isn't NULL */
486 off = dhcp_send_offer(pData, bp, bc, m);
487 return off;
488 }
489 else
490 {
491 /* flag == 0 inform */
492 bc = find_addr(pData, &daddr, bp->bp_hwaddr);
493 if (bc == NULL)
494 {
495 LogRel(("NAT: DHCP Inform was ignored no boot client was found\n"));
496 return -1;
497 }
498 off = dhcp_send_ack(pData, bp, bc, m, 0);
499 return off;
500 }
501 return -1;
502}
503
504static int dhcp_decode_release(PNATState pData, struct bootp_t *bp, const uint8_t *buf, int size, int flag)
505{
506 return -1;
507}
508/**
509 * fields for discovering t
510 * Field DHCPDISCOVER DHCPREQUEST DHCPDECLINE,
511 * DHCPINFORM DHCPRELEASE
512 * ----- ------------ ----------- -----------
513 * 'op' BOOTREQUEST BOOTREQUEST BOOTREQUEST
514 * 'htype' (From "Assigned Numbers" RFC)
515 * 'hlen' (Hardware address length in octets)
516 * 'hops' 0 0 0
517 * 'xid' selected by client 'xid' from server selected by
518 * DHCPOFFER message client
519 * 'secs' 0 or seconds since 0 or seconds since 0
520 * DHCP process started DHCP process started
521 * 'flags' Set 'BROADCAST' Set 'BROADCAST' 0
522 * flag if client flag if client
523 * requires broadcast requires broadcast
524 * reply reply
525 * 'ciaddr' 0 (DHCPDISCOVER) 0 or client's 0 (DHCPDECLINE)
526 * client's network address client's network
527 * network address (BOUND/RENEW/REBIND) address
528 * (DHCPINFORM) (DHCPRELEASE)
529 * 'yiaddr' 0 0 0
530 * 'siaddr' 0 0 0
531 * 'giaddr' 0 0 0
532 * 'chaddr' client's hardware client's hardware client's hardware
533 * address address address
534 * 'sname' options, if options, if (unused)
535 * indicated in indicated in
536 * 'sname/file' 'sname/file'
537 * option; otherwise option; otherwise
538 * unused unused
539 * 'file' options, if options, if (unused)
540 * indicated in indicated in
541 * 'sname/file' 'sname/file'
542 * option; otherwise option; otherwise
543 * unused unused
544 * 'options' options options (unused)
545 * Requested IP address MAY MUST (in MUST
546 * (DISCOVER) SELECTING or (DHCPDECLINE),
547 * MUST NOT INIT-REBOOT) MUST NOT
548 * (INFORM) MUST NOT (in (DHCPRELEASE)
549 * BOUND or
550 * RENEWING)
551 * IP address lease time MAY MAY MUST NOT
552 * (DISCOVER)
553 * MUST NOT
554 * (INFORM)
555 * Use 'file'/'sname' fields MAY MAY MAY
556 * DHCP message type DHCPDISCOVER/ DHCPREQUEST DHCPDECLINE/
557 * DHCPINFORM DHCPRELEASE
558 * Client identifier MAY MAY MAY
559 * Vendor class identifier MAY MAY MUST NOT
560 * Server identifier MUST NOT MUST (after MUST
561 * SELECTING)
562 * MUST NOT (after
563 * INIT-REBOOT,
564 * BOUND, RENEWING
565 * or REBINDING)
566 * Parameter request list MAY MAY MUST NOT
567 * Maximum message size MAY MAY MUST NOT
568 * Message SHOULD NOT SHOULD NOT SHOULD
569 * Site-specific MAY MAY MUST NOT
570 * All others MAY MAY MUST NOT
571 *
572 */
573static void dhcp_decode(PNATState pData, struct bootp_t *bp, const uint8_t *buf, int size)
574{
575 const uint8_t *p, *p_end;
576 int rc;
577 int pmsg_type;
578 struct in_addr req_ip;
579 int flag = 0;
580 int len, tag;
581 struct mbuf *m = NULL;
582
583 pmsg_type = 0;
584
585 p = buf;
586 p_end = buf + size;
587 if (size < 5)
588 return;
589 if (memcmp(p, rfc1533_cookie, 4) != 0)
590 return;
591 p = dhcp_find_option(bp->bp_vend, RFC2132_MSG_TYPE);
592 Assert(p);
593 if (p == NULL)
594 return;
595 if ((m = m_get(pData)) == NULL)
596 {
597 LogRel(("NAT: can't alocate memory for response!\n"));
598 return;
599 }
600 switch(*(p+2))
601 {
602 case DHCPDISCOVER:
603 flag = 1;
604 /**/
605 case DHCPINFORM:
606 rc = dhcp_decode_discover(pData, bp, buf, size, flag, m);
607 if (rc > 0)
608 goto reply;
609 break;
610 case DHCPREQUEST:
611 rc = dhcp_decode_request(pData, bp, buf, size, m);
612 if (rc > 0)
613 goto reply;
614 break;
615 case DHCPRELEASE:
616 flag = 1;
617#if 0
618 case DHCPDECLINE:
619#endif
620 rc = dhcp_decode_release(pData, bp, buf, size, flag);
621 if (rc > 0)
622 goto reply;
623 break;
624 default:
625 AssertMsgFailed(("unsupported DHCP message type"));
626 }
627 Assert(m);
628 /*silently ignore*/
629 m_free(pData, m);
630 return;
631reply:
632 bootp_reply(pData, m, rc, bp->bp_flags);
633 return;
634}
635
636static void bootp_reply(PNATState pData, struct mbuf *m, int off, uint16_t flags)
637{
638 struct sockaddr_in saddr, daddr;
639 struct bootp_t *rbp = NULL;
640 uint8_t *q = NULL;
641 int nack;
642 rbp = mtod(m, struct bootp_t *);
643 Assert((m));
644 Assert((rbp));
645 q = rbp->bp_vend;
646 nack = (q[6] == DHCPNAK);
647 q += off;
648
649#ifndef VBOX_WITH_NAT_SERVICE
650 saddr.sin_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
651#else
652 saddr.sin_addr.s_addr = special_addr.s_addr;
653#endif
654
655 FILL_BOOTP_EXT(q, RFC2132_SRV_ID, 4, &saddr.sin_addr);
656
657
658 *q++ = RFC1533_END; /*end of message */
659
660
661 m->m_len = sizeof(struct bootp_t)
662 - sizeof(struct ip)
663 - sizeof(struct udphdr);
664 m->m_data += sizeof(struct udphdr)
665 + sizeof(struct ip);
666 if ((flags & DHCP_FLAGS_B) || nack != 0)
667 daddr.sin_addr.s_addr = INADDR_BROADCAST;
668 else
669 daddr.sin_addr.s_addr = rbp->bp_yiaddr.s_addr; /*unicast requested by client*/
670 saddr.sin_port = htons(BOOTP_SERVER);
671 daddr.sin_port = htons(BOOTP_CLIENT);
672 udp_output2(pData, NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
673}
674
675void bootp_input(PNATState pData, struct mbuf *m)
676{
677 struct bootp_t *bp = mtod(m, struct bootp_t *);
678
679 if (bp->bp_op == BOOTP_REQUEST)
680 {
681 dhcp_decode(pData, bp, bp->bp_vend, DHCP_OPT_LEN);
682 }
683}
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