VirtualBox

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

Last change on this file was 109273, checked in by vboxsync, 7 days ago

Devices/{Network/DevINIP.cpp,Storage/DrvVD.cpp,Makefile.kmk}: Use the new lwip library, bugref:10899 [build fix]

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette