VirtualBox

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

Last change on this file since 107876 was 107691, checked in by vboxsync, 6 weeks ago

Devices/Network/DevINIP.cpp: Remove unused variable, bugref:3409

  • 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 107691 2025-01-10 16:44:22Z 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 struct pbuf *p, *q;
338
339 LogFlow(("%s: pInterface=%p pvBuf=%p cb=%lu\n", __FUNCTION__, pInterface, pvBuf, cb));
340 Assert(g_pDevINIPData);
341 Assert(g_pDevINIPData->pDrv);
342
343 /* Silently ignore packets being received while lwIP isn't set up. */
344 if (!g_pDevINIPData)
345 {
346 LogFlow(("%s: return %Rrc (no global)\n", __FUNCTION__, VINF_SUCCESS));
347 return VINF_SUCCESS;
348 }
349
350#if ETH_PAD_SIZE
351 len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
352#endif
353
354 /* We allocate a pbuf chain of pbufs from the pool. */
355 Assert((u16_t)len == len);
356 p = lwip_pbuf_alloc(PBUF_RAW, (u16_t)len, PBUF_POOL);
357 if (p != NULL)
358 {
359#if ETH_PAD_SIZE
360 lwip_pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
361#endif
362
363 for (q = p; q != NULL; q = q->next)
364 {
365 /* Fill the buffers, and clean out unused buffer space. */
366 memcpy(q->payload, pbBuf, RT_MIN(cb, q->len));
367 pbBuf += RT_MIN(cb, q->len);
368 if (q->len > cb)
369 memset(((uint8_t *)q->payload) + cb, '\0', q->len - cb);
370 cb -= RT_MIN(cb, q->len);
371 }
372
373 struct netif *iface = &g_pDevINIPData->IntNetIF;
374
375 /* We've setup flags NETIF_FLAG_ETHARP and NETIF_FLAG_ETHERNET
376 so this should be thread-safe. */
377 tcpip_input(p,iface);
378 }
379
380 LogFlow(("%s: return %Rrc\n", __FUNCTION__, VINF_SUCCESS));
381 return VINF_SUCCESS;
382}
383
384/**
385 * @interface_method_impl{PDMINETWORKDOWN,pfnXmitPending}
386 */
387static DECLCALLBACK(void) devINIPNetworkDown_XmitPending(PPDMINETWORKDOWN pInterface)
388{
389 NOREF(pInterface);
390}
391
392
393/**
394 * Signals the end of lwIP TCPIP initialization.
395 *
396 * @param arg opaque argument, here the pointer to the PDEVINTNETIP.
397 * @note TCPIP thread, corresponding EMT waiting on semaphore.
398 */
399static DECLCALLBACK(void) devINIPTcpipInitDone(void *arg)
400{
401 PDEVINTNETIP pThis = (PDEVINTNETIP)arg;
402 AssertPtrReturnVoid(arg);
403
404 pThis->rcInitialization = VINF_SUCCESS;
405 struct in_addr ip;
406 if (!inet_aton(pThis->pszIP, &ip))
407 {
408 pThis->rcInitialization = VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
409 PDMDEV_SET_ERROR(pThis->pDevIns, pThis->rcInitialization, N_("Configuration error: Invalid \"IP\" value"));
410 return;
411 }
412 struct ip_addr ipaddr;
413 memcpy(&ipaddr, &ip, sizeof(ipaddr));
414
415 if (!inet_aton(pThis->pszNetmask, &ip))
416 {
417 pThis->rcInitialization = VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
418 PDMDEV_SET_ERROR(pThis->pDevIns, pThis->rcInitialization, N_("Configuration error: Invalid \"Netmask\" value"));
419 return;
420 }
421 struct ip_addr netmask;
422 memcpy(&netmask, &ip, sizeof(netmask));
423
424 if (pThis->pszGateway)
425 {
426 if (!inet_aton(pThis->pszGateway, &ip))
427 {
428 pThis->rcInitialization = VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
429 PDMDEV_SET_ERROR(pThis->pDevIns, pThis->rcInitialization, N_("Configuration error: Invalid \"Gateway\" value"));
430 return;
431 }
432 }
433 else
434 inet_aton(pThis->pszIP, &ip);
435 struct ip_addr gw;
436 memcpy(&gw, &ip, sizeof(gw));
437
438 pThis->IntNetIF.name[0] = 'I';
439 pThis->IntNetIF.name[1] = 'N';
440
441 struct netif *ret = netif_add(&pThis->IntNetIF, &ipaddr, &netmask, &gw, NULL, devINIPInterface, lwip_tcpip_input);
442 if (!ret)
443 {
444
445 pThis->rcInitialization = VERR_NET_NO_NETWORK;
446 PDMDEV_SET_ERROR(pThis->pDevIns, pThis->rcInitialization, N_("netif_add failed"));
447 return;
448 }
449
450 lwip_netif_set_default(&pThis->IntNetIF);
451 lwip_netif_set_up(&pThis->IntNetIF);
452}
453
454
455/**
456 * This callback is for finitializing our activity on TCPIP thread.
457 * @todo XXX: We do it only for new LWIP, old LWIP will stay broken for now.
458 */
459static DECLCALLBACK(void) devINIPTcpipFiniDone(void *arg)
460{
461 PDEVINTNETIP pThis = (PDEVINTNETIP)arg;
462 AssertPtrReturnVoid(arg);
463
464 netif_set_link_down(&pThis->IntNetIF);
465 netif_set_down(&pThis->IntNetIF);
466 netif_remove(&pThis->IntNetIF);
467}
468
469
470/**
471 * Gets the current Media Access Control (MAC) address.
472 *
473 * @returns VBox status code.
474 * @param pInterface Pointer to the interface structure containing the called function pointer.
475 * @param pMac Where to store the MAC address.
476 * @thread EMT
477 */
478static DECLCALLBACK(int) devINIPGetMac(PPDMINETWORKCONFIG pInterface, PRTMAC pMac)
479{
480 PDEVINTNETIP pThis = RT_FROM_MEMBER(pInterface, DEVINTNETIP, INetworkConfig);
481 memcpy(pMac, pThis->MAC.au8, sizeof(RTMAC));
482 return VINF_SUCCESS;
483}
484
485/**
486 * Gets the new link state.
487 *
488 * @returns The current link state.
489 * @param pInterface Pointer to the interface structure containing the called function pointer.
490 * @thread EMT
491 */
492static DECLCALLBACK(PDMNETWORKLINKSTATE) devINIPGetLinkState(PPDMINETWORKCONFIG pInterface)
493{
494 PDEVINTNETIP pThis = RT_FROM_MEMBER(pInterface, DEVINTNETIP, INetworkConfig);
495 if (pThis->fLnkUp)
496 return PDMNETWORKLINKSTATE_UP;
497 return PDMNETWORKLINKSTATE_DOWN;
498}
499
500
501/**
502 * Sets the new link state.
503 *
504 * @returns VBox status code.
505 * @param pInterface Pointer to the interface structure containing the called function pointer.
506 * @param enmState The new link state
507 */
508static DECLCALLBACK(int) devINIPSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
509{
510 PDEVINTNETIP pThis = RT_FROM_MEMBER(pInterface, DEVINTNETIP, INetworkConfig);
511 bool fNewUp = enmState == PDMNETWORKLINKSTATE_UP;
512
513 if (fNewUp != pThis->fLnkUp)
514 {
515 if (fNewUp)
516 {
517 LogFlowFunc(("Link is up\n"));
518 pThis->fLnkUp = true;
519 }
520 else
521 {
522 LogFlowFunc(("Link is down\n"));
523 pThis->fLnkUp = false;
524 }
525 if (pThis->pDrv)
526 pThis->pDrv->pfnNotifyLinkChanged(pThis->pDrv, enmState);
527 }
528 return VINF_SUCCESS;
529}
530
531/* -=-=-=-=- PDMIBASE -=-=-=-=- */
532
533/**
534 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
535 */
536static DECLCALLBACK(void *) devINIPQueryInterface(PPDMIBASE pInterface,
537 const char *pszIID)
538{
539 PDEVINTNETIP pThis = RT_FROM_MEMBER(pInterface, DEVINTNETIP, IBase);
540 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
541 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKDOWN, &pThis->INetworkDown);
542 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThis->INetworkConfig);
543 return NULL;
544}
545
546/* -=-=-=-=- PDMDEVREG -=-=-=-=- */
547
548/**
549 * Destruct a device instance.
550 *
551 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
552 * resources can be freed correctly.
553 *
554 * @returns VBox status code.
555 * @param pDevIns The device instance data.
556 */
557static DECLCALLBACK(int) devINIPDestruct(PPDMDEVINS pDevIns)
558{
559 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
560 LogFlow(("devINIPDestruct: pDevIns=%p\n", pDevIns));
561 PDEVINTNETIP pThis = PDMDEVINS_2_DATA(pDevIns, PDEVINTNETIP);
562
563 if (g_pDevINIPData != NULL)
564 vboxLwipCoreFinalize(devINIPTcpipFiniDone, pThis);
565
566 PDMDevHlpMMHeapFree(pDevIns, pThis->pszIP);
567 pThis->pszIP = NULL;
568 PDMDevHlpMMHeapFree(pDevIns, pThis->pszNetmask);
569 pThis->pszNetmask = NULL;
570 PDMDevHlpMMHeapFree(pDevIns, pThis->pszGateway);
571 pThis->pszGateway = NULL;
572
573 LogFlow(("%s: success\n", __FUNCTION__));
574 return VINF_SUCCESS;
575}
576
577
578/**
579 * @interface_method_impl{PDMDEVREG,pfnConstruct}
580 */
581static DECLCALLBACK(int) devINIPConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
582{
583 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
584 PDEVINTNETIP pThis = PDMDEVINS_2_DATA(pDevIns, PDEVINTNETIP);
585 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
586 LogFlow(("devINIPConstruct: pDevIns=%p iInstance=%d pCfg=%p\n", pDevIns, iInstance, pCfg));
587 RT_NOREF(iInstance);
588
589 Assert(iInstance == 0);
590
591 /*
592 * Init the static parts.
593 */
594 //pThis->pszIP = NULL;
595 //pThis->pszNetmask = NULL;
596 //pThis->pszGateway = NULL;
597 /* Pointer to device instance */
598 pThis->pDevIns = pDevIns;
599 /* IBase */
600 pThis->IBase.pfnQueryInterface = devINIPQueryInterface;
601 /* INetworkDown */
602 pThis->INetworkDown.pfnWaitReceiveAvail = devINIPNetworkDown_WaitInputAvail;
603 pThis->INetworkDown.pfnReceive = devINIPNetworkDown_Input;
604 pThis->INetworkDown.pfnXmitPending = devINIPNetworkDown_XmitPending;
605 /* INetworkConfig */
606 pThis->INetworkConfig.pfnGetMac = devINIPGetMac;
607 pThis->INetworkConfig.pfnGetLinkState = devINIPGetLinkState;
608 pThis->INetworkConfig.pfnSetLinkState = devINIPSetLinkState;
609
610
611 /*
612 * Validate the config.
613 */
614 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "MAC|IP|IPv6|Netmask|Gateway", "");
615
616 /*
617 * Get the configuration settings.
618 */
619 int rc = pHlp->pfnCFGMQueryBytes(pCfg, "MAC", &pThis->MAC, sizeof(pThis->MAC));
620 if (rc == VERR_CFGM_NOT_BYTES)
621 {
622 char szMAC[64];
623 rc = pHlp->pfnCFGMQueryString(pCfg, "MAC", &szMAC[0], sizeof(szMAC));
624 if (RT_SUCCESS(rc))
625 {
626 char *macStr = &szMAC[0];
627 char *pMac = (char *)&pThis->MAC;
628 for (uint32_t i = 0; i < 6; i++)
629 {
630 if (!*macStr || !macStr[1] || *macStr == ':' || macStr[1] == ':')
631 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
632 N_("Configuration error: Invalid \"MAC\" value"));
633 char c1 = *macStr++ - '0';
634 if (c1 > 9)
635 c1 -= 7;
636 char c2 = *macStr++ - '0';
637 if (c2 > 9)
638 c2 -= 7;
639 *pMac++ = ((c1 & 0x0f) << 4) | (c2 & 0x0f);
640 if (i != 5 && *macStr == ':')
641 macStr++;
642 }
643 }
644 }
645 if (RT_FAILURE(rc))
646 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"MAC\" value"));
647 rc = devINIPNetworkConfiguration(pDevIns, pThis, pCfg);
648 AssertLogRelRCReturn(rc, rc);
649
650 /*
651 * Attach driver and query the network connector interface.
652 */
653 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Network Port");
654 if (RT_FAILURE(rc))
655 {
656 pThis->pDrvBase = NULL;
657 pThis->pDrv = NULL;
658 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Error attaching device below us"));
659 }
660 pThis->pDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMINETWORKUP);
661 AssertMsgReturn(pThis->pDrv, ("Failed to obtain the PDMINETWORKUP interface!\n"), VERR_PDM_MISSING_INTERFACE_BELOW);
662
663
664 /*
665 * Set up global pointer to interface data.
666 */
667 g_pDevINIPData = pThis;
668
669
670 /* link hack */
671 pThis->pLinkHack = g_pDevINILinkHack;
672
673 /*
674 * Initialize lwIP.
675 */
676 vboxLwipCoreInitialize(devINIPTcpipInitDone, pThis);
677
678 /* this rc could be updated in devINIPTcpInitDone thread */
679 AssertRCReturn(pThis->rcInitialization, pThis->rcInitialization);
680
681
682 LogFlow(("devINIPConstruct: return %Rrc\n", rc));
683 return rc;
684}
685
686
687/**
688 * Query whether lwIP is initialized or not. Since there is only a single
689 * instance of this device ever for a VM, it can be a global function.
690 *
691 * @returns True if lwIP is initialized.
692 */
693bool DevINIPConfigured(void)
694{
695 return g_pDevINIPData != NULL;
696}
697
698
699/**
700 * Internal network IP stack device registration record.
701 */
702const PDMDEVREG g_DeviceINIP =
703{
704 /* .u32Version = */ PDM_DEVREG_VERSION,
705 /* .uReserved0 = */ 0,
706 /* .szName = */ "IntNetIP",
707 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_NEW_STYLE,
708 /* .fClass = */ PDM_DEVREG_CLASS_VMM_DEV, /* As this is used by the storage devices, it must come earlier. */
709 /* .cMaxInstances = */ 1,
710 /* .uSharedVersion = */ 42,
711 /* .cbInstanceShared = */ sizeof(DEVINTNETIP),
712 /* .cbInstanceCC = */ 0,
713 /* .cbInstanceRC = */ 0,
714 /* .cMaxPciDevices = */ 0,
715 /* .cMaxMsixVectors = */ 0,
716 /* .pszDescription = */ "Internal Network IP stack device",
717#if defined(IN_RING3)
718 /* .pszRCMod = */ "",
719 /* .pszR0Mod = */ "",
720 /* .pfnConstruct = */ devINIPConstruct,
721 /* .pfnDestruct = */ devINIPDestruct,
722 /* .pfnRelocate = */ NULL,
723 /* .pfnMemSetup = */ NULL,
724 /* .pfnPowerOn = */ NULL,
725 /* .pfnReset = */ NULL,
726 /* .pfnSuspend = */ NULL,
727 /* .pfnResume = */ NULL,
728 /* .pfnAttach = */ NULL,
729 /* .pfnDetach = */ NULL,
730 /* .pfnQueryInterface = */ NULL,
731 /* .pfnInitComplete = */ NULL,
732 /* .pfnPowerOff = */ NULL,
733 /* .pfnSoftReset = */ NULL,
734 /* .pfnReserved0 = */ NULL,
735 /* .pfnReserved1 = */ NULL,
736 /* .pfnReserved2 = */ NULL,
737 /* .pfnReserved3 = */ NULL,
738 /* .pfnReserved4 = */ NULL,
739 /* .pfnReserved5 = */ NULL,
740 /* .pfnReserved6 = */ NULL,
741 /* .pfnReserved7 = */ NULL,
742#elif defined(IN_RING0)
743 /* .pfnEarlyConstruct = */ NULL,
744 /* .pfnConstruct = */ NULL,
745 /* .pfnDestruct = */ NULL,
746 /* .pfnFinalDestruct = */ NULL,
747 /* .pfnRequest = */ NULL,
748 /* .pfnReserved0 = */ NULL,
749 /* .pfnReserved1 = */ NULL,
750 /* .pfnReserved2 = */ NULL,
751 /* .pfnReserved3 = */ NULL,
752 /* .pfnReserved4 = */ NULL,
753 /* .pfnReserved5 = */ NULL,
754 /* .pfnReserved6 = */ NULL,
755 /* .pfnReserved7 = */ NULL,
756#elif defined(IN_RC)
757 /* .pfnConstruct = */ NULL,
758 /* .pfnReserved0 = */ NULL,
759 /* .pfnReserved1 = */ NULL,
760 /* .pfnReserved2 = */ NULL,
761 /* .pfnReserved3 = */ NULL,
762 /* .pfnReserved4 = */ NULL,
763 /* .pfnReserved5 = */ NULL,
764 /* .pfnReserved6 = */ NULL,
765 /* .pfnReserved7 = */ NULL,
766#else
767# error "Not in IN_RING3, IN_RING0 or IN_RC!"
768#endif
769 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
770};
771
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