VirtualBox

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

Last change on this file since 55432 was 55432, checked in by vboxsync, 10 years ago

G/c VBOX_WITH_NEW_LWIP. This option only affects DevINIP/DrvVD (as
NAT Network always uses the new one) and it has been on since 4.3 was
released. Old lwip sources will be removed in a separate commit.

Same object code is produced modulo a few LINE changes.

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