VirtualBox

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

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

Network/Dev*: Preparing for pfnXmitPending to be callable and the TX threads move from the devices to the drivers.

  • 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 28277 2010-04-13 20:31:08Z 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.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 * 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,pfnXmitPending}
388 */
389static DECLCALLBACK(void) devINIPNetworkDown_XmitPending(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.pfnXmitPending = devINIPNetworkDown_XmitPending;
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.

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