VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use