VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/Dhcpd/VBoxNetDhcpd.cpp@ 78403

Last change on this file since 78403 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.1 KB
Line 
1/* $Id: VBoxNetDhcpd.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * VBoxNetDhcpd - DHCP server for host-only and NAT networks.
4 */
5
6/*
7 * Copyright (C) 2009-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include <iprt/cdefs.h>
19
20/*
21 * Need to get host/network order conversion stuff from Windows headers,
22 * so we do not define them in LWIP and then try to re-define them in
23 * Windows headers.
24 */
25#ifdef RT_OS_WINDOWS
26# include <iprt/win/winsock2.h>
27#endif
28
29
30#include <iprt/param.h>
31#include <iprt/errcore.h>
32
33#include <iprt/initterm.h>
34#include <iprt/message.h>
35
36#include <iprt/net.h>
37#include <iprt/path.h>
38#include <iprt/stream.h>
39
40#include <VBox/sup.h>
41#include <VBox/vmm/vmm.h>
42#include <VBox/vmm/pdmnetinline.h>
43#include <VBox/intnet.h>
44#include <VBox/intnetinline.h>
45
46#include "VBoxLwipCore.h"
47#include "Config.h"
48#include "DHCPD.h"
49#include "DhcpMessage.h"
50
51extern "C"
52{
53#include "lwip/sys.h"
54#include "lwip/pbuf.h"
55#include "lwip/netif.h"
56#include "lwip/tcpip.h"
57#include "lwip/udp.h"
58#include "netif/etharp.h"
59}
60
61#include <string>
62#include <vector>
63#include <memory>
64
65#ifdef RT_OS_WINDOWS
66# include <iprt/win/windows.h>
67#endif
68
69struct delete_pbuf
70{
71 delete_pbuf() {}
72 void operator()(struct pbuf *p) const { pbuf_free(p); }
73};
74
75typedef std::unique_ptr<pbuf, delete_pbuf> unique_ptr_pbuf;
76
77
78#define CALL_VMMR0(op, req) \
79 (SUPR3CallVMMR0Ex(NIL_RTR0PTR, NIL_VMCPUID, (op), 0, &(req).Hdr))
80
81
82class VBoxNetDhcpd
83{
84 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(VBoxNetDhcpd);
85
86private:
87 PRTLOGGER m_pStderrReleaseLogger;
88
89 /* intnet plumbing */
90 PSUPDRVSESSION m_pSession;
91 INTNETIFHANDLE m_hIf;
92 PINTNETBUF m_pIfBuf;
93
94 /* lwip stack connected to the intnet */
95 struct netif m_LwipNetif;
96
97 Config *m_Config;
98
99 /* listening pcb */
100 struct udp_pcb *m_Dhcp4Pcb;
101
102 DHCPD m_server;
103
104public:
105 VBoxNetDhcpd();
106 ~VBoxNetDhcpd();
107
108 int main(int argc, char **argv);
109
110private:
111 int logInitStderr();
112
113 /*
114 * Boilerplate code.
115 */
116 int r3Init();
117 void r3Fini();
118
119 int vmmInit();
120
121 int ifInit(const std::string &strNetwork,
122 const std::string &strTrunk = std::string(),
123 INTNETTRUNKTYPE enmTrunkType = kIntNetTrunkType_WhateverNone);
124 int ifOpen(const std::string &strNetwork,
125 const std::string &strTrunk,
126 INTNETTRUNKTYPE enmTrunkType);
127 int ifGetBuf();
128 int ifActivate();
129
130 int ifWait(uint32_t cMillies = RT_INDEFINITE_WAIT);
131 int ifProcessInput();
132 int ifFlush();
133
134 int ifClose();
135
136 void ifPump();
137 int ifInput(void *pvSegFrame, uint32_t cbSegFrame);
138
139 int ifOutput(PCINTNETSEG paSegs, size_t cSegs, size_t cbFrame);
140
141
142 /*
143 * lwIP callbacks
144 */
145 static DECLCALLBACK(void) lwipInitCB(void *pvArg);
146 void lwipInit();
147
148 static err_t netifInitCB(netif *pNetif);
149 err_t netifInit(netif *pNetif);
150
151 static err_t netifLinkOutputCB(netif *pNetif, pbuf *pPBuf);
152 err_t netifLinkOutput(pbuf *pPBuf);
153
154 static void dhcp4RecvCB(void *arg, struct udp_pcb *pcb, struct pbuf *p,
155 ip_addr_t *addr, u16_t port);
156 void dhcp4Recv(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
157};
158
159
160VBoxNetDhcpd::VBoxNetDhcpd()
161 : m_pStderrReleaseLogger(NULL),
162 m_pSession(NIL_RTR0PTR),
163 m_hIf(INTNET_HANDLE_INVALID),
164 m_pIfBuf(NULL),
165 m_LwipNetif(),
166 m_Config(NULL),
167 m_Dhcp4Pcb(NULL)
168{
169 int rc;
170
171 logInitStderr();
172
173 rc = r3Init();
174 if (RT_FAILURE(rc))
175 return;
176
177 vmmInit();
178}
179
180
181VBoxNetDhcpd::~VBoxNetDhcpd()
182{
183 ifClose();
184 r3Fini();
185}
186
187
188/*
189 * We don't know the name of the release log file until we parse our
190 * configuration because we use network name as basename. To get
191 * early logging to work, start with stderr-only release logger.
192 *
193 * We disable "sup" for this logger to avoid spam from SUPR3Init().
194 */
195int VBoxNetDhcpd::logInitStderr()
196{
197 static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
198
199 PRTLOGGER pLogger;
200 int rc;
201
202 uint32_t fFlags = 0;
203#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
204 fFlags |= RTLOGFLAGS_USECRLF;
205#endif
206
207 rc = RTLogCreate(&pLogger, fFlags,
208 "all -sup all.restrict -default.restrict",
209 NULL, /* environment base */
210 RT_ELEMENTS(s_apszGroups), s_apszGroups,
211 RTLOGDEST_STDERR, NULL);
212 if (RT_FAILURE(rc))
213 {
214 RTPrintf("Failed to init stderr logger: %Rrs\n", rc);
215 return rc;
216 }
217
218 m_pStderrReleaseLogger = pLogger;
219 RTLogRelSetDefaultInstance(m_pStderrReleaseLogger);
220
221 return VINF_SUCCESS;
222}
223
224
225int VBoxNetDhcpd::r3Init()
226{
227 AssertReturn(m_pSession == NIL_RTR0PTR, VERR_GENERAL_FAILURE);
228
229 int rc = SUPR3Init(&m_pSession);
230 return rc;
231}
232
233
234void VBoxNetDhcpd::r3Fini()
235{
236 if (m_pSession == NIL_RTR0PTR)
237 return;
238
239 SUPR3Term();
240 m_pSession = NIL_RTR0PTR;
241}
242
243
244int VBoxNetDhcpd::vmmInit()
245{
246 int rc;
247 try {
248 std::vector<char> vExecDir(RTPATH_MAX);
249 rc = RTPathExecDir(&vExecDir.front(), vExecDir.size());
250 if (RT_FAILURE(rc))
251 return rc;
252 std::string strPath(&vExecDir.front());
253 strPath.append("/VMMR0.r0");
254
255 rc = SUPR3LoadVMM(strPath.c_str());
256 if (RT_FAILURE(rc))
257 return rc;
258
259 rc = VINF_SUCCESS;
260 }
261 catch (...)
262 {
263 rc = VERR_GENERAL_FAILURE;
264 }
265
266 return rc;
267}
268
269
270int VBoxNetDhcpd::ifInit(const std::string &strNetwork,
271 const std::string &strTrunk,
272 INTNETTRUNKTYPE enmTrunkType)
273{
274 int rc;
275
276 rc = ifOpen(strNetwork, strTrunk, enmTrunkType);
277 if (RT_FAILURE(rc))
278 return rc;
279
280 rc = ifGetBuf();
281 if (RT_FAILURE(rc))
282 return rc;
283
284 rc = ifActivate();
285 if (RT_FAILURE(rc))
286 return rc;
287
288 return VINF_SUCCESS;
289}
290
291
292int VBoxNetDhcpd::ifOpen(const std::string &strNetwork,
293 const std::string &strTrunk,
294 INTNETTRUNKTYPE enmTrunkType)
295{
296 AssertReturn(m_pSession != NIL_RTR0PTR, VERR_GENERAL_FAILURE);
297 AssertReturn(m_hIf == INTNET_HANDLE_INVALID, VERR_GENERAL_FAILURE);
298
299 INTNETOPENREQ OpenReq;
300 int rc;
301
302 OpenReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
303 OpenReq.Hdr.cbReq = sizeof(OpenReq);
304 OpenReq.pSession = m_pSession;
305
306 strncpy(OpenReq.szNetwork, strNetwork.c_str(), sizeof(OpenReq.szNetwork));
307 OpenReq.szNetwork[sizeof(OpenReq.szNetwork) - 1] = '\0';
308
309 strncpy(OpenReq.szTrunk, strTrunk.c_str(), sizeof(OpenReq.szTrunk));
310 OpenReq.szTrunk[sizeof(OpenReq.szTrunk) - 1] = '\0';
311
312 if (enmTrunkType != kIntNetTrunkType_Invalid)
313 OpenReq.enmTrunkType = enmTrunkType;
314 else
315 OpenReq.enmTrunkType = kIntNetTrunkType_WhateverNone;
316
317 OpenReq.fFlags = 0;
318 OpenReq.cbSend = 128 * _1K;
319 OpenReq.cbRecv = 256 * _1K;
320
321 OpenReq.hIf = INTNET_HANDLE_INVALID;
322
323 rc = CALL_VMMR0(VMMR0_DO_INTNET_OPEN, OpenReq);
324 if (RT_FAILURE(rc))
325 return rc;
326
327 m_hIf = OpenReq.hIf;
328 AssertReturn(m_hIf != INTNET_HANDLE_INVALID, VERR_GENERAL_FAILURE);
329
330 return VINF_SUCCESS;
331}
332
333
334int VBoxNetDhcpd::ifGetBuf()
335{
336 AssertReturn(m_pSession != NIL_RTR0PTR, VERR_GENERAL_FAILURE);
337 AssertReturn(m_hIf != INTNET_HANDLE_INVALID, VERR_GENERAL_FAILURE);
338 AssertReturn(m_pIfBuf == NULL, VERR_GENERAL_FAILURE);
339
340 INTNETIFGETBUFFERPTRSREQ GetBufferPtrsReq;
341 int rc;
342
343 GetBufferPtrsReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
344 GetBufferPtrsReq.Hdr.cbReq = sizeof(GetBufferPtrsReq);
345 GetBufferPtrsReq.pSession = m_pSession;
346 GetBufferPtrsReq.hIf = m_hIf;
347
348 GetBufferPtrsReq.pRing0Buf = NIL_RTR0PTR;
349 GetBufferPtrsReq.pRing3Buf = NULL;
350
351 rc = CALL_VMMR0(VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS, GetBufferPtrsReq);
352 if (RT_FAILURE(rc))
353 return rc;
354
355 m_pIfBuf = GetBufferPtrsReq.pRing3Buf;
356 AssertReturn(m_pIfBuf != NULL, VERR_GENERAL_FAILURE);
357
358 return VINF_SUCCESS;
359}
360
361
362int VBoxNetDhcpd::ifActivate()
363{
364 AssertReturn(m_pSession != NIL_RTR0PTR, VERR_GENERAL_FAILURE);
365 AssertReturn(m_hIf != INTNET_HANDLE_INVALID, VERR_GENERAL_FAILURE);
366 AssertReturn(m_pIfBuf != NULL, VERR_GENERAL_FAILURE);
367
368 INTNETIFSETACTIVEREQ ActiveReq;
369 int rc;
370
371 ActiveReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
372 ActiveReq.Hdr.cbReq = sizeof(ActiveReq);
373 ActiveReq.pSession = m_pSession;
374 ActiveReq.hIf = m_hIf;
375
376 ActiveReq.fActive = 1;
377
378 rc = CALL_VMMR0(VMMR0_DO_INTNET_IF_SET_ACTIVE, ActiveReq);
379 return rc;
380}
381
382
383void VBoxNetDhcpd::ifPump()
384{
385 for (;;)
386 {
387 int rc = ifWait();
388
389 if (RT_UNLIKELY(rc == VERR_INTERRUPTED))
390 continue;
391
392#if 0 /* we wait indefinitely */
393 if (rc == VERR_TIMEOUT)
394 ...;
395#endif
396
397 if (RT_FAILURE(rc))
398 return;
399
400 ifProcessInput();
401 }
402}
403
404
405int VBoxNetDhcpd::ifWait(uint32_t cMillies)
406{
407 AssertReturn(m_pSession != NIL_RTR0PTR, VERR_GENERAL_FAILURE);
408 AssertReturn(m_hIf != INTNET_HANDLE_INVALID, VERR_GENERAL_FAILURE);
409
410 INTNETIFWAITREQ WaitReq;
411 int rc;
412
413 WaitReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
414 WaitReq.Hdr.cbReq = sizeof(WaitReq);
415 WaitReq.pSession = m_pSession;
416 WaitReq.hIf = m_hIf;
417
418 WaitReq.cMillies = cMillies;
419
420 rc = CALL_VMMR0(VMMR0_DO_INTNET_IF_WAIT, WaitReq);
421 return rc;
422}
423
424
425int VBoxNetDhcpd::ifProcessInput()
426{
427 AssertReturn(m_pSession != NIL_RTR0PTR, VERR_GENERAL_FAILURE);
428 AssertReturn(m_hIf != INTNET_HANDLE_INVALID, VERR_GENERAL_FAILURE);
429 AssertReturn(m_pIfBuf != NULL, VERR_GENERAL_FAILURE);
430
431 for (PCINTNETHDR pHdr;
432 (pHdr = IntNetRingGetNextFrameToRead(&m_pIfBuf->Recv)) != NULL;
433 IntNetRingSkipFrame(&m_pIfBuf->Recv))
434 {
435 const uint8_t u8Type = pHdr->u8Type;
436 void *pvSegFrame;
437 uint32_t cbSegFrame;
438
439 if (u8Type == INTNETHDR_TYPE_FRAME)
440 {
441 pvSegFrame = IntNetHdrGetFramePtr(pHdr, m_pIfBuf);
442 cbSegFrame = pHdr->cbFrame;
443
444 ifInput(pvSegFrame, cbSegFrame);
445 }
446 else if (u8Type == INTNETHDR_TYPE_GSO)
447 {
448 PCPDMNETWORKGSO pGso;
449 size_t cbGso = pHdr->cbFrame;
450 size_t cbFrame = cbGso - sizeof(PDMNETWORKGSO);
451
452 pGso = IntNetHdrGetGsoContext(pHdr, m_pIfBuf);
453 if (!PDMNetGsoIsValid(pGso, cbGso, cbFrame))
454 continue;
455
456 const uint32_t cSegs = PDMNetGsoCalcSegmentCount(pGso, cbFrame);
457 for (uint32_t i = 0; i < cSegs; ++i)
458 {
459 uint8_t abHdrScratch[256];
460 pvSegFrame = PDMNetGsoCarveSegmentQD(pGso, (uint8_t *)(pGso + 1), cbFrame,
461 abHdrScratch,
462 i, cSegs,
463 &cbSegFrame);
464 ifInput(pvSegFrame, (uint32_t)cbFrame);
465 }
466 }
467 }
468
469 return VINF_SUCCESS;
470}
471
472
473/*
474 * Got a frame from the internal network, feed it to the lwIP stack.
475 */
476int VBoxNetDhcpd::ifInput(void *pvFrame, uint32_t cbFrame)
477{
478 if (pvFrame == NULL)
479 return VERR_INVALID_PARAMETER;
480
481 if ( cbFrame <= sizeof(RTNETETHERHDR)
482 || cbFrame > UINT16_MAX - ETH_PAD_SIZE)
483 return VERR_INVALID_PARAMETER;
484
485 struct pbuf *p = pbuf_alloc(PBUF_RAW, (u16_t)cbFrame + ETH_PAD_SIZE, PBUF_POOL);
486 if (RT_UNLIKELY(p == NULL))
487 return VERR_NO_MEMORY;
488
489 /*
490 * The code below is inlined version of:
491 *
492 * pbuf_header(p, -ETH_PAD_SIZE); // hide padding
493 * pbuf_take(p, pvFrame, cbFrame);
494 * pbuf_header(p, ETH_PAD_SIZE); // reveal padding
495 */
496 struct pbuf *q = p;
497 uint8_t *pu8Chunk = (uint8_t *)pvFrame;
498 do {
499 uint8_t *payload = (uint8_t *)q->payload;
500 size_t len = q->len;
501
502#if ETH_PAD_SIZE
503 if (RT_LIKELY(q == p)) /* single pbuf is large enough */
504 {
505 payload += ETH_PAD_SIZE;
506 len -= ETH_PAD_SIZE;
507 }
508#endif
509 memcpy(payload, pu8Chunk, len);
510 pu8Chunk += len;
511 q = q->next;
512 } while (RT_UNLIKELY(q != NULL));
513
514 m_LwipNetif.input(p, &m_LwipNetif);
515 return VINF_SUCCESS;
516}
517
518
519/*
520 * Got a frame from the lwIP stack, feed it to the internal network.
521 */
522err_t VBoxNetDhcpd::netifLinkOutput(pbuf *pPBuf)
523{
524 PINTNETHDR pHdr;
525 void *pvFrame;
526 u16_t cbFrame;
527 int rc;
528
529 if (pPBuf->tot_len < sizeof(struct eth_hdr)) /* includes ETH_PAD_SIZE */
530 return ERR_ARG;
531
532 cbFrame = pPBuf->tot_len - ETH_PAD_SIZE;
533 rc = IntNetRingAllocateFrame(&m_pIfBuf->Send, cbFrame, &pHdr, &pvFrame);
534 if (RT_FAILURE(rc))
535 return ERR_MEM;
536
537 pbuf_copy_partial(pPBuf, pvFrame, cbFrame, ETH_PAD_SIZE);
538 IntNetRingCommitFrameEx(&m_pIfBuf->Send, pHdr, cbFrame);
539
540 ifFlush();
541 return ERR_OK;
542}
543
544
545int VBoxNetDhcpd::ifFlush()
546{
547 INTNETIFSENDREQ SendReq;
548 int rc;
549
550 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
551 SendReq.Hdr.cbReq = sizeof(SendReq);
552 SendReq.pSession = m_pSession;
553
554 SendReq.hIf = m_hIf;
555
556 rc = CALL_VMMR0(VMMR0_DO_INTNET_IF_SEND, SendReq);
557 return rc;
558}
559
560
561int VBoxNetDhcpd::ifClose()
562{
563 if (m_hIf == INTNET_HANDLE_INVALID)
564 return VINF_SUCCESS;
565
566 INTNETIFCLOSEREQ CloseReq;
567
568 CloseReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
569 CloseReq.Hdr.cbReq = sizeof(CloseReq);
570 CloseReq.pSession = m_pSession;
571
572 CloseReq.hIf = m_hIf;
573
574 m_hIf = INTNET_HANDLE_INVALID;
575 m_pIfBuf = NULL;
576
577 CALL_VMMR0(VMMR0_DO_INTNET_IF_CLOSE, CloseReq);
578 return VINF_SUCCESS;
579}
580
581
582/* static */ DECLCALLBACK(void) VBoxNetDhcpd::lwipInitCB(void *pvArg)
583{
584 AssertPtrReturnVoid(pvArg);
585
586 VBoxNetDhcpd *self = static_cast<VBoxNetDhcpd *>(pvArg);
587 self->lwipInit();
588}
589
590
591/* static */ err_t VBoxNetDhcpd::netifInitCB(netif *pNetif)
592{
593 AssertPtrReturn(pNetif, ERR_ARG);
594
595 VBoxNetDhcpd *self = static_cast<VBoxNetDhcpd *>(pNetif->state);
596 return self->netifInit(pNetif);
597}
598
599
600/* static */ err_t VBoxNetDhcpd::netifLinkOutputCB(netif *pNetif, pbuf *pPBuf)
601{
602 AssertPtrReturn(pNetif, ERR_ARG);
603 AssertPtrReturn(pPBuf, ERR_ARG);
604
605 VBoxNetDhcpd *self = static_cast<VBoxNetDhcpd *>(pNetif->state);
606 AssertPtrReturn(self, ERR_IF);
607
608 return self->netifLinkOutput(pPBuf);
609}
610
611
612/* static */ void VBoxNetDhcpd::dhcp4RecvCB(void *arg, struct udp_pcb *pcb,
613 struct pbuf *p,
614 ip_addr_t *addr, u16_t port)
615{
616 AssertPtrReturnVoid(arg);
617
618 VBoxNetDhcpd *self = static_cast<VBoxNetDhcpd *>(arg);
619 self->dhcp4Recv(pcb, p, addr, port);
620 pbuf_free(p);
621}
622
623
624
625
626
627int VBoxNetDhcpd::main(int argc, char **argv)
628{
629 int rc;
630
631 ClientId::registerFormat();
632
633 /* XXX: We no longer need hardcoded and compat methods. We should remove them soon. */
634 if (argc < 2)
635 m_Config = Config::hardcoded();
636 else if ( strcmp(argv[1], "--config") == 0
637 || strcmp(argv[1], "--comment") == 0)
638 m_Config = Config::create(argc, argv);
639 else
640 m_Config = Config::compat(argc, argv);
641
642 if (m_Config == NULL)
643 return VERR_GENERAL_FAILURE;
644
645 rc = m_server.init(m_Config);
646
647 /* connect to the intnet */
648 rc = ifInit(m_Config->getNetwork(),
649 m_Config->getTrunk(),
650 m_Config->getTrunkType());
651 if (RT_FAILURE(rc))
652 return rc;
653
654 /* setup lwip */
655 rc = vboxLwipCoreInitialize(lwipInitCB, this);
656 if (RT_FAILURE(rc))
657 return rc;
658
659 ifPump();
660 return VINF_SUCCESS;
661}
662
663
664void VBoxNetDhcpd::lwipInit()
665{
666 err_t error;
667
668 ip_addr_t addr, mask;
669 ip4_addr_set_u32(&addr, m_Config->getIPv4Address().u);
670 ip4_addr_set_u32(&mask, m_Config->getIPv4Netmask().u);
671
672 netif *pNetif = netif_add(&m_LwipNetif,
673 &addr, &mask,
674 IP_ADDR_ANY, /* gateway */
675 this, /* state */
676 VBoxNetDhcpd::netifInitCB, /* netif_init_fn */
677 tcpip_input); /* netif_input_fn */
678 if (pNetif == NULL)
679 return;
680
681 netif_set_up(pNetif);
682 netif_set_link_up(pNetif);
683
684 m_Dhcp4Pcb = udp_new();
685 if (RT_UNLIKELY(m_Dhcp4Pcb == NULL))
686 return; /* XXX? */
687
688 ip_set_option(m_Dhcp4Pcb, SOF_BROADCAST);
689 udp_recv(m_Dhcp4Pcb, dhcp4RecvCB, this);
690
691 error = udp_bind(m_Dhcp4Pcb, IP_ADDR_ANY, RTNETIPV4_PORT_BOOTPS);
692 if (error != ERR_OK)
693 {
694 udp_remove(m_Dhcp4Pcb);
695 m_Dhcp4Pcb = NULL;
696 return; /* XXX? */
697 }
698}
699
700
701err_t VBoxNetDhcpd::netifInit(netif *pNetif)
702{
703 pNetif->hwaddr_len = sizeof(RTMAC);
704 memcpy(pNetif->hwaddr, &m_Config->getMacAddress(), sizeof(RTMAC));
705
706 pNetif->mtu = 1500;
707
708 pNetif->flags = NETIF_FLAG_BROADCAST
709 | NETIF_FLAG_ETHARP
710 | NETIF_FLAG_ETHERNET;
711
712 pNetif->linkoutput = netifLinkOutputCB;
713 pNetif->output = etharp_output;
714
715 netif_set_default(pNetif);
716 return ERR_OK;
717}
718
719
720void VBoxNetDhcpd::dhcp4Recv(struct udp_pcb *pcb, struct pbuf *p,
721 ip_addr_t *addr, u16_t port)
722{
723 err_t error;
724 int rc;
725
726 RT_NOREF(pcb, addr, port);
727
728 if (RT_UNLIKELY(p->next != NULL))
729 return; /* XXX: we want it in one chunk */
730
731 bool broadcasted = ip_addr_cmp(ip_current_dest_addr(), &ip_addr_broadcast)
732 || ip_addr_cmp(ip_current_dest_addr(), &ip_addr_any);
733
734 DhcpClientMessage *msgIn = DhcpClientMessage::parse(broadcasted, p->payload, p->len);
735 if (msgIn == NULL)
736 return;
737
738 std::unique_ptr<DhcpClientMessage> autoFreeMsgIn(msgIn);
739
740 DhcpServerMessage *msgOut = m_server.process(*msgIn);
741 if (msgOut == NULL)
742 return;
743
744 std::unique_ptr<DhcpServerMessage> autoFreeMsgOut(msgOut);
745
746 ip_addr_t dst = { msgOut->dst().u };
747 if (ip_addr_cmp(&dst, &ip_addr_any))
748 ip_addr_copy(dst, ip_addr_broadcast);
749
750 octets_t data;
751 rc = msgOut->encode(data);
752 if (RT_FAILURE(rc))
753 return;
754
755 unique_ptr_pbuf q ( pbuf_alloc(PBUF_RAW, (u16_t)data.size(), PBUF_RAM) );
756 if (!q)
757 return;
758
759 error = pbuf_take(q.get(), &data.front(), (u16_t)data.size());
760 if (error != ERR_OK)
761 return;
762
763 error = udp_sendto(pcb, q.get(), &dst, RTNETIPV4_PORT_BOOTPC);
764 if (error != ERR_OK)
765 return;
766}
767
768
769
770
771/*
772 * Entry point.
773 */
774extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv)
775{
776 VBoxNetDhcpd Dhcpd;
777 int rc = Dhcpd.main(argc, argv);
778
779 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
780}
781
782
783#ifndef VBOX_WITH_HARDENING
784
785int main(int argc, char **argv)
786{
787 int rc = RTR3InitExe(argc, &argv, RTR3INIT_FLAGS_SUPLIB);
788 if (RT_FAILURE(rc))
789 return RTMsgInitFailure(rc);
790
791 return TrustedMain(argc, argv);
792}
793
794
795# ifdef RT_OS_WINDOWS
796/** (We don't want a console usually.) */
797int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
798{
799 RT_NOREF(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
800
801 return main(__argc, __argv);
802}
803# endif /* RT_OS_WINDOWS */
804
805#endif /* !VBOX_WITH_HARDENING */
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