VirtualBox

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

最後變更 在這個檔案從22541是 22541,由 vboxsync 提交於 16 年 前

NAT: some order in ARP cache managment + gratuitous ARP request handling

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

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