VirtualBox

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

Last change on this file since 63185 was 62961, checked in by vboxsync, 8 years ago

Devices: warnings

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