VirtualBox

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

Last change on this file since 28258 was 28258, checked in by vboxsync, 15 years ago

PDM critsects for drivers. Fixed critsect cleanup in failure path. Started on new transmit locking scheme (required for intnet buffer serialization).

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette