VirtualBox

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

Last change on this file since 44124 was 43924, checked in by vboxsync, 12 years ago

DevINIP: IPv6 and new LWIP introduction.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.2 KB
Line 
1/* $Id: DevINIP.cpp 43924 2012-11-21 09:05:59Z vboxsync $ */
2/** @file
3 * DevINIP - Internal Network IP stack device/service.
4 */
5
6/*
7 * Copyright (C) 2007-2009 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 /** Flag whether the configuration is IPv6 */
115 bool fIpv6;
116 /** Static IPv6 address of the interface. */
117 char *pszIP6;
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 DECLCALLBACK(void) devINIPARPTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer);
149static DECLCALLBACK(void) devINIPTCPFastTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer);
150static DECLCALLBACK(void) devINIPTCPSlowTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer);
151static DECLCALLBACK(err_t) devINIPOutput(struct netif *netif, struct pbuf *p,
152 struct ip_addr *ipaddr);
153static DECLCALLBACK(err_t) devINIPOutputRaw(struct netif *netif,
154 struct pbuf *p);
155static DECLCALLBACK(err_t) devINIPInterface(struct netif *netif);
156
157/**
158 * ARP cache timeout handling for lwIP.
159 *
160 * @param pDevIns Device instance.
161 * @param pTimer Pointer to timer.
162 */
163static DECLCALLBACK(void) devINIPARPTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
164{
165 PDEVINTNETIP pThis = (PDEVINTNETIP)pvUser;
166 LogFlow(("%s: pDevIns=%p pTimer=%p\n", __FUNCTION__, pDevIns, pTimer));
167 lwip_etharp_tmr();
168 TMTimerSetMillies(pThis->ARPTimer, ARP_TMR_INTERVAL);
169 LogFlow(("%s: return\n", __FUNCTION__));
170}
171
172/**
173 * TCP fast timer handling for lwIP.
174 *
175 * @param pDevIns Device instance.
176 * @param pTimer Pointer to timer.
177 */
178static DECLCALLBACK(void) devINIPTCPFastTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
179{
180 PDEVINTNETIP pThis = (PDEVINTNETIP)pvUser;
181 LogFlow(("%s: pDevIns=%p pTimer=%p\n", __FUNCTION__, pDevIns, pTimer));
182 lwip_tcp_fasttmr();
183 TMTimerSetMillies(pThis->TCPFastTimer, TCP_FAST_INTERVAL);
184 LogFlow(("%s: return\n", __FUNCTION__));
185}
186
187/**
188 * TCP slow timer handling for lwIP.
189 *
190 * @param pDevIns Device instance.
191 * @param pTimer Pointer to timer.
192 */
193static DECLCALLBACK(void) devINIPTCPSlowTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
194{
195 PDEVINTNETIP pThis = (PDEVINTNETIP)pvUser;
196 LogFlow(("%s: pDevIns=%p pTimer=%p\n", __FUNCTION__, pDevIns, pTimer));
197 lwip_tcp_slowtmr();
198 TMTimerSetMillies(pThis->TCPSlowTimer, TCP_SLOW_INTERVAL);
199 LogFlow(("%s: return\n", __FUNCTION__));
200}
201
202/**
203 * Output a TCP/IP packet on the interface. Uses the generic lwIP ARP
204 * code to resolve the address and call the link-level packet function.
205 *
206 * @returns lwIP error code
207 * @param netif Interface on which to send IP packet.
208 * @param p Packet data.
209 * @param ipaddr Destination IP address.
210 */
211static DECLCALLBACK(err_t) devINIPOutput(struct netif *netif, struct pbuf *p,
212 struct ip_addr *ipaddr)
213{
214 err_t lrc;
215 LogFlow(("%s: netif=%p p=%p ipaddr=%#04x\n", __FUNCTION__, netif, p,
216 ipaddr->addr));
217#ifndef VBOX_WITH_NEW_LWIP
218 lrc = lwip_etharp_output(netif, ipaddr, p);
219#else
220 lrc = lwip_etharp_output(netif, p, ipaddr);
221#endif
222 LogFlow(("%s: return %d\n", __FUNCTION__, lrc));
223 return lrc;
224}
225
226/**
227 * Output a raw packet on the interface.
228 *
229 * @returns lwIP error code
230 * @param netif Interface on which to send frame.
231 * @param p Frame data.
232 */
233static DECLCALLBACK(err_t) devINIPOutputRaw(struct netif *netif,
234 struct pbuf *p)
235{
236 int rc = VINF_SUCCESS;
237
238 LogFlow(("%s: netif=%p p=%p\n", __FUNCTION__, netif, p));
239 Assert(g_pDevINIPData);
240 Assert(g_pDevINIPData->pDrv);
241
242 /* Silently ignore packets being sent while lwIP isn't set up. */
243 if (g_pDevINIPData)
244 {
245 PPDMSCATTERGATHER pSgBuf;
246
247 rc = g_pDevINIPData->pDrv->pfnBeginXmit(g_pDevINIPData->pDrv, true /* fOnWorkerThread */);
248 if (RT_FAILURE(rc))
249 return ERR_IF;
250
251 rc = g_pDevINIPData->pDrv->pfnAllocBuf(g_pDevINIPData->pDrv, DEVINIP_MAX_FRAME, NULL /*pGso*/, &pSgBuf);
252 if (RT_SUCCESS(rc))
253 {
254#if ETH_PAD_SIZE
255 lwip_pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
256#endif
257
258 uint8_t *pbBuf = pSgBuf ? (uint8_t *)pSgBuf->aSegs[0].pvSeg : NULL;
259 size_t cbBuf = 0;
260 for (struct pbuf *q = p; q != NULL; q = q->next)
261 {
262 if (cbBuf + q->len <= DEVINIP_MAX_FRAME)
263 {
264 if (RT_LIKELY(pbBuf))
265 {
266 memcpy(pbBuf, q->payload, q->len);
267 pbBuf += q->len;
268 }
269 cbBuf += q->len;
270 }
271 else
272 {
273 LogRel(("INIP: exceeded frame size\n"));
274 break;
275 }
276 }
277 if (cbBuf)
278 {
279 pSgBuf->cbUsed = cbBuf;
280 rc = g_pDevINIPData->pDrv->pfnSendBuf(g_pDevINIPData->pDrv, pSgBuf, true /* fOnWorkerThread */);
281 }
282 else
283 rc = g_pDevINIPData->pDrv->pfnFreeBuf(g_pDevINIPData->pDrv, pSgBuf);
284
285#if ETH_PAD_SIZE
286 lwip_pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
287#endif
288 }
289
290 g_pDevINIPData->pDrv->pfnEndXmit(g_pDevINIPData->pDrv);
291 }
292
293 err_t lrc = ERR_OK;
294 if (RT_FAILURE(rc))
295 lrc = ERR_IF;
296 LogFlow(("%s: return %d (vbox: %Rrc)\n", __FUNCTION__, rc, lrc));
297 return lrc;
298}
299
300/**
301 * Implements the ethernet interface backend initialization for lwIP.
302 *
303 * @returns lwIP error code
304 * @param netif Interface to configure.
305 */
306static DECLCALLBACK(err_t) devINIPInterface(struct netif *netif)
307{
308 LogFlow(("%s: netif=%p\n", __FUNCTION__, netif));
309 Assert(g_pDevINIPData != NULL);
310 netif->state = g_pDevINIPData;
311 netif->hwaddr_len = sizeof(g_pDevINIPData->MAC);
312 memcpy(netif->hwaddr, &g_pDevINIPData->MAC, sizeof(g_pDevINIPData->MAC));
313 netif->mtu = DEVINIP_MAX_FRAME;
314 netif->flags = NETIF_FLAG_BROADCAST;
315#ifdef VBOX_WITH_NEW_LWIP
316 /* @todo: why explicit ARP routing required for 1.2.0 case? */
317 netif->flags |= NETIF_FLAG_ETHARP;
318 netif->flags |= NETIF_FLAG_ETHERNET;
319 if (g_pDevINIPData->fIpv6)
320 {
321 /* @todo: Don't bother user with entering IPv6 address explicitly,
322 * instead what is required here that IPv6 local-address generation ?
323 */
324 if (!inet6_aton(g_pDevINIPData->pszIP6, &netif->ip6_addr[0]))
325 {
326 PDMDEV_SET_ERROR(g_pDevINIPData->pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
327 N_("Configuration error: Invalid \"IPv6\" value"));
328 return ERR_IF;
329 }
330 netif_ip6_addr_set_state(netif, 0, IP6_ADDR_VALID);
331 netif->output_ip6 = ethip6_output;
332 netif->ip6_autoconfig_enabled=1;
333 }
334 else
335 netif->output = lwip_etharp_output;
336
337#else
338 netif->output = devINIPOutput;
339#endif
340 netif->linkoutput = devINIPOutputRaw;
341
342 lwip_etharp_init();
343 TMTimerSetMillies(g_pDevINIPData->ARPTimer, ARP_TMR_INTERVAL);
344 LogFlow(("%s: success\n", __FUNCTION__));
345 return ERR_OK;
346}
347
348/**
349 * Parses CFGM parameters related to network connection
350 */
351static DECLCALLBACK(int) devINIPNetworkConfiguration(PPDMDEVINS pDevIns, PDEVINTNETIP pThis, PCFGMNODE pCfg)
352{
353 int rc = VINF_SUCCESS;
354 rc = CFGMR3QueryStringAlloc(pCfg, "IP", &pThis->pszIP);
355 if (RT_FAILURE(rc))
356 {
357 PDMDEV_SET_ERROR(pDevIns, rc,
358 N_("Configuration error: Failed to get the \"IP\" value"));
359 return rc;
360 }
361#ifdef VBOX_WITH_NEW_LWIP
362 rc = CFGMR3QueryStringAlloc(pCfg, "IPv6", &pThis->pszIP6);
363 if (RT_SUCCESS(rc))
364 pThis->fIpv6 = true;
365 else if (rc != VERR_CFGM_VALUE_NOT_FOUND)
366 {
367 PDMDEV_SET_ERROR(pDevIns, rc,
368 N_("Configuration error: Failed to get the \"IPv6\" value"));
369 AssertReturn(rc, rc);
370 }
371#endif
372 rc = CFGMR3QueryStringAlloc(pCfg, "Netmask", &pThis->pszNetmask);
373 if (RT_FAILURE(rc))
374 {
375 PDMDEV_SET_ERROR(pDevIns, rc,
376 N_("Configuration error: Failed to get the \"Netmask\" value"));
377 return rc;
378 }
379 rc = CFGMR3QueryStringAlloc(pCfg, "Gateway", &pThis->pszGateway);
380 if ( RT_FAILURE(rc)
381 && rc != VERR_CFGM_VALUE_NOT_FOUND)
382 {
383 PDMDEV_SET_ERROR(pDevIns, rc,
384 N_("Configuration error: Failed to get the \"Gateway\" value"));
385 return rc;
386 }
387 return VINF_SUCCESS;
388}
389
390/**
391 * Wait until data can be received.
392 *
393 * @returns VBox status code. VINF_SUCCESS means there is at least one receive descriptor available.
394 * @param pInterface PDM network port interface pointer.
395 * @param cMillies Number of milliseconds to wait. 0 means return immediately.
396 */
397static DECLCALLBACK(int) devINIPNetworkDown_WaitInputAvail(PPDMINETWORKDOWN pInterface, RTMSINTERVAL cMillies)
398{
399 LogFlow(("%s: pInterface=%p\n", __FUNCTION__, pInterface));
400 LogFlow(("%s: return VINF_SUCCESS\n", __FUNCTION__));
401 return VINF_SUCCESS;
402}
403
404/**
405 * Receive data and pass it to lwIP for processing.
406 *
407 * @returns VBox status code
408 * @param pInterface PDM network port interface pointer.
409 * @param pvBuf Pointer to frame data.
410 * @param cb Frame size.
411 */
412static DECLCALLBACK(int) devINIPNetworkDown_Input(PPDMINETWORKDOWN pInterface,
413 const void *pvBuf, size_t cb)
414{
415 const uint8_t *pbBuf = (const uint8_t *)pvBuf;
416 size_t len = cb;
417 const struct eth_hdr *ethhdr;
418 struct pbuf *p, *q;
419 int rc = VINF_SUCCESS;
420
421 LogFlow(("%s: pInterface=%p pvBuf=%p cb=%lu\n", __FUNCTION__, pInterface,
422 pvBuf, cb));
423 Assert(g_pDevINIPData);
424 Assert(g_pDevINIPData->pDrv);
425
426 /* Silently ignore packets being received while lwIP isn't set up. */
427 if (!g_pDevINIPData)
428 goto out;
429
430#if ETH_PAD_SIZE
431 len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
432#endif
433
434 /* We allocate a pbuf chain of pbufs from the pool. */
435 p = lwip_pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
436 if (p != NULL)
437 {
438#if ETH_PAD_SIZE
439 lwip_pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
440#endif
441
442 for (q = p; q != NULL; q = q->next)
443 {
444 /* Fill the buffers, and clean out unused buffer space. */
445 memcpy(q->payload, pbBuf, RT_MIN(cb, q->len));
446 pbBuf += RT_MIN(cb, q->len);
447 if (q->len > cb)
448 memset(((uint8_t *)q->payload) + cb, '\0', q->len - cb);
449 cb -= RT_MIN(cb, q->len);
450 }
451
452 ethhdr = (const struct eth_hdr *)p->payload;
453 struct netif *iface = &g_pDevINIPData->IntNetIF;
454 err_t lrc;
455#ifndef VBOX_WITH_NEW_LWIP
456 switch (htons(ethhdr->type))
457 {
458 case ETHTYPE_IP: /* IP packet */
459 lwip_pbuf_header(p, -(ssize_t)sizeof(struct eth_hdr));
460 lrc = iface->input(p, iface);
461 if (lrc)
462 rc = VERR_NET_IO_ERROR;
463 break;
464 case ETHTYPE_ARP: /* ARP packet */
465 lwip_etharp_arp_input(iface, (struct eth_addr *)iface->hwaddr, p);
466 break;
467 default:
468 lwip_pbuf_free(p);
469 }
470#else
471 /* We've setup flags NETIF_FLAG_ETHARP and NETIF_FLAG_ETHERNET
472 * so this should be thread-safe.
473 */
474 tcpip_input(p,iface);
475#endif
476 }
477
478out:
479 LogFlow(("%s: return %Rrc\n", __FUNCTION__, rc));
480 return rc;
481}
482
483/**
484 * @interface_method_impl{PDMINETWORKDOWN,pfnXmitPending}
485 */
486static DECLCALLBACK(void) devINIPNetworkDown_XmitPending(PPDMINETWORKDOWN pInterface)
487{
488 NOREF(pInterface);
489}
490
491
492/**
493 * Signals the end of lwIP TCPIP initialization.
494 *
495 * @param arg opaque argument, here the pointer to the semaphore.
496 */
497static DECLCALLBACK(void) devINIPTcpipInitDone(void *arg)
498{
499 sys_sem_t *sem = (sys_sem_t *)arg;
500#ifndef VBOX_WITH_NEW_LWIP
501 lwip_sys_sem_signal(*sem);
502#else
503 lwip_sys_sem_signal(sem);
504#endif
505}
506
507
508/**
509 * Gets the current Media Access Control (MAC) address.
510 *
511 * @returns VBox status code.
512 * @param pInterface Pointer to the interface structure containing the called function pointer.
513 * @param pMac Where to store the MAC address.
514 * @thread EMT
515 */
516static DECLCALLBACK(int) devINIPGetMac(PPDMINETWORKCONFIG pInterface, PRTMAC pMac)
517{
518 PDEVINTNETIP pThis = RT_FROM_MEMBER(pInterface, DEVINTNETIP, INetworkConfig);
519 memcpy(pMac, pThis->MAC.au8, sizeof(RTMAC));
520 return VINF_SUCCESS;
521}
522
523/**
524 * Gets the new link state.
525 *
526 * @returns The current link state.
527 * @param pInterface Pointer to the interface structure containing the called function pointer.
528 * @thread EMT
529 */
530static DECLCALLBACK(PDMNETWORKLINKSTATE) devINIPGetLinkState(PPDMINETWORKCONFIG pInterface)
531{
532 PDEVINTNETIP pThis = RT_FROM_MEMBER(pInterface, DEVINTNETIP, INetworkConfig);
533 if (pThis->fLnkUp)
534 return PDMNETWORKLINKSTATE_UP;
535 return PDMNETWORKLINKSTATE_DOWN;
536}
537
538
539/**
540 * Sets the new link state.
541 *
542 * @returns VBox status code.
543 * @param pInterface Pointer to the interface structure containing the called function pointer.
544 * @param enmState The new link state
545 */
546static DECLCALLBACK(int) devINIPSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
547{
548 PDEVINTNETIP pThis = RT_FROM_MEMBER(pInterface, DEVINTNETIP, INetworkConfig);
549 bool fNewUp = enmState == PDMNETWORKLINKSTATE_UP;
550
551 if (fNewUp != pThis->fLnkUp)
552 {
553 if (fNewUp)
554 {
555 LogFlowFunc(("Link is up\n"));
556 pThis->fLnkUp = true;
557 }
558 else
559 {
560 LogFlowFunc(("Link is down\n"));
561 pThis->fLnkUp = false;
562 }
563 if (pThis->pDrv)
564 pThis->pDrv->pfnNotifyLinkChanged(pThis->pDrv, enmState);
565 }
566 return VINF_SUCCESS;
567}
568
569/* -=-=-=-=- PDMIBASE -=-=-=-=- */
570
571/**
572 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
573 */
574static DECLCALLBACK(void *) devINIPQueryInterface(PPDMIBASE pInterface,
575 const char *pszIID)
576{
577 PDEVINTNETIP pThis = RT_FROM_MEMBER(pInterface, DEVINTNETIP, IBase);
578 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
579 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKDOWN, &pThis->INetworkDown);
580 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThis->INetworkConfig);
581 return NULL;
582}
583
584/* -=-=-=-=- PDMDEVREG -=-=-=-=- */
585
586/**
587 * Destruct a device instance.
588 *
589 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
590 * resources can be freed correctly.
591 *
592 * @returns VBox status.
593 * @param pDevIns The device instance data.
594 */
595static DECLCALLBACK(int) devINIPDestruct(PPDMDEVINS pDevIns)
596{
597 PDEVINTNETIP pThis = PDMINS_2_DATA(pDevIns, PDEVINTNETIP);
598
599 LogFlow(("%s: pDevIns=%p\n", __FUNCTION__, pDevIns));
600 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
601
602 if (g_pDevINIPData != NULL)
603 {
604 netif_set_down(&pThis->IntNetIF);
605 netif_remove(&pThis->IntNetIF);
606 tcpip_terminate();
607#ifndef VBOX_WITH_NEW_LWIP
608 lwip_sys_sem_wait(pThis->LWIPTcpInitSem);
609 lwip_sys_sem_free(pThis->LWIPTcpInitSem);
610#else
611 lwip_sys_sem_wait(&pThis->LWIPTcpInitSem, 0);
612 lwip_sys_sem_free(&pThis->LWIPTcpInitSem);
613#endif
614 }
615
616 if (pThis->pszIP)
617 MMR3HeapFree(pThis->pszIP);
618 if (pThis->pszNetmask)
619 MMR3HeapFree(pThis->pszNetmask);
620 if (pThis->pszGateway)
621 MMR3HeapFree(pThis->pszGateway);
622
623 LogFlow(("%s: success\n", __FUNCTION__));
624 return VINF_SUCCESS;
625}
626
627
628/**
629 * @interface_method_impl{PDMDEVREG,pfnConstruct}
630 */
631static DECLCALLBACK(int) devINIPConstruct(PPDMDEVINS pDevIns, int iInstance,
632 PCFGMNODE pCfg)
633{
634 PDEVINTNETIP pThis = PDMINS_2_DATA(pDevIns, PDEVINTNETIP);
635 int rc = VINF_SUCCESS;
636#ifdef VBOX_WITH_NEW_LWIP
637 err_t errRc = ERR_OK;
638#endif
639 LogFlow(("%s: pDevIns=%p iInstance=%d pCfg=%p\n", __FUNCTION__,
640 pDevIns, iInstance, pCfg));
641
642 Assert(iInstance == 0);
643 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
644
645 /*
646 * Validate the config.
647 */
648 if (!CFGMR3AreValuesValid(pCfg, "MAC\0IP\0"
649#ifdef VBOX_WITH_NEW_LWIP
650 "IPv6\0"
651#endif
652 "Netmask\0Gateway\0"))
653 {
654 rc = PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
655 N_("Unknown Internal Networking IP configuration option"));
656 goto out;
657 }
658
659 /*
660 * Init the static parts.
661 */
662 pThis->pszIP = NULL;
663 pThis->pszNetmask = NULL;
664 pThis->pszGateway = NULL;
665 /* Pointer to device instance */
666 pThis->pDevIns = pDevIns;
667 /* IBase */
668 pThis->IBase.pfnQueryInterface = devINIPQueryInterface;
669 /* INetworkDown */
670 pThis->INetworkDown.pfnWaitReceiveAvail = devINIPNetworkDown_WaitInputAvail;
671 pThis->INetworkDown.pfnReceive = devINIPNetworkDown_Input;
672 pThis->INetworkDown.pfnXmitPending = devINIPNetworkDown_XmitPending;
673 /* INetworkConfig */
674 pThis->INetworkConfig.pfnGetMac = devINIPGetMac;
675 pThis->INetworkConfig.pfnGetLinkState = devINIPGetLinkState;
676 pThis->INetworkConfig.pfnSetLinkState = devINIPSetLinkState;
677
678 /*
679 * Get the configuration settings.
680 */
681 rc = CFGMR3QueryBytes(pCfg, "MAC", &pThis->MAC, sizeof(pThis->MAC));
682 if (rc == VERR_CFGM_NOT_BYTES)
683 {
684 char szMAC[64];
685 rc = CFGMR3QueryString(pCfg, "MAC", &szMAC[0], sizeof(szMAC));
686 if (RT_SUCCESS(rc))
687 {
688 char *macStr = &szMAC[0];
689 char *pMac = (char *)&pThis->MAC;
690 for (uint32_t i = 0; i < 6; i++)
691 {
692 if ( !*macStr || !*(macStr + 1)
693 || *macStr == ':' || *(macStr + 1) == ':')
694 {
695 rc = PDMDEV_SET_ERROR(pDevIns,
696 VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
697 N_("Configuration error: Invalid \"MAC\" value"));
698 goto out;
699 }
700 char c1 = *macStr++ - '0';
701 if (c1 > 9)
702 c1 -= 7;
703 char c2 = *macStr++ - '0';
704 if (c2 > 9)
705 c2 -= 7;
706 *pMac++ = ((c1 & 0x0f) << 4) | (c2 & 0x0f);
707 if (i != 5 && *macStr == ':')
708 macStr++;
709 }
710 }
711 }
712 if (RT_FAILURE(rc))
713 {
714 PDMDEV_SET_ERROR(pDevIns, rc,
715 N_("Configuration error: Failed to get the \"MAC\" value"));
716 goto out;
717 }
718 rc = devINIPNetworkConfiguration(pDevIns, pThis, pCfg);
719 if (RT_FAILURE(rc))
720 goto out;
721
722 /*
723 * Attach driver and query the network connector interface.
724 */
725 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase,
726 "Network Port");
727 if (RT_FAILURE(rc))
728 {
729 pThis->pDrvBase = NULL;
730 pThis->pDrv = NULL;
731 goto out;
732 }
733 else
734 {
735 pThis->pDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMINETWORKUP);
736 if (!pThis->pDrv)
737 {
738 AssertMsgFailed(("Failed to obtain the PDMINETWORKUP interface!\n"));
739 rc = VERR_PDM_MISSING_INTERFACE_BELOW;
740 goto out;
741 }
742 }
743
744 struct ip_addr ipaddr, netmask, gw;
745 struct in_addr ip;
746
747 if (!inet_aton(pThis->pszIP, &ip))
748 {
749 rc = PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
750 N_("Configuration error: Invalid \"IP\" value"));
751 goto out;
752 }
753 memcpy(&ipaddr, &ip, sizeof(ipaddr));
754 if (!inet_aton(pThis->pszNetmask, &ip))
755 {
756 rc = PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
757 N_("Configuration error: Invalid \"Netmask\" value"));
758 goto out;
759 }
760 memcpy(&netmask, &ip, sizeof(netmask));
761 if (pThis->pszGateway)
762 {
763 if (!inet_aton(pThis->pszGateway, &ip))
764 {
765 rc = PDMDEV_SET_ERROR(pDevIns,
766 VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
767 N_("Configuration error: Invalid \"Gateway\" value"));
768 goto out;
769 }
770 memcpy(&gw, &ip, sizeof(gw));
771 }
772 else
773 {
774 inet_aton(pThis->pszIP, &ip);
775 memcpy(&gw, &ip, sizeof(gw));
776 }
777 /*
778 * Initialize lwIP.
779 */
780 lwip_stats_init();
781 lwip_sys_init();
782#if MEM_LIBC_MALLOC == 0
783 lwip_mem_init();
784#endif
785 lwip_memp_init();
786 lwip_pbuf_init();
787 lwip_netif_init();
788 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, devINIPARPTimer, pThis,
789 TMTIMER_FLAGS_NO_CRIT_SECT, "lwIP ARP", &pThis->ARPTimer);
790 if (RT_FAILURE(rc))
791 goto out;
792 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, devINIPTCPFastTimer, pThis,
793 TMTIMER_FLAGS_NO_CRIT_SECT, "lwIP fast TCP", &pThis->TCPFastTimer);
794 if (RT_FAILURE(rc))
795 goto out;
796 TMTimerSetMillies(pThis->TCPFastTimer, TCP_FAST_INTERVAL);
797 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, devINIPTCPSlowTimer, pThis,
798 TMTIMER_FLAGS_NO_CRIT_SECT, "lwIP slow TCP", &pThis->TCPSlowTimer);
799 if (RT_FAILURE(rc))
800 goto out;
801 TMTimerSetMillies(pThis->TCPFastTimer, TCP_SLOW_INTERVAL);
802#ifndef VBOX_WITH_NEW_LWIP
803 pThis->LWIPTcpInitSem = lwip_sys_sem_new(0);
804 {
805 lwip_tcpip_init(devINIPTcpipInitDone, &pThis->LWIPTcpInitSem);
806 lwip_sys_sem_wait(pThis->LWIPTcpInitSem);
807 }
808#else
809 errRc = lwip_sys_sem_new(&pThis->LWIPTcpInitSem, 0);
810 /* VERR_INTERNAL_ERROR perhaps should be replaced with right error code */
811 AssertReturn(errRc == ERR_OK, VERR_INTERNAL_ERROR);
812 {
813 lwip_tcpip_init(devINIPTcpipInitDone, &pThis->LWIPTcpInitSem);
814 lwip_sys_sem_wait(&pThis->LWIPTcpInitSem, 0);
815 }
816#endif
817
818 /*
819 * Set up global pointer to interface data.
820 */
821 g_pDevINIPData = pThis;
822
823 struct netif *ret;
824 pThis->IntNetIF.name[0] = 'I';
825 pThis->IntNetIF.name[1] = 'N';
826 ret = netif_add(&pThis->IntNetIF, &ipaddr, &netmask, &gw, NULL,
827 devINIPInterface, lwip_tcpip_input);
828 if (!ret)
829 {
830 rc = VERR_NET_NO_NETWORK;
831 goto out;
832 }
833
834 lwip_netif_set_default(&pThis->IntNetIF);
835 lwip_netif_set_up(&pThis->IntNetIF);
836
837 /* link hack */
838 pThis->pLinkHack = g_pDevINILinkHack;
839
840out:
841 LogFlow(("%s: return %Rrc\n", __FUNCTION__, rc));
842 return rc;
843}
844
845
846/**
847 * Query whether lwIP is initialized or not. Since there is only a single
848 * instance of this device ever for a VM, it can be a global function.
849 *
850 * @returns True if lwIP is initialized.
851 */
852bool DevINIPConfigured(void)
853{
854 return g_pDevINIPData != NULL;
855}
856
857
858/**
859 * Internal network IP stack device registration record.
860 */
861const PDMDEVREG g_DeviceINIP =
862{
863 /* u32Version */
864 PDM_DEVREG_VERSION,
865 /* szName */
866 "IntNetIP",
867 /* szRCMod/szR0Mod */
868 "",
869 "",
870 /* pszDescription */
871 "Internal Network IP stack device",
872 /* fFlags */
873 PDM_DEVREG_FLAGS_DEFAULT_BITS,
874 /* fClass. As this is used by the storage devices, it must come earlier. */
875 PDM_DEVREG_CLASS_VMM_DEV,
876 /* cMaxInstances */
877 1,
878 /* cbInstance */
879 sizeof(DEVINTNETIP),
880 /* pfnConstruct */
881 devINIPConstruct,
882 /* pfnDestruct */
883 devINIPDestruct,
884 /* pfnRelocate */
885 NULL,
886 /* pfnIOCtl */
887 NULL,
888 /* pfnPowerOn */
889 NULL,
890 /* pfnReset */
891 NULL,
892 /* pfnSuspend */
893 NULL,
894 /* pfnResume */
895 NULL,
896 /* pfnAttach */
897 NULL,
898 /* pfnDetach */
899 NULL,
900 /* pfnQueryInterface */
901 NULL,
902 /* pfnInitComplete */
903 NULL,
904 /* pfnPowerOff */
905 NULL,
906 /* pfnSoftReset */
907 NULL,
908 /* u32VersionEnd */
909 PDM_DEVREG_VERSION
910};
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