VirtualBox

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

Last change on this file since 44582 was 44528, checked in by vboxsync, 12 years ago

header (C) fixes

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