VirtualBox

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

Last change on this file since 106129 was 106061, checked in by vboxsync, 2 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
Line 
1/* $Id: DevINIP.cpp 106061 2024-09-16 14:03:52Z 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.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
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#include "lwip/tcp_impl.h"
48# if LWIP_IPV6
49# include "ipv6/lwip/ethip6.h"
50# endif
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"
56RT_C_DECLS_END
57#include <VBox/vmm/pdmdev.h>
58#include <VBox/vmm/pdmnetifs.h>
59#include <VBox/vmm/tm.h>
60#include <iprt/assert.h>
61#include <iprt/string.h>
62#include <iprt/uuid.h>
63
64#include "VBoxDD.h"
65#include "VBoxLwipCore.h"
66
67
68/*********************************************************************************************************************************
69* Macros and Defines *
70*********************************************************************************************************************************/
71/** Maximum frame size this device can handle. */
72#define DEVINIP_MAX_FRAME 1514
73
74
75/*********************************************************************************************************************************
76* Structures and Typedefs *
77*********************************************************************************************************************************/
78/**
79 * Internal Network IP stack device instance data.
80 *
81 * @implements PDMIBASE
82 * @implements PDMINETWORKDOWN
83 */
84typedef struct DEVINTNETIP
85{
86 /** The base interface for LUN\#0. */
87 PDMIBASE IBase;
88 /** The network port this device provides (LUN\#0). */
89 PDMINETWORKDOWN INetworkDown;
90 /** The network configuration port this device provides (LUN\#0). */
91 PDMINETWORKCONFIG INetworkConfig;
92 /** The base interface of the network driver below us. */
93 PPDMIBASE pDrvBase;
94 /** The connector of the network driver below us. */
95 PPDMINETWORKUP pDrv;
96 /** Pointer to the device instance. */
97 PPDMDEVINSR3 pDevIns;
98 /** MAC address. */
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;
119 /** Flag whether the link is up. */
120 bool fLnkUp;
121 /**
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).
124 */
125 int rcInitialization;
126} DEVINTNETIP;
127/** Pointer to the instance data for an Internal Network IP stack. */
128typedef DEVINTNETIP *PDEVINTNETIP;
129
130
131/*********************************************************************************************************************************
132* Global Variables *
133*********************************************************************************************************************************/
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 */
143static const struct CLANG11WEIRDNESS { PFNRT pfn; } g_pDevINILinkHack[] =
144{
145 { (PFNRT)lwip_socket },
146 { (PFNRT)lwip_close },
147 { (PFNRT)lwip_setsockopt },
148 { (PFNRT)lwip_recv },
149 { (PFNRT)lwip_send },
150 { (PFNRT)lwip_select },
151};
152
153
154#if 0 /* unused */
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 */
164static err_t devINIPOutput(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr)
165{
166 err_t lrc;
167 LogFlow(("%s: netif=%p p=%p ipaddr=%#04x\n", __FUNCTION__, netif, p,
168 ipaddr->addr));
169
170 lrc = lwip_etharp_output(netif, p, ipaddr);
171
172 LogFlow(("%s: return %d\n", __FUNCTION__, lrc));
173 return lrc;
174}
175#endif
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 */
184static err_t devINIPOutputRaw(struct netif *netif, struct pbuf *p)
185{
186 NOREF(netif);
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. */
194 if (g_pDevINIPData)
195 {
196 PPDMSCATTERGATHER pSgBuf;
197
198 rc = g_pDevINIPData->pDrv->pfnBeginXmit(g_pDevINIPData->pDrv, true /* fOnWorkerThread */);
199 if (RT_FAILURE(rc))
200 return ERR_IF;
201
202 rc = g_pDevINIPData->pDrv->pfnAllocBuf(g_pDevINIPData->pDrv, DEVINIP_MAX_FRAME, NULL /*pGso*/, &pSgBuf);
203 if (RT_SUCCESS(rc))
204 {
205#if ETH_PAD_SIZE
206 lwip_pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
207#endif
208
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)
229 {
230 pSgBuf->cbUsed = cbBuf;
231 rc = g_pDevINIPData->pDrv->pfnSendBuf(g_pDevINIPData->pDrv, pSgBuf, true /* fOnWorkerThread */);
232 }
233 else
234 rc = g_pDevINIPData->pDrv->pfnFreeBuf(g_pDevINIPData->pDrv, pSgBuf);
235
236#if ETH_PAD_SIZE
237 lwip_pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
238#endif
239 }
240
241 g_pDevINIPData->pDrv->pfnEndXmit(g_pDevINIPData->pDrv);
242 }
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 */
257static err_t devINIPInterface(struct netif *netif) RT_NOTHROW_DEF
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;
266 netif->flags |= NETIF_FLAG_ETHARP;
267 netif->flags |= NETIF_FLAG_ETHERNET;
268
269#if LWIP_IPV6
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]));
275#endif
276
277 netif->output = lwip_etharp_output;
278 netif->linkoutput = devINIPOutputRaw;
279
280 LogFlow(("%s: success\n", __FUNCTION__));
281 return ERR_OK;
282}
283
284/**
285 * Parses CFGM parameters related to network connection
286 */
287static DECLCALLBACK(int) devINIPNetworkConfiguration(PPDMDEVINS pDevIns, PDEVINTNETIP pThis, PCFGMNODE pCfg)
288{
289 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
290
291 int rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "IP", &pThis->pszIP);
292 if (RT_FAILURE(rc))
293 /** @todo perhaps we should panic if IPv4 address isn't specify, with assumtion that
294 * ISCSI target specified in IPv6 form. */
295 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"IP\" value"));
296
297 rc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "Netmask", &pThis->pszNetmask);
298 if (RT_FAILURE(rc))
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);
302 if ( RT_FAILURE(rc)
303 && rc != VERR_CFGM_VALUE_NOT_FOUND)
304 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"Gateway\" value"));
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 * @param arg opaque argument, here the pointer to the PDEVINTNETIP.
399 * @note TCPIP thread, corresponding EMT waiting on semaphore.
400 */
401static DECLCALLBACK(void) devINIPTcpipInitDone(void *arg)
402{
403 PDEVINTNETIP pThis = (PDEVINTNETIP)arg;
404 AssertPtrReturnVoid(arg);
405
406 pThis->rcInitialization = VINF_SUCCESS;
407 struct in_addr ip;
408 if (!inet_aton(pThis->pszIP, &ip))
409 {
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));
416
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));
425
426 if (pThis->pszGateway)
427 {
428 if (!inet_aton(pThis->pszGateway, &ip))
429 {
430 pThis->rcInitialization = VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
431 PDMDEV_SET_ERROR(pThis->pDevIns, pThis->rcInitialization, N_("Configuration error: Invalid \"Gateway\" value"));
432 return;
433 }
434 }
435 else
436 inet_aton(pThis->pszIP, &ip);
437 struct ip_addr gw;
438 memcpy(&gw, &ip, sizeof(gw));
439
440 pThis->IntNetIF.name[0] = 'I';
441 pThis->IntNetIF.name[1] = 'N';
442
443 struct netif *ret = netif_add(&pThis->IntNetIF, &ipaddr, &netmask, &gw, NULL, devINIPInterface, lwip_tcpip_input);
444 if (!ret)
445 {
446
447 pThis->rcInitialization = VERR_NET_NO_NETWORK;
448 PDMDEV_SET_ERROR(pThis->pDevIns, pThis->rcInitialization, N_("netif_add failed"));
449 return;
450 }
451
452 lwip_netif_set_default(&pThis->IntNetIF);
453 lwip_netif_set_up(&pThis->IntNetIF);
454}
455
456
457/**
458 * This callback is for finitializing our activity on TCPIP thread.
459 * @todo XXX: We do it only for new LWIP, old LWIP will stay broken for now.
460 */
461static DECLCALLBACK(void) devINIPTcpipFiniDone(void *arg)
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}
470
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
533/* -=-=-=-=- PDMIBASE -=-=-=-=- */
534
535/**
536 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
537 */
538static DECLCALLBACK(void *) devINIPQueryInterface(PPDMIBASE pInterface,
539 const char *pszIID)
540{
541 PDEVINTNETIP pThis = RT_FROM_MEMBER(pInterface, DEVINTNETIP, IBase);
542 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
543 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKDOWN, &pThis->INetworkDown);
544 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThis->INetworkConfig);
545 return NULL;
546}
547
548/* -=-=-=-=- PDMDEVREG -=-=-=-=- */
549
550/**
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 *
556 * @returns VBox status code.
557 * @param pDevIns The device instance data.
558 */
559static DECLCALLBACK(int) devINIPDestruct(PPDMDEVINS pDevIns)
560{
561 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
562 LogFlow(("devINIPDestruct: pDevIns=%p\n", pDevIns));
563 PDEVINTNETIP pThis = PDMDEVINS_2_DATA(pDevIns, PDEVINTNETIP);
564
565 if (g_pDevINIPData != NULL)
566 vboxLwipCoreFinalize(devINIPTcpipFiniDone, pThis);
567
568 PDMDevHlpMMHeapFree(pDevIns, pThis->pszIP);
569 pThis->pszIP = NULL;
570 PDMDevHlpMMHeapFree(pDevIns, pThis->pszNetmask);
571 pThis->pszNetmask = NULL;
572 PDMDevHlpMMHeapFree(pDevIns, pThis->pszGateway);
573 pThis->pszGateway = NULL;
574
575 LogFlow(("%s: success\n", __FUNCTION__));
576 return VINF_SUCCESS;
577}
578
579
580/**
581 * @interface_method_impl{PDMDEVREG,pfnConstruct}
582 */
583static DECLCALLBACK(int) devINIPConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
584{
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));
589 RT_NOREF(iInstance);
590
591 Assert(iInstance == 0);
592
593 /*
594 * Init the static parts.
595 */
596 //pThis->pszIP = NULL;
597 //pThis->pszNetmask = NULL;
598 //pThis->pszGateway = NULL;
599 /* Pointer to device instance */
600 pThis->pDevIns = pDevIns;
601 /* IBase */
602 pThis->IBase.pfnQueryInterface = devINIPQueryInterface;
603 /* INetworkDown */
604 pThis->INetworkDown.pfnWaitReceiveAvail = devINIPNetworkDown_WaitInputAvail;
605 pThis->INetworkDown.pfnReceive = devINIPNetworkDown_Input;
606 pThis->INetworkDown.pfnXmitPending = devINIPNetworkDown_XmitPending;
607 /* INetworkConfig */
608 pThis->INetworkConfig.pfnGetMac = devINIPGetMac;
609 pThis->INetworkConfig.pfnGetLinkState = devINIPGetLinkState;
610 pThis->INetworkConfig.pfnSetLinkState = devINIPSetLinkState;
611
612
613 /*
614 * Validate the config.
615 */
616 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "MAC|IP|IPv6|Netmask|Gateway", "");
617
618 /*
619 * Get the configuration settings.
620 */
621 int rc = pHlp->pfnCFGMQueryBytes(pCfg, "MAC", &pThis->MAC, sizeof(pThis->MAC));
622 if (rc == VERR_CFGM_NOT_BYTES)
623 {
624 char szMAC[64];
625 rc = pHlp->pfnCFGMQueryString(pCfg, "MAC", &szMAC[0], sizeof(szMAC));
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 {
632 if (!*macStr || !macStr[1] || *macStr == ':' || macStr[1] == ':')
633 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
634 N_("Configuration error: Invalid \"MAC\" value"));
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))
648 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"MAC\" value"));
649 rc = devINIPNetworkConfiguration(pDevIns, pThis, pCfg);
650 AssertLogRelRCReturn(rc, rc);
651
652 /*
653 * Attach driver and query the network connector interface.
654 */
655 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Network Port");
656 if (RT_FAILURE(rc))
657 {
658 pThis->pDrvBase = NULL;
659 pThis->pDrv = NULL;
660 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Error attaching device below us"));
661 }
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);
664
665
666 /*
667 * Set up global pointer to interface data.
668 */
669 g_pDevINIPData = pThis;
670
671
672 /* link hack */
673 pThis->pLinkHack = g_pDevINILinkHack;
674
675 /*
676 * Initialize lwIP.
677 */
678 vboxLwipCoreInitialize(devINIPTcpipInitDone, pThis);
679
680 /* this rc could be updated in devINIPTcpInitDone thread */
681 AssertRCReturn(pThis->rcInitialization, pThis->rcInitialization);
682
683
684 LogFlow(("devINIPConstruct: return %Rrc\n", rc));
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{
706 /* .u32Version = */ PDM_DEVREG_VERSION,
707 /* .uReserved0 = */ 0,
708 /* .szName = */ "IntNetIP",
709 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_NEW_STYLE,
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,
716 /* .cMaxPciDevices = */ 0,
717 /* .cMaxMsixVectors = */ 0,
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
772};
773
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