VirtualBox

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

Last change on this file since 33000 was 28800, checked in by vboxsync, 14 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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

© 2023 Oracle
ContactPrivacy policyTerms of Use