VirtualBox

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

Last change on this file since 22101 was 22101, checked in by vboxsync, 15 years ago

NAT: dhcp rfc2131/rfc2132 step 1

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