VirtualBox

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

Last change on this file since 86822 was 86822, checked in by vboxsync, 4 years ago

VBoxNetDHCP: Fixed incorrect VBoxNetDhcpd::ifPump return condition (don't return on VERR_INTERRUPT). Inlined ifWait since it was only used from ifPump. bugref:9787

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