VirtualBox

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

Last change on this file since 46422 was 46132, checked in by vboxsync, 12 years ago

Access netif::ip6_autoconfig_enabled only #if LWIP_IPV6_AUTOCONFIG

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette