VirtualBox

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

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

DevINIP: makes compatible with LWIP 1.4.1.

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