VirtualBox

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

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

SUP: Added a PRTERRINFO parameter to SUPR3LoadVMM. bugref:9801

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