VirtualBox

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

Last change on this file since 51898 was 48947, checked in by vboxsync, 11 years ago

Devices: Whitespace and svn:keyword cleanups by scm.

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