VirtualBox

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

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