VirtualBox

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

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

Dhcpd: DHCP_LOG_MSG_ERROR. bugref:9288

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