VirtualBox

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

Last change on this file since 81428 was 80704, checked in by vboxsync, 5 years ago

PDM,Devices: Changed PDM_DEVREG_FLAGS_MSI_X into a registration field giving the max MSI-X vector count config for the device (typically VBOX_MSIX_MAX_ENTRIES). bugref:9218

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