VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DevINIP.cpp@ 60404

Last change on this file since 60404 was 58170, checked in by vboxsync, 9 years ago

doxygen: fixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.8 KB
Line 
1/* $Id: DevINIP.cpp 58170 2015-10-12 09:27:14Z vboxsync $ */
2/** @file
3 * DevINIP - Internal Network IP stack device/service.
4 */
5
6/*
7 * Copyright (C) 2007-2015 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/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DEV_INIP
23#include <iprt/cdefs.h> /* include early to allow RT_C_DECLS_BEGIN hack */
24#include <iprt/mem.h> /* include anything of ours that the lwip headers use. */
25#include <iprt/semaphore.h>
26#include <iprt/thread.h>
27#include <iprt/alloca.h>
28/* All lwip header files are not C++ safe. So hack around this. */
29RT_C_DECLS_BEGIN
30#include "lwip/sys.h"
31#include "lwip/stats.h"
32#include "lwip/mem.h"
33#include "lwip/memp.h"
34#include "lwip/pbuf.h"
35#include "lwip/netif.h"
36#include "lwip/api.h"
37#include "lwip/tcp_impl.h"
38# if LWIP_IPV6
39# include "ipv6/lwip/ethip6.h"
40# endif
41#include "lwip/udp.h"
42#include "lwip/tcp.h"
43#include "lwip/tcpip.h"
44#include "lwip/sockets.h"
45#include "netif/etharp.h"
46RT_C_DECLS_END
47#include <VBox/vmm/pdmdev.h>
48#include <VBox/vmm/pdmnetifs.h>
49#include <VBox/vmm/tm.h>
50#include <iprt/assert.h>
51#include <iprt/string.h>
52#include <iprt/uuid.h>
53
54#include "VBoxDD.h"
55#include "VBoxLwipCore.h"
56
57
58/*********************************************************************************************************************************
59* Macros and Defines *
60*********************************************************************************************************************************/
61
62/** Maximum frame size this device can handle. */
63#define DEVINIP_MAX_FRAME 1514
64
65
66/*********************************************************************************************************************************
67* Structures and Typedefs *
68*********************************************************************************************************************************/
69
70/**
71 * Internal Network IP stack device instance data.
72 *
73 * @implements PDMIBASE
74 * @implements PDMINETWORKDOWN
75 */
76typedef struct DEVINTNETIP
77{
78 /** The base interface for LUN\#0. */
79 PDMIBASE IBase;
80 /** The network port this device provides (LUN\#0). */
81 PDMINETWORKDOWN INetworkDown;
82 /** The network configuration port this device provides (LUN\#0). */
83 PDMINETWORKCONFIG INetworkConfig;
84 /** The base interface of the network driver below us. */
85 PPDMIBASE pDrvBase;
86 /** The connector of the network driver below us. */
87 PPDMINETWORKUP pDrv;
88 /** Pointer to the device instance. */
89 PPDMDEVINSR3 pDevIns;
90 /** MAC address. */
91 RTMAC MAC;
92 /** Static IP address of the interface. */
93 char *pszIP;
94 /** Netmask of the interface. */
95 char *pszNetmask;
96 /** Gateway for the interface. */
97 char *pszGateway;
98 /** lwIP network interface description. */
99 struct netif IntNetIF;
100 /** lwIP ARP timer. */
101 PTMTIMERR3 ARPTimer;
102 /** lwIP TCP fast timer. */
103 PTMTIMERR3 TCPFastTimer;
104 /** lwIP TCP slow timer. */
105 PTMTIMERR3 TCPSlowTimer;
106 /** lwIP semaphore to coordinate TCPIP init/terminate. */
107 sys_sem_t LWIPTcpInitSem;
108 /** hack: get linking right. remove this eventually, once the device
109 * provides a proper interface to all IP stack functions. */
110 const void *pLinkHack;
111 /** Flag whether the link is up. */
112 bool fLnkUp;
113 /**
114 * In callback we're getting status of interface adding operation (TCPIP thread),
115 * but we need inform constructing routine whether it was success or not(EMT thread).
116 */
117 int rcInitialization;
118} DEVINTNETIP, *PDEVINTNETIP;
119
120
121/*********************************************************************************************************************************
122* Global Variables *
123*********************************************************************************************************************************/
124
125/**
126 * Pointer to the (only) instance data in this device.
127 */
128static PDEVINTNETIP g_pDevINIPData = NULL;
129
130/*
131 * really ugly hack to avoid linking problems on unix style platforms
132 * using .a libraries for now.
133 */
134static const PFNRT g_pDevINILinkHack[] =
135{
136 (PFNRT)lwip_socket,
137 (PFNRT)lwip_close,
138 (PFNRT)lwip_setsockopt,
139 (PFNRT)lwip_recv,
140 (PFNRT)lwip_send,
141 (PFNRT)lwip_select
142};
143
144
145/*********************************************************************************************************************************
146* Internal Functions *
147*********************************************************************************************************************************/
148static err_t devINIPOutput(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr);
149static err_t devINIPOutputRaw(struct netif *netif, struct pbuf *p);
150static err_t devINIPInterface(struct netif *netif);
151
152
153/**
154 * Output a TCP/IP packet on the interface. Uses the generic lwIP ARP
155 * code to resolve the address and call the link-level packet function.
156 *
157 * @returns lwIP error code
158 * @param netif Interface on which to send IP packet.
159 * @param p Packet data.
160 * @param ipaddr Destination IP address.
161 */
162static err_t devINIPOutput(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr)
163{
164 err_t lrc;
165 LogFlow(("%s: netif=%p p=%p ipaddr=%#04x\n", __FUNCTION__, netif, p,
166 ipaddr->addr));
167
168 lrc = lwip_etharp_output(netif, p, ipaddr);
169
170 LogFlow(("%s: return %d\n", __FUNCTION__, lrc));
171 return lrc;
172}
173
174/**
175 * Output a raw packet on the interface.
176 *
177 * @returns lwIP error code
178 * @param netif Interface on which to send frame.
179 * @param p Frame data.
180 */
181static err_t devINIPOutputRaw(struct netif *netif, struct pbuf *p)
182{
183 int rc = VINF_SUCCESS;
184
185 LogFlow(("%s: netif=%p p=%p\n", __FUNCTION__, netif, p));
186 Assert(g_pDevINIPData);
187 Assert(g_pDevINIPData->pDrv);
188
189 /* Silently ignore packets being sent while lwIP isn't set up. */
190 if (g_pDevINIPData)
191 {
192 PPDMSCATTERGATHER pSgBuf;
193
194 rc = g_pDevINIPData->pDrv->pfnBeginXmit(g_pDevINIPData->pDrv, true /* fOnWorkerThread */);
195 if (RT_FAILURE(rc))
196 return ERR_IF;
197
198 rc = g_pDevINIPData->pDrv->pfnAllocBuf(g_pDevINIPData->pDrv, DEVINIP_MAX_FRAME, NULL /*pGso*/, &pSgBuf);
199 if (RT_SUCCESS(rc))
200 {
201#if ETH_PAD_SIZE
202 lwip_pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
203#endif
204
205 uint8_t *pbBuf = pSgBuf ? (uint8_t *)pSgBuf->aSegs[0].pvSeg : NULL;
206 size_t cbBuf = 0;
207 for (struct pbuf *q = p; q != NULL; q = q->next)
208 {
209 if (cbBuf + q->len <= DEVINIP_MAX_FRAME)
210 {
211 if (RT_LIKELY(pbBuf))
212 {
213 memcpy(pbBuf, q->payload, q->len);
214 pbBuf += q->len;
215 }
216 cbBuf += q->len;
217 }
218 else
219 {
220 LogRel(("INIP: exceeded frame size\n"));
221 break;
222 }
223 }
224 if (cbBuf)
225 {
226 pSgBuf->cbUsed = cbBuf;
227 rc = g_pDevINIPData->pDrv->pfnSendBuf(g_pDevINIPData->pDrv, pSgBuf, true /* fOnWorkerThread */);
228 }
229 else
230 rc = g_pDevINIPData->pDrv->pfnFreeBuf(g_pDevINIPData->pDrv, pSgBuf);
231
232#if ETH_PAD_SIZE
233 lwip_pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
234#endif
235 }
236
237 g_pDevINIPData->pDrv->pfnEndXmit(g_pDevINIPData->pDrv);
238 }
239
240 err_t lrc = ERR_OK;
241 if (RT_FAILURE(rc))
242 lrc = ERR_IF;
243 LogFlow(("%s: return %d (vbox: %Rrc)\n", __FUNCTION__, rc, lrc));
244 return lrc;
245}
246
247/**
248 * Implements the ethernet interface backend initialization for lwIP.
249 *
250 * @returns lwIP error code
251 * @param netif Interface to configure.
252 */
253static err_t devINIPInterface(struct netif *netif)
254{
255 LogFlow(("%s: netif=%p\n", __FUNCTION__, netif));
256 Assert(g_pDevINIPData != NULL);
257 netif->state = g_pDevINIPData;
258 netif->hwaddr_len = sizeof(g_pDevINIPData->MAC);
259 memcpy(netif->hwaddr, &g_pDevINIPData->MAC, sizeof(g_pDevINIPData->MAC));
260 netif->mtu = DEVINIP_MAX_FRAME;
261 netif->flags = NETIF_FLAG_BROADCAST;
262 netif->flags |= NETIF_FLAG_ETHARP;
263 netif->flags |= NETIF_FLAG_ETHERNET;
264
265#if LWIP_IPV6
266 netif_create_ip6_linklocal_address(netif, 0);
267 netif_ip6_addr_set_state(netif, 0, IP6_ADDR_VALID);
268 netif->output_ip6 = ethip6_output;
269 netif->ip6_autoconfig_enabled=1;
270 LogFunc(("netif: ipv6:%RTnaipv6\n", &netif->ip6_addr[0].addr[0]));
271#endif
272
273 netif->output = lwip_etharp_output;
274 netif->linkoutput = devINIPOutputRaw;
275
276 LogFlow(("%s: success\n", __FUNCTION__));
277 return ERR_OK;
278}
279
280/**
281 * Parses CFGM parameters related to network connection
282 */
283static DECLCALLBACK(int) devINIPNetworkConfiguration(PPDMDEVINS pDevIns, PDEVINTNETIP pThis, PCFGMNODE pCfg)
284{
285 int rc = VINF_SUCCESS;
286 rc = CFGMR3QueryStringAlloc(pCfg, "IP", &pThis->pszIP);
287 if (RT_FAILURE(rc))
288 {
289 PDMDEV_SET_ERROR(pDevIns, rc,
290 N_("Configuration error: Failed to get the \"IP\" value"));
291 /* @todo: perhaps we should panic if IPv4 address isn't specify, with assumtion that
292 * ISCSI target specified in IPv6 form.
293 */
294 return rc;
295 }
296
297 rc = CFGMR3QueryStringAlloc(pCfg, "Netmask", &pThis->pszNetmask);
298 if (RT_FAILURE(rc))
299 {
300 PDMDEV_SET_ERROR(pDevIns, rc,
301 N_("Configuration error: Failed to get the \"Netmask\" value"));
302 return rc;
303 }
304 rc = CFGMR3QueryStringAlloc(pCfg, "Gateway", &pThis->pszGateway);
305 if ( RT_FAILURE(rc)
306 && rc != VERR_CFGM_VALUE_NOT_FOUND)
307 {
308 PDMDEV_SET_ERROR(pDevIns, rc,
309 N_("Configuration error: Failed to get the \"Gateway\" value"));
310 return rc;
311 }
312 return VINF_SUCCESS;
313}
314
315/**
316 * Wait until data can be received.
317 *
318 * @returns VBox status code. VINF_SUCCESS means there is at least one receive descriptor available.
319 * @param pInterface PDM network port interface pointer.
320 * @param cMillies Number of milliseconds to wait. 0 means return immediately.
321 */
322static DECLCALLBACK(int) devINIPNetworkDown_WaitInputAvail(PPDMINETWORKDOWN pInterface, RTMSINTERVAL cMillies)
323{
324 LogFlow(("%s: pInterface=%p\n", __FUNCTION__, pInterface));
325 LogFlow(("%s: return VINF_SUCCESS\n", __FUNCTION__));
326 return VINF_SUCCESS;
327}
328
329/**
330 * Receive data and pass it to lwIP for processing.
331 *
332 * @returns VBox status code
333 * @param pInterface PDM network port interface pointer.
334 * @param pvBuf Pointer to frame data.
335 * @param cb Frame size.
336 */
337static DECLCALLBACK(int) devINIPNetworkDown_Input(PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb)
338{
339 const uint8_t *pbBuf = (const uint8_t *)pvBuf;
340 size_t len = cb;
341 const struct eth_hdr *ethhdr;
342 struct pbuf *p, *q;
343 int rc = VINF_SUCCESS;
344
345 LogFlow(("%s: pInterface=%p pvBuf=%p cb=%lu\n", __FUNCTION__, pInterface, pvBuf, cb));
346 Assert(g_pDevINIPData);
347 Assert(g_pDevINIPData->pDrv);
348
349 /* Silently ignore packets being received while lwIP isn't set up. */
350 if (!g_pDevINIPData)
351 {
352 LogFlow(("%s: return %Rrc (no global)\n", __FUNCTION__, rc));
353 return VINF_SUCCESS;
354 }
355
356#if ETH_PAD_SIZE
357 len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
358#endif
359
360 /* We allocate a pbuf chain of pbufs from the pool. */
361 p = lwip_pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
362 if (p != NULL)
363 {
364#if ETH_PAD_SIZE
365 lwip_pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
366#endif
367
368 for (q = p; q != NULL; q = q->next)
369 {
370 /* Fill the buffers, and clean out unused buffer space. */
371 memcpy(q->payload, pbBuf, RT_MIN(cb, q->len));
372 pbBuf += RT_MIN(cb, q->len);
373 if (q->len > cb)
374 memset(((uint8_t *)q->payload) + cb, '\0', q->len - cb);
375 cb -= RT_MIN(cb, q->len);
376 }
377
378 ethhdr = (const struct eth_hdr *)p->payload;
379 struct netif *iface = &g_pDevINIPData->IntNetIF;
380
381 /* We've setup flags NETIF_FLAG_ETHARP and NETIF_FLAG_ETHERNET
382 so this should be thread-safe. */
383 tcpip_input(p,iface);
384 }
385
386 LogFlow(("%s: return %Rrc\n", __FUNCTION__, rc));
387 return rc;
388}
389
390/**
391 * @interface_method_impl{PDMINETWORKDOWN,pfnXmitPending}
392 */
393static DECLCALLBACK(void) devINIPNetworkDown_XmitPending(PPDMINETWORKDOWN pInterface)
394{
395 NOREF(pInterface);
396}
397
398
399/**
400 * Signals the end of lwIP TCPIP initialization.
401 *
402 * @note: TCPIP thread, corresponding EMT waiting on semaphore.
403 * @param arg opaque argument, here the pointer to the PDEVINTNETIP.
404 */
405static DECLCALLBACK(void) devINIPTcpipInitDone(void *arg)
406{
407 PDEVINTNETIP pThis = (PDEVINTNETIP)arg;
408 AssertPtrReturnVoid(arg);
409
410 pThis->rcInitialization = VINF_SUCCESS;
411 {
412 struct netif *ret;
413 struct ip_addr ipaddr, netmask, gw;
414 struct in_addr ip;
415
416 if (!inet_aton(pThis->pszIP, &ip))
417 {
418 pThis->rcInitialization = VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
419 PDMDEV_SET_ERROR(pThis->pDevIns,
420 pThis->rcInitialization,
421 N_("Configuration error: Invalid \"IP\" value"));
422 goto done;
423 }
424 memcpy(&ipaddr, &ip, sizeof(ipaddr));
425
426 if (!inet_aton(pThis->pszNetmask, &ip))
427 {
428 pThis->rcInitialization = VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
429 PDMDEV_SET_ERROR(pThis->pDevIns,
430 pThis->rcInitialization,
431 N_("Configuration error: Invalid \"Netmask\" value"));
432 goto done;
433 }
434 memcpy(&netmask, &ip, sizeof(netmask));
435
436 if (pThis->pszGateway)
437 {
438 if (!inet_aton(pThis->pszGateway, &ip))
439 {
440 pThis->rcInitialization = VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
441 PDMDEV_SET_ERROR(pThis->pDevIns,
442 pThis->rcInitialization,
443 N_("Configuration error: Invalid \"Gateway\" value"));
444 goto done;
445 }
446
447 }
448 else
449 {
450 inet_aton(pThis->pszIP, &ip);
451 }
452 memcpy(&gw, &ip, sizeof(gw));
453
454 pThis->IntNetIF.name[0] = 'I';
455 pThis->IntNetIF.name[1] = 'N';
456
457 ret = netif_add(&pThis->IntNetIF, &ipaddr, &netmask, &gw, NULL,
458 devINIPInterface, lwip_tcpip_input);
459
460 if (!ret)
461 {
462
463 pThis->rcInitialization = VERR_NET_NO_NETWORK;
464 PDMDEV_SET_ERROR(pThis->pDevIns,
465 pThis->rcInitialization,
466 N_("netif_add failed"));
467 goto done;
468 }
469
470 lwip_netif_set_default(&pThis->IntNetIF);
471 lwip_netif_set_up(&pThis->IntNetIF);
472 }
473 done:
474 return;
475}
476
477
478/**
479 * This callback is for finitializing our activity on TCPIP thread.
480 * XXX: We do it only for new LWIP, old LWIP will stay broken for now.
481 */
482static DECLCALLBACK(void) devINIPTcpipFiniDone(void *arg)
483{
484 PDEVINTNETIP pThis = (PDEVINTNETIP)arg;
485 AssertPtrReturnVoid(arg);
486
487 netif_set_link_down(&pThis->IntNetIF);
488 netif_set_down(&pThis->IntNetIF);
489 netif_remove(&pThis->IntNetIF);
490}
491
492
493/**
494 * Gets the current Media Access Control (MAC) address.
495 *
496 * @returns VBox status code.
497 * @param pInterface Pointer to the interface structure containing the called function pointer.
498 * @param pMac Where to store the MAC address.
499 * @thread EMT
500 */
501static DECLCALLBACK(int) devINIPGetMac(PPDMINETWORKCONFIG pInterface, PRTMAC pMac)
502{
503 PDEVINTNETIP pThis = RT_FROM_MEMBER(pInterface, DEVINTNETIP, INetworkConfig);
504 memcpy(pMac, pThis->MAC.au8, sizeof(RTMAC));
505 return VINF_SUCCESS;
506}
507
508/**
509 * Gets the new link state.
510 *
511 * @returns The current link state.
512 * @param pInterface Pointer to the interface structure containing the called function pointer.
513 * @thread EMT
514 */
515static DECLCALLBACK(PDMNETWORKLINKSTATE) devINIPGetLinkState(PPDMINETWORKCONFIG pInterface)
516{
517 PDEVINTNETIP pThis = RT_FROM_MEMBER(pInterface, DEVINTNETIP, INetworkConfig);
518 if (pThis->fLnkUp)
519 return PDMNETWORKLINKSTATE_UP;
520 return PDMNETWORKLINKSTATE_DOWN;
521}
522
523
524/**
525 * Sets the new link state.
526 *
527 * @returns VBox status code.
528 * @param pInterface Pointer to the interface structure containing the called function pointer.
529 * @param enmState The new link state
530 */
531static DECLCALLBACK(int) devINIPSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
532{
533 PDEVINTNETIP pThis = RT_FROM_MEMBER(pInterface, DEVINTNETIP, INetworkConfig);
534 bool fNewUp = enmState == PDMNETWORKLINKSTATE_UP;
535
536 if (fNewUp != pThis->fLnkUp)
537 {
538 if (fNewUp)
539 {
540 LogFlowFunc(("Link is up\n"));
541 pThis->fLnkUp = true;
542 }
543 else
544 {
545 LogFlowFunc(("Link is down\n"));
546 pThis->fLnkUp = false;
547 }
548 if (pThis->pDrv)
549 pThis->pDrv->pfnNotifyLinkChanged(pThis->pDrv, enmState);
550 }
551 return VINF_SUCCESS;
552}
553
554/* -=-=-=-=- PDMIBASE -=-=-=-=- */
555
556/**
557 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
558 */
559static DECLCALLBACK(void *) devINIPQueryInterface(PPDMIBASE pInterface,
560 const char *pszIID)
561{
562 PDEVINTNETIP pThis = RT_FROM_MEMBER(pInterface, DEVINTNETIP, IBase);
563 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
564 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKDOWN, &pThis->INetworkDown);
565 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThis->INetworkConfig);
566 return NULL;
567}
568
569/* -=-=-=-=- PDMDEVREG -=-=-=-=- */
570
571/**
572 * Destruct a device instance.
573 *
574 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
575 * resources can be freed correctly.
576 *
577 * @returns VBox status code.
578 * @param pDevIns The device instance data.
579 */
580static DECLCALLBACK(int) devINIPDestruct(PPDMDEVINS pDevIns)
581{
582 PDEVINTNETIP pThis = PDMINS_2_DATA(pDevIns, PDEVINTNETIP);
583
584 LogFlow(("%s: pDevIns=%p\n", __FUNCTION__, pDevIns));
585 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
586
587 if (g_pDevINIPData != NULL)
588 vboxLwipCoreFinalize(devINIPTcpipFiniDone, pThis);
589
590 MMR3HeapFree(pThis->pszIP);
591 pThis->pszIP = NULL;
592 MMR3HeapFree(pThis->pszNetmask);
593 pThis->pszNetmask = NULL;
594 MMR3HeapFree(pThis->pszGateway);
595 pThis->pszGateway = NULL;
596
597 LogFlow(("%s: success\n", __FUNCTION__));
598 return VINF_SUCCESS;
599}
600
601
602/**
603 * @interface_method_impl{PDMDEVREG,pfnConstruct}
604 */
605static DECLCALLBACK(int) devINIPConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
606{
607 PDEVINTNETIP pThis = PDMINS_2_DATA(pDevIns, PDEVINTNETIP);
608 int rc = VINF_SUCCESS;
609 err_t errRc = ERR_OK;
610
611 LogFlow(("%s: pDevIns=%p iInstance=%d pCfg=%p\n", __FUNCTION__,
612 pDevIns, iInstance, pCfg));
613
614 Assert(iInstance == 0);
615 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
616
617 /*
618 * Validate the config.
619 */
620 if (!CFGMR3AreValuesValid(pCfg, "MAC\0IP\0"
621 "IPv6\0"
622 "Netmask\0Gateway\0"))
623 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
624 N_("Unknown Internal Networking IP configuration option"));
625
626 /*
627 * Init the static parts.
628 */
629 pThis->pszIP = NULL;
630 pThis->pszNetmask = NULL;
631 pThis->pszGateway = NULL;
632 /* Pointer to device instance */
633 pThis->pDevIns = pDevIns;
634 /* IBase */
635 pThis->IBase.pfnQueryInterface = devINIPQueryInterface;
636 /* INetworkDown */
637 pThis->INetworkDown.pfnWaitReceiveAvail = devINIPNetworkDown_WaitInputAvail;
638 pThis->INetworkDown.pfnReceive = devINIPNetworkDown_Input;
639 pThis->INetworkDown.pfnXmitPending = devINIPNetworkDown_XmitPending;
640 /* INetworkConfig */
641 pThis->INetworkConfig.pfnGetMac = devINIPGetMac;
642 pThis->INetworkConfig.pfnGetLinkState = devINIPGetLinkState;
643 pThis->INetworkConfig.pfnSetLinkState = devINIPSetLinkState;
644
645 /*
646 * Get the configuration settings.
647 */
648 rc = CFGMR3QueryBytes(pCfg, "MAC", &pThis->MAC, sizeof(pThis->MAC));
649 if (rc == VERR_CFGM_NOT_BYTES)
650 {
651 char szMAC[64];
652 rc = CFGMR3QueryString(pCfg, "MAC", &szMAC[0], sizeof(szMAC));
653 if (RT_SUCCESS(rc))
654 {
655 char *macStr = &szMAC[0];
656 char *pMac = (char *)&pThis->MAC;
657 for (uint32_t i = 0; i < 6; i++)
658 {
659 if ( !*macStr || !*(macStr + 1)
660 || *macStr == ':' || *(macStr + 1) == ':')
661 return PDMDEV_SET_ERROR(pDevIns,
662 VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
663 N_("Configuration error: Invalid \"MAC\" value"));
664 char c1 = *macStr++ - '0';
665 if (c1 > 9)
666 c1 -= 7;
667 char c2 = *macStr++ - '0';
668 if (c2 > 9)
669 c2 -= 7;
670 *pMac++ = ((c1 & 0x0f) << 4) | (c2 & 0x0f);
671 if (i != 5 && *macStr == ':')
672 macStr++;
673 }
674 }
675 }
676 if (RT_FAILURE(rc))
677 return PDMDEV_SET_ERROR(pDevIns, rc,
678 N_("Configuration error: Failed to get the \"MAC\" value"));
679 rc = devINIPNetworkConfiguration(pDevIns, pThis, pCfg);
680 AssertLogRelRCReturn(rc, rc);
681
682 /*
683 * Attach driver and query the network connector interface.
684 */
685 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Network Port");
686 if (RT_FAILURE(rc))
687 {
688 pThis->pDrvBase = NULL;
689 pThis->pDrv = NULL;
690 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Error attaching device below us"));
691 }
692 pThis->pDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMINETWORKUP);
693 AssertMsgReturn(pThis->pDrv, ("Failed to obtain the PDMINETWORKUP interface!\n"), VERR_PDM_MISSING_INTERFACE_BELOW);
694
695
696 /*
697 * Set up global pointer to interface data.
698 */
699 g_pDevINIPData = pThis;
700
701
702 /* link hack */
703 pThis->pLinkHack = g_pDevINILinkHack;
704
705 /*
706 * Initialize lwIP.
707 */
708 vboxLwipCoreInitialize(devINIPTcpipInitDone, pThis);
709
710 /* this rc could be updated in devINIPTcpInitDone thread */
711 AssertRCReturn(pThis->rcInitialization, pThis->rcInitialization);
712
713
714 LogFlow(("%s: return %Rrc\n", __FUNCTION__, rc));
715 return rc;
716}
717
718
719/**
720 * Query whether lwIP is initialized or not. Since there is only a single
721 * instance of this device ever for a VM, it can be a global function.
722 *
723 * @returns True if lwIP is initialized.
724 */
725bool DevINIPConfigured(void)
726{
727 return g_pDevINIPData != NULL;
728}
729
730
731/**
732 * Internal network IP stack device registration record.
733 */
734const PDMDEVREG g_DeviceINIP =
735{
736 /* u32Version */
737 PDM_DEVREG_VERSION,
738 /* szName */
739 "IntNetIP",
740 /* szRCMod/szR0Mod */
741 "",
742 "",
743 /* pszDescription */
744 "Internal Network IP stack device",
745 /* fFlags */
746 PDM_DEVREG_FLAGS_DEFAULT_BITS,
747 /* fClass. As this is used by the storage devices, it must come earlier. */
748 PDM_DEVREG_CLASS_VMM_DEV,
749 /* cMaxInstances */
750 1,
751 /* cbInstance */
752 sizeof(DEVINTNETIP),
753 /* pfnConstruct */
754 devINIPConstruct,
755 /* pfnDestruct */
756 devINIPDestruct,
757 /* pfnRelocate */
758 NULL,
759 /* pfnMemSetup */
760 NULL,
761 /* pfnPowerOn */
762 NULL,
763 /* pfnReset */
764 NULL,
765 /* pfnSuspend */
766 NULL,
767 /* pfnResume */
768 NULL,
769 /* pfnAttach */
770 NULL,
771 /* pfnDetach */
772 NULL,
773 /* pfnQueryInterface */
774 NULL,
775 /* pfnInitComplete */
776 NULL,
777 /* pfnPowerOff */
778 NULL,
779 /* pfnSoftReset */
780 NULL,
781 /* u32VersionEnd */
782 PDM_DEVREG_VERSION
783};
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use