VirtualBox

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

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

NAT: removing some todos

  • Property svn:eol-style set to native
File size: 24.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
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 struct bootp_t *rbp;
336 int off = 0; /* boot_reply will fill general options and add END before sending response*/
337
338 dhcp_create_msg(pData, bp, m, DHCPOFFER);
339 off = dhcp_do_ack_offer(pData, m, bc, 0);
340 return off;
341}
342
343/**
344 * decoding client messages RFC2131 (4.3.6)
345 * ---------------------------------------------------------------------
346 * | |INIT-REBOOT |SELECTING |RENEWING |REBINDING |
347 * ---------------------------------------------------------------------
348 * |broad/unicast |broadcast |broadcast |unicast |broadcast |
349 * |server-ip |MUST NOT |MUST |MUST NOT |MUST NOT |
350 * |requested-ip |MUST |MUST |MUST NOT |MUST NOT |
351 * |ciaddr |zero |zero |IP address |IP address|
352 * ---------------------------------------------------------------------
353 *
354 */
355enum DHCP_REQUEST_STATES{INIT_REBOOT, SELECTING, RENEWING, REBINDING, NONE};
356static int dhcp_decode_request(PNATState pData, struct bootp_t *bp, const uint8_t *buf, int size, struct mbuf *m)
357{
358 BOOTPClient *bc;
359 struct in_addr daddr;
360 int off;
361 uint8_t *opt;
362 uint8_t *req_ip;
363 uint8_t *server_ip;
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
369 bc = find_addr(pData, &daddr, bp->bp_hwaddr);
370 if (!bc)
371 {
372 LogRel(("NAT: DHCP no IP address left\n"));
373 Log(("no address left\n"));
374 return -1;
375 }
376 if (server_ip != NULL)
377 {
378 /*selecting*/
379 dhcp_stat = SELECTING;
380 Assert((bp->bp_ciaddr.s_addr == INADDR_ANY));
381 Assert((*(uint32_t *)(req_ip + 2) == bc->addr.s_addr)); /*the same address as in offer*/
382 Assert((bp->bp_xid == bc->xid));
383 }
384 else
385 {
386 if (req_ip != NULL)
387 {
388 /* init-reboot */
389 dhcp_stat = INIT_REBOOT;
390 }
391 else
392 {
393 if (bp->bp_flags & DHCP_FLAGS_B)
394 dhcp_stat = RENEWING;
395 else
396 dhcp_stat = REBINDING; /*??rebinding??*/
397 }
398 }
399 /*?? renewing ??*/
400 if(dhcp_stat == RENEWING){
401 Assert(( server_ip == NULL
402 && req_ip == NULL
403 && bp->bp_ciaddr.s_addr != INADDR_ANY));
404 if (bc != NULL)
405 {
406 Assert((bc->addr.s_addr == bp->bp_ciaddr.s_addr));
407 /*if it already here well just do ack, we aren't aware of dhcp time expiration*/
408 }
409 else
410 {
411 if ((bp->bp_ciaddr.s_addr & pData->netmask) != special_addr.s_addr)
412 {
413 off = dhcp_send_nack(pData, bp, bc, m);
414 return off;
415 }
416 bc = alloc_addr(pData);
417 if (bc == NULL)
418 {
419 LogRel(("NAT: can't alloc address. RENEW has been silently ignored\n"));
420 return -1;
421 }
422 Assert((bp->bp_hlen == ETH_ALEN));
423 memcpy(bc->macaddr, bp->bp_hwaddr, bp->bp_hlen);
424 bc->addr.s_addr = bp->bp_ciaddr.s_addr;
425 }
426 }
427 Assert((dhcp_stat != NONE));
428 off = dhcp_send_ack(pData, bp, bc, m, 1);
429 return off;
430}
431
432static int dhcp_decode_discover(PNATState pData, struct bootp_t *bp, const uint8_t *buf, int size, int flag, struct mbuf *m)
433{
434 BOOTPClient *bc;
435 struct in_addr daddr;
436 int off;
437 /* flag == 1 discover */
438 if (flag == 1)
439 {
440 bc = find_addr(pData, &daddr, bp->bp_hwaddr);
441 if (!bc)
442 {
443 bc = get_new_addr(pData, &daddr);
444 if (!bc)
445 {
446 LogRel(("NAT: DHCP no IP address left\n"));
447 Log(("no address left\n"));
448 return -1;
449 }
450 memcpy(bc->macaddr, bp->bp_hwaddr, 6);
451 }
452 bc->xid = bp->bp_xid;
453 /*bc isn't NULL */
454 off = dhcp_send_offer(pData, bp, bc, m);
455 return off;
456 }
457 else
458 {
459 /* flag == 0 inform */
460 bc = find_addr(pData, &daddr, bp->bp_hwaddr);
461 if (bc == NULL)
462 {
463 LogRel(("NAT: DHCP Inform was ignored no boot client was found\n"));
464 return -1;
465 }
466 off = dhcp_send_ack(pData, bp, bc, m, 0);
467 return off;
468 }
469 return -1;
470}
471
472static int dhcp_decode_release(PNATState pData, struct bootp_t *bp, const uint8_t *buf, int size, int flag)
473{
474 return -1;
475}
476/**
477 * fields for discovering t
478 * Field DHCPDISCOVER DHCPREQUEST DHCPDECLINE,
479 * DHCPINFORM DHCPRELEASE
480 * ----- ------------ ----------- -----------
481 * 'op' BOOTREQUEST BOOTREQUEST BOOTREQUEST
482 * 'htype' (From "Assigned Numbers" RFC)
483 * 'hlen' (Hardware address length in octets)
484 * 'hops' 0 0 0
485 * 'xid' selected by client 'xid' from server selected by
486 * DHCPOFFER message client
487 * 'secs' 0 or seconds since 0 or seconds since 0
488 * DHCP process started DHCP process started
489 * 'flags' Set 'BROADCAST' Set 'BROADCAST' 0
490 * flag if client flag if client
491 * requires broadcast requires broadcast
492 * reply reply
493 * 'ciaddr' 0 (DHCPDISCOVER) 0 or client's 0 (DHCPDECLINE)
494 * client's network address client's network
495 * network address (BOUND/RENEW/REBIND) address
496 * (DHCPINFORM) (DHCPRELEASE)
497 * 'yiaddr' 0 0 0
498 * 'siaddr' 0 0 0
499 * 'giaddr' 0 0 0
500 * 'chaddr' client's hardware client's hardware client's hardware
501 * address address address
502 * 'sname' options, if options, if (unused)
503 * indicated in indicated in
504 * 'sname/file' 'sname/file'
505 * option; otherwise option; otherwise
506 * unused unused
507 * 'file' options, if options, if (unused)
508 * indicated in indicated in
509 * 'sname/file' 'sname/file'
510 * option; otherwise option; otherwise
511 * unused unused
512 * 'options' options options (unused)
513 * Requested IP address MAY MUST (in MUST
514 * (DISCOVER) SELECTING or (DHCPDECLINE),
515 * MUST NOT INIT-REBOOT) MUST NOT
516 * (INFORM) MUST NOT (in (DHCPRELEASE)
517 * BOUND or
518 * RENEWING)
519 * IP address lease time MAY MAY MUST NOT
520 * (DISCOVER)
521 * MUST NOT
522 * (INFORM)
523 * Use 'file'/'sname' fields MAY MAY MAY
524 * DHCP message type DHCPDISCOVER/ DHCPREQUEST DHCPDECLINE/
525 * DHCPINFORM DHCPRELEASE
526 * Client identifier MAY MAY MAY
527 * Vendor class identifier MAY MAY MUST NOT
528 * Server identifier MUST NOT MUST (after MUST
529 * SELECTING)
530 * MUST NOT (after
531 * INIT-REBOOT,
532 * BOUND, RENEWING
533 * or REBINDING)
534 * Parameter request list MAY MAY MUST NOT
535 * Maximum message size MAY MAY MUST NOT
536 * Message SHOULD NOT SHOULD NOT SHOULD
537 * Site-specific MAY MAY MUST NOT
538 * All others MAY MAY MUST NOT
539 *
540 */
541static void dhcp_decode(PNATState pData, struct bootp_t *bp, const uint8_t *buf, int size)
542{
543 const uint8_t *p, *p_end;
544 int rc;
545 int pmsg_type;
546 struct in_addr req_ip;
547 int flag = 0;
548 int len, tag;
549 struct mbuf *m = NULL;
550
551 pmsg_type = 0;
552
553 p = buf;
554 p_end = buf + size;
555 if (size < 5)
556 return;
557 if (memcmp(p, rfc1533_cookie, 4) != 0)
558 return;
559 p = dhcp_find_option(bp->bp_vend, RFC2132_MSG_TYPE);
560 Assert(p);
561 if (p == NULL)
562 return;
563 if ((m = m_get(pData)) == NULL)
564 {
565 LogRel(("NAT: can't alocate memory for response!\n"));
566 return;
567 }
568 switch(*(p+2))
569 {
570 case DHCPDISCOVER:
571 flag = 1;
572 /**/
573 case DHCPINFORM:
574 rc = dhcp_decode_discover(pData, bp, buf, size, flag, m);
575 Assert(rc > 0);
576 goto reply;
577 break;
578 case DHCPREQUEST:
579 rc = dhcp_decode_request(pData, bp, buf, size, m);
580 Assert(rc > 0);
581 goto reply;
582 break;
583 case DHCPRELEASE:
584 flag = 1;
585#if 0
586 case DHCPDECLINE:
587#endif
588 rc = dhcp_decode_release(pData, bp, buf, size, flag);
589 Assert(rc > 0);
590 goto reply;
591 break;
592 default:
593 AssertMsgFailed(("unsupported DHCP message type"));
594 }
595 return;
596reply:
597 Assert(m);
598 if (rc < 0)
599 {
600 /*silently ignore*/
601 m_free(pData, m);
602 return;
603 }
604 bootp_reply(pData, m, rc, bp->bp_flags);
605 return;
606}
607
608static void bootp_reply(PNATState pData, struct mbuf *m, int off, uint16_t flags)
609{
610#if 0
611 BOOTPClient *bc;
612 struct mbuf *m; /* XXX: @todo vasily - it'd be better to reuse this mbuf here */
613 struct bootp_t *bp = mtod(m0, struct bootp_t *);
614 struct bootp_t *rbp;
615 struct sockaddr_in saddr, daddr;
616 int dhcp_msg_type, val;
617 uint8_t *q;
618 struct in_addr requested_ip; /* the requested IP in DHCPREQUEST */
619 int send_nak = 0;
620
621 /* extract exact DHCP msg type */
622 requested_ip.s_addr = 0xffffffff;
623 dhcp_decode(bp, bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type, &requested_ip);
624 Log(("bootp packet op=%d msgtype=%d\n", bp->bp_op, dhcp_msg_type));
625
626 if (dhcp_msg_type == 0)
627 dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */
628
629 if (dhcp_msg_type == DHCPRELEASE)
630 {
631 int rc;
632 rc = release_addr(pData, &bp->bp_ciaddr);
633 LogRel(("NAT: %s %R[IP4]\n",
634 rc ? "DHCP released IP address" : "Ignored DHCP release for IP address",
635 &bp->bp_ciaddr));
636 /* This message is not to be answered in any way. */
637 return;
638 }
639 if ( dhcp_msg_type != DHCPDISCOVER
640 && dhcp_msg_type != DHCPREQUEST)
641 return;
642
643
644 if (dhcp_msg_type == DHCPDISCOVER)
645 {
646 /* Do not allocate a new lease for clients that forgot that they had a lease. */
647 }
648 else if (dhcp_msg_type == DHCPREQUEST)
649 {
650 *q++ = RFC2132_MSG_TYPE;
651 *q++ = 1;
652 if (requested_ip.s_addr != daddr.sin_addr.s_addr)
653 {
654 /* network changed */
655 *q++ = DHCPNAK;
656 send_nak = 1;
657 }
658 else
659 *q++ = DHCPACK;
660 }
661
662 if (send_nak)
663 LogRel(("NAT: Client requested IP address %R[IP4] -- sending NAK\n",
664 &requested_ip));
665 else
666 LogRel(("NAT: DHCP offered IP address %R[IP4]\n",
667 &daddr.sin_addr));
668 if ( dhcp_msg_type == DHCPDISCOVER
669 || dhcp_msg_type == DHCPREQUEST)
670 {
671 FILL_BOOTP_EXT(q, RFC2132_SRV_ID, 4, &saddr.sin_addr);
672 }
673
674 if (!send_nak &&
675 ( dhcp_msg_type == DHCPDISCOVER
676 || dhcp_msg_type == DHCPREQUEST))
677#endif
678 struct sockaddr_in saddr, daddr;
679 struct bootp_t *rbp = NULL;
680 uint8_t *q = NULL;
681 int nack;
682 rbp = mtod(m, struct bootp_t *);
683 Assert((m));
684 Assert((rbp));
685 q = rbp->bp_vend;
686 nack = (q[6] == DHCPNAK);
687 q += off;
688
689#ifndef VBOX_WITH_NAT_SERVICE
690 saddr.sin_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
691#else
692 saddr.sin_addr.s_addr = special_addr.s_addr;
693#endif
694
695 FILL_BOOTP_EXT(q, RFC2132_SRV_ID, 4, &saddr.sin_addr);
696
697
698 *q++ = RFC1533_END; /*end of message */
699
700
701 m->m_len = sizeof(struct bootp_t)
702 - sizeof(struct ip)
703 - sizeof(struct udphdr);
704 m->m_data += sizeof(struct udphdr)
705 + sizeof(struct ip);
706 if ((flags & DHCP_FLAGS_B) || nack != 0)
707 daddr.sin_addr.s_addr = INADDR_BROADCAST;
708 else
709 daddr.sin_addr.s_addr = rbp->bp_yiaddr.s_addr; /*unicast requested by client*/
710 saddr.sin_port = htons(BOOTP_SERVER);
711 daddr.sin_port = htons(BOOTP_CLIENT);
712 udp_output2(pData, NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
713}
714
715void bootp_input(PNATState pData, struct mbuf *m)
716{
717 struct bootp_t *bp = mtod(m, struct bootp_t *);
718
719 if (bp->bp_op == BOOTP_REQUEST)
720 {
721 dhcp_decode(pData, bp, bp->bp_vend, DHCP_OPT_LEN);
722 }
723}
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