VirtualBox

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

Last change on this file since 37636 was 36044, checked in by vboxsync, 14 years ago

typo.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.5 KB
Line 
1/* $Id: DevINIP.cpp 36044 2011-02-21 17:06:48Z 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/vmm/pdmdev.h>
44#include <VBox/vmm/pdmnetifs.h>
45#include <VBox/vmm/tm.h>
46#include <iprt/assert.h>
47#include <iprt/string.h>
48#include <iprt/uuid.h>
49
50#include "VBoxDD.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 network configuration port this device provides (LUN\#0). */
78 PDMINETWORKCONFIG INetworkConfig;
79 /** The base interface of the network driver below us. */
80 PPDMIBASE pDrvBase;
81 /** The connector of the network driver below us. */
82 PPDMINETWORKUP pDrv;
83 /** Pointer to the device instance. */
84 PPDMDEVINSR3 pDevIns;
85 /** MAC address. */
86 RTMAC MAC;
87 /** Static IP address of the interface. */
88 char *pszIP;
89 /** Netmask of the interface. */
90 char *pszNetmask;
91 /** Gateway for the interface. */
92 char *pszGateway;
93 /** lwIP network interface description. */
94 struct netif IntNetIF;
95 /** lwIP ARP timer. */
96 PTMTIMERR3 ARPTimer;
97 /** lwIP TCP fast timer. */
98 PTMTIMERR3 TCPFastTimer;
99 /** lwIP TCP slow timer. */
100 PTMTIMERR3 TCPSlowTimer;
101 /** lwIP semaphore to coordinate TCPIP init/terminate. */
102 sys_sem_t LWIPTcpInitSem;
103 /** hack: get linking right. remove this eventually, once the device
104 * provides a proper interface to all IP stack functions. */
105 const void *pLinkHack;
106 /** Flag whether the link is up. */
107 bool fLnkUp;
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
233 rc = g_pDevINIPData->pDrv->pfnBeginXmit(g_pDevINIPData->pDrv, true /* fOnWorkerThread */);
234 if (RT_FAILURE(rc))
235 return ERR_IF;
236
237 rc = g_pDevINIPData->pDrv->pfnAllocBuf(g_pDevINIPData->pDrv, DEVINIP_MAX_FRAME, NULL /*pGso*/, &pSgBuf);
238 if (RT_SUCCESS(rc))
239 {
240#if ETH_PAD_SIZE
241 lwip_pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
242#endif
243
244 uint8_t *pbBuf = pSgBuf ? (uint8_t *)pSgBuf->aSegs[0].pvSeg : NULL;
245 size_t cbBuf = 0;
246 for (struct pbuf *q = p; q != NULL; q = q->next)
247 {
248 if (cbBuf + q->len <= DEVINIP_MAX_FRAME)
249 {
250 if (RT_LIKELY(pbBuf))
251 {
252 memcpy(pbBuf, q->payload, q->len);
253 pbBuf += q->len;
254 }
255 cbBuf += q->len;
256 }
257 else
258 {
259 LogRel(("INIP: exceeded frame size\n"));
260 break;
261 }
262 }
263 if (cbBuf)
264 {
265 pSgBuf->cbUsed = cbBuf;
266 rc = g_pDevINIPData->pDrv->pfnSendBuf(g_pDevINIPData->pDrv, pSgBuf, true /* fOnWorkerThread */);
267 }
268 else
269 rc = g_pDevINIPData->pDrv->pfnFreeBuf(g_pDevINIPData->pDrv, pSgBuf);
270
271#if ETH_PAD_SIZE
272 lwip_pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
273#endif
274 }
275
276 g_pDevINIPData->pDrv->pfnEndXmit(g_pDevINIPData->pDrv);
277 }
278
279 err_t lrc = ERR_OK;
280 if (RT_FAILURE(rc))
281 lrc = ERR_IF;
282 LogFlow(("%s: return %d (vbox: %Rrc)\n", __FUNCTION__, rc, lrc));
283 return lrc;
284}
285
286/**
287 * Implements the ethernet interface backend initialization for lwIP.
288 *
289 * @returns lwIP error code
290 * @param netif Interface to configure.
291 */
292static DECLCALLBACK(err_t) devINIPInterface(struct netif *netif)
293{
294 LogFlow(("%s: netif=%p\n", __FUNCTION__, netif));
295 Assert(g_pDevINIPData != NULL);
296 netif->state = g_pDevINIPData;
297 netif->hwaddr_len = sizeof(g_pDevINIPData->MAC);
298 memcpy(netif->hwaddr, &g_pDevINIPData->MAC, sizeof(g_pDevINIPData->MAC));
299 netif->mtu = DEVINIP_MAX_FRAME;
300 netif->flags = NETIF_FLAG_BROADCAST;
301 netif->output = devINIPOutput;
302 netif->linkoutput = devINIPOutputRaw;
303
304 lwip_etharp_init();
305 TMTimerSetMillies(g_pDevINIPData->ARPTimer, ARP_TMR_INTERVAL);
306 LogFlow(("%s: success\n", __FUNCTION__));
307 return ERR_OK;
308}
309
310/**
311 * Wait until data can be received.
312 *
313 * @returns VBox status code. VINF_SUCCESS means there is at least one receive descriptor available.
314 * @param pInterface PDM network port interface pointer.
315 * @param cMillies Number of milliseconds to wait. 0 means return immediately.
316 */
317static DECLCALLBACK(int) devINIPNetworkDown_WaitInputAvail(PPDMINETWORKDOWN pInterface, RTMSINTERVAL cMillies)
318{
319 LogFlow(("%s: pInterface=%p\n", __FUNCTION__, pInterface));
320 LogFlow(("%s: return VINF_SUCCESS\n", __FUNCTION__));
321 return VINF_SUCCESS;
322}
323
324/**
325 * Receive data and pass it to lwIP for processing.
326 *
327 * @returns VBox status code
328 * @param pInterface PDM network port interface pointer.
329 * @param pvBuf Pointer to frame data.
330 * @param cb Frame size.
331 */
332static DECLCALLBACK(int) devINIPNetworkDown_Input(PPDMINETWORKDOWN pInterface,
333 const void *pvBuf, size_t cb)
334{
335 const uint8_t *pbBuf = (const uint8_t *)pvBuf;
336 size_t len = cb;
337 const struct eth_hdr *ethhdr;
338 struct pbuf *p, *q;
339 int rc = VINF_SUCCESS;
340
341 LogFlow(("%s: pInterface=%p pvBuf=%p cb=%lu\n", __FUNCTION__, pInterface,
342 pvBuf, cb));
343 Assert(g_pDevINIPData);
344 Assert(g_pDevINIPData->pDrv);
345
346 /* Silently ignore packets being received while lwIP isn't set up. */
347 if (!g_pDevINIPData)
348 goto out;
349
350#if ETH_PAD_SIZE
351 len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
352#endif
353
354 /* We allocate a pbuf chain of pbufs from the pool. */
355 p = lwip_pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
356 if (p != NULL)
357 {
358#if ETH_PAD_SIZE
359 lwip_pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
360#endif
361
362 for (q = p; q != NULL; q = q->next)
363 {
364 /* Fill the buffers, and clean out unused buffer space. */
365 memcpy(q->payload, pbBuf, RT_MIN(cb, q->len));
366 pbBuf += RT_MIN(cb, q->len);
367 if (q->len > cb)
368 memset(((uint8_t *)q->payload) + cb, '\0', q->len - cb);
369 cb -= RT_MIN(cb, q->len);
370 }
371
372 ethhdr = (const struct eth_hdr *)p->payload;
373 struct netif *iface = &g_pDevINIPData->IntNetIF;
374 err_t lrc;
375 switch (htons(ethhdr->type))
376 {
377 case ETHTYPE_IP: /* IP packet */
378 lwip_pbuf_header(p, -(ssize_t)sizeof(struct eth_hdr));
379 lrc = iface->input(p, iface);
380 if (lrc)
381 rc = VERR_NET_IO_ERROR;
382 break;
383 case ETHTYPE_ARP: /* ARP packet */
384 lwip_etharp_arp_input(iface, (struct eth_addr *)iface->hwaddr, p);
385 break;
386 default:
387 lwip_pbuf_free(p);
388 }
389 }
390
391out:
392 LogFlow(("%s: return %Rrc\n", __FUNCTION__, rc));
393 return rc;
394}
395
396/**
397 * @interface_method_impl{PDMINETWORKDOWN,pfnXmitPending}
398 */
399static DECLCALLBACK(void) devINIPNetworkDown_XmitPending(PPDMINETWORKDOWN pInterface)
400{
401 NOREF(pInterface);
402}
403
404
405/**
406 * Signals the end of lwIP TCPIP initialization.
407 *
408 * @param arg opaque argument, here the pointer to the semaphore.
409 */
410static DECLCALLBACK(void) devINIPTcpipInitDone(void *arg)
411{
412 sys_sem_t *sem = (sys_sem_t *)arg;
413 lwip_sys_sem_signal(*sem);
414}
415
416
417/**
418 * Gets the current Media Access Control (MAC) address.
419 *
420 * @returns VBox status code.
421 * @param pInterface Pointer to the interface structure containing the called function pointer.
422 * @param pMac Where to store the MAC address.
423 * @thread EMT
424 */
425static DECLCALLBACK(int) devINIPGetMac(PPDMINETWORKCONFIG pInterface, PRTMAC pMac)
426{
427 PDEVINTNETIP pThis = RT_FROM_MEMBER(pInterface, DEVINTNETIP, INetworkConfig);
428 memcpy(pMac, pThis->MAC.au8, sizeof(RTMAC));
429 return VINF_SUCCESS;
430}
431
432/**
433 * Gets the new link state.
434 *
435 * @returns The current link state.
436 * @param pInterface Pointer to the interface structure containing the called function pointer.
437 * @thread EMT
438 */
439static DECLCALLBACK(PDMNETWORKLINKSTATE) devINIPGetLinkState(PPDMINETWORKCONFIG pInterface)
440{
441 PDEVINTNETIP pThis = RT_FROM_MEMBER(pInterface, DEVINTNETIP, INetworkConfig);
442 if (pThis->fLnkUp)
443 return PDMNETWORKLINKSTATE_UP;
444 return PDMNETWORKLINKSTATE_DOWN;
445}
446
447
448/**
449 * Sets the new link state.
450 *
451 * @returns VBox status code.
452 * @param pInterface Pointer to the interface structure containing the called function pointer.
453 * @param enmState The new link state
454 */
455static DECLCALLBACK(int) devINIPSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
456{
457 PDEVINTNETIP pThis = RT_FROM_MEMBER(pInterface, DEVINTNETIP, INetworkConfig);
458 bool fNewUp = enmState == PDMNETWORKLINKSTATE_UP;
459
460 if (fNewUp != pThis->fLnkUp)
461 {
462 if (fNewUp)
463 {
464 LogFlowFunc(("Link is up\n"));
465 pThis->fLnkUp = true;
466 }
467 else
468 {
469 LogFlowFunc(("Link is down\n"));
470 pThis->fLnkUp = false;
471 }
472 if (pThis->pDrv)
473 pThis->pDrv->pfnNotifyLinkChanged(pThis->pDrv, enmState);
474 }
475 return VINF_SUCCESS;
476}
477
478/* -=-=-=-=- PDMIBASE -=-=-=-=- */
479
480/**
481 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
482 */
483static DECLCALLBACK(void *) devINIPQueryInterface(PPDMIBASE pInterface,
484 const char *pszIID)
485{
486 PDEVINTNETIP pThis = RT_FROM_MEMBER(pInterface, DEVINTNETIP, IBase);
487 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
488 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKDOWN, &pThis->INetworkDown);
489 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThis->INetworkConfig);
490 return NULL;
491}
492
493/* -=-=-=-=- PDMDEVREG -=-=-=-=- */
494
495/**
496 * Destruct a device instance.
497 *
498 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
499 * resources can be freed correctly.
500 *
501 * @returns VBox status.
502 * @param pDevIns The device instance data.
503 */
504static DECLCALLBACK(int) devINIPDestruct(PPDMDEVINS pDevIns)
505{
506 PDEVINTNETIP pThis = PDMINS_2_DATA(pDevIns, PDEVINTNETIP);
507
508 LogFlow(("%s: pDevIns=%p\n", __FUNCTION__, pDevIns));
509 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
510
511 if (g_pDevINIPData != NULL)
512 {
513 netif_set_down(&pThis->IntNetIF);
514 netif_remove(&pThis->IntNetIF);
515 tcpip_terminate();
516 lwip_sys_sem_wait(pThis->LWIPTcpInitSem);
517 lwip_sys_sem_free(pThis->LWIPTcpInitSem);
518 }
519
520 if (pThis->pszIP)
521 MMR3HeapFree(pThis->pszIP);
522 if (pThis->pszNetmask)
523 MMR3HeapFree(pThis->pszNetmask);
524 if (pThis->pszGateway)
525 MMR3HeapFree(pThis->pszGateway);
526
527 LogFlow(("%s: success\n", __FUNCTION__));
528 return VINF_SUCCESS;
529}
530
531
532/**
533 * @interface_method_impl{PDMDEVREG,pfnConstruct}
534 */
535static DECLCALLBACK(int) devINIPConstruct(PPDMDEVINS pDevIns, int iInstance,
536 PCFGMNODE pCfg)
537{
538 PDEVINTNETIP pThis = PDMINS_2_DATA(pDevIns, PDEVINTNETIP);
539 int rc = VINF_SUCCESS;
540 LogFlow(("%s: pDevIns=%p iInstance=%d pCfg=%p\n", __FUNCTION__,
541 pDevIns, iInstance, pCfg));
542
543 Assert(iInstance == 0);
544 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
545
546 /*
547 * Validate the config.
548 */
549 if (!CFGMR3AreValuesValid(pCfg, "MAC\0IP\0Netmask\0Gateway\0"))
550 {
551 rc = PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
552 N_("Unknown Internal Networking IP configuration option"));
553 goto out;
554 }
555
556 /*
557 * Init the static parts.
558 */
559 pThis->pszIP = NULL;
560 pThis->pszNetmask = NULL;
561 pThis->pszGateway = NULL;
562 /* Pointer to device instance */
563 pThis->pDevIns = pDevIns;
564 /* IBase */
565 pThis->IBase.pfnQueryInterface = devINIPQueryInterface;
566 /* INetworkDown */
567 pThis->INetworkDown.pfnWaitReceiveAvail = devINIPNetworkDown_WaitInputAvail;
568 pThis->INetworkDown.pfnReceive = devINIPNetworkDown_Input;
569 pThis->INetworkDown.pfnXmitPending = devINIPNetworkDown_XmitPending;
570 /* INetworkConfig */
571 pThis->INetworkConfig.pfnGetMac = devINIPGetMac;
572 pThis->INetworkConfig.pfnGetLinkState = devINIPGetLinkState;
573 pThis->INetworkConfig.pfnSetLinkState = devINIPSetLinkState;
574
575 /*
576 * Get the configuration settings.
577 */
578 rc = CFGMR3QueryBytes(pCfg, "MAC", &pThis->MAC, sizeof(pThis->MAC));
579 if (rc == VERR_CFGM_NOT_BYTES)
580 {
581 char szMAC[64];
582 rc = CFGMR3QueryString(pCfg, "MAC", &szMAC[0], sizeof(szMAC));
583 if (RT_SUCCESS(rc))
584 {
585 char *macStr = &szMAC[0];
586 char *pMac = (char *)&pThis->MAC;
587 for (uint32_t i = 0; i < 6; i++)
588 {
589 if ( !*macStr || !*(macStr + 1)
590 || *macStr == ':' || *(macStr + 1) == ':')
591 {
592 rc = PDMDEV_SET_ERROR(pDevIns,
593 VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
594 N_("Configuration error: Invalid \"MAC\" value"));
595 goto out;
596 }
597 char c1 = *macStr++ - '0';
598 if (c1 > 9)
599 c1 -= 7;
600 char c2 = *macStr++ - '0';
601 if (c2 > 9)
602 c2 -= 7;
603 *pMac++ = ((c1 & 0x0f) << 4) | (c2 & 0x0f);
604 if (i != 5 && *macStr == ':')
605 macStr++;
606 }
607 }
608 }
609 if (RT_FAILURE(rc))
610 {
611 PDMDEV_SET_ERROR(pDevIns, rc,
612 N_("Configuration error: Failed to get the \"MAC\" value"));
613 goto out;
614 }
615 rc = CFGMR3QueryStringAlloc(pCfg, "IP", &pThis->pszIP);
616 if (RT_FAILURE(rc))
617 {
618 PDMDEV_SET_ERROR(pDevIns, rc,
619 N_("Configuration error: Failed to get the \"IP\" value"));
620 goto out;
621 }
622 rc = CFGMR3QueryStringAlloc(pCfg, "Netmask", &pThis->pszNetmask);
623 if (RT_FAILURE(rc))
624 {
625 PDMDEV_SET_ERROR(pDevIns, rc,
626 N_("Configuration error: Failed to get the \"Netmask\" value"));
627 goto out;
628 }
629 rc = CFGMR3QueryStringAlloc(pCfg, "Gateway", &pThis->pszGateway);
630 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
631 rc = VINF_SUCCESS;
632 if (RT_FAILURE(rc))
633 {
634 PDMDEV_SET_ERROR(pDevIns, rc,
635 N_("Configuration error: Failed to get the \"Gateway\" value"));
636 goto out;
637 }
638
639 /*
640 * Attach driver and query the network connector interface.
641 */
642 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase,
643 "Network Port");
644 if (RT_FAILURE(rc))
645 {
646 pThis->pDrvBase = NULL;
647 pThis->pDrv = NULL;
648 goto out;
649 }
650 else
651 {
652 pThis->pDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMINETWORKUP);
653 if (!pThis->pDrv)
654 {
655 AssertMsgFailed(("Failed to obtain the PDMINETWORKUP interface!\n"));
656 rc = VERR_PDM_MISSING_INTERFACE_BELOW;
657 goto out;
658 }
659 }
660
661 struct ip_addr ipaddr, netmask, gw;
662 struct in_addr ip;
663
664 if (!inet_aton(pThis->pszIP, &ip))
665 {
666 rc = PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
667 N_("Configuration error: Invalid \"IP\" value"));
668 goto out;
669 }
670 memcpy(&ipaddr, &ip, sizeof(ipaddr));
671 if (!inet_aton(pThis->pszNetmask, &ip))
672 {
673 rc = PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
674 N_("Configuration error: Invalid \"Netmask\" value"));
675 goto out;
676 }
677 memcpy(&netmask, &ip, sizeof(netmask));
678 if (pThis->pszGateway)
679 {
680 if (!inet_aton(pThis->pszGateway, &ip))
681 {
682 rc = PDMDEV_SET_ERROR(pDevIns,
683 VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
684 N_("Configuration error: Invalid \"Gateway\" value"));
685 goto out;
686 }
687 memcpy(&gw, &ip, sizeof(gw));
688 }
689 else
690 {
691 inet_aton(pThis->pszIP, &ip);
692 memcpy(&gw, &ip, sizeof(gw));
693 }
694
695 /*
696 * Initialize lwIP.
697 */
698 lwip_stats_init();
699 lwip_sys_init();
700#if MEM_LIBC_MALLOC == 0
701 lwip_mem_init();
702#endif
703 lwip_memp_init();
704 lwip_pbuf_init();
705 lwip_netif_init();
706 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, devINIPARPTimer, pThis,
707 TMTIMER_FLAGS_NO_CRIT_SECT, "lwIP ARP", &pThis->ARPTimer);
708 if (RT_FAILURE(rc))
709 goto out;
710 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, devINIPTCPFastTimer, pThis,
711 TMTIMER_FLAGS_NO_CRIT_SECT, "lwIP fast TCP", &pThis->TCPFastTimer);
712 if (RT_FAILURE(rc))
713 goto out;
714 TMTimerSetMillies(pThis->TCPFastTimer, TCP_FAST_INTERVAL);
715 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, devINIPTCPSlowTimer, pThis,
716 TMTIMER_FLAGS_NO_CRIT_SECT, "lwIP slow TCP", &pThis->TCPSlowTimer);
717 if (RT_FAILURE(rc))
718 goto out;
719 TMTimerSetMillies(pThis->TCPFastTimer, TCP_SLOW_INTERVAL);
720 pThis->LWIPTcpInitSem = lwip_sys_sem_new(0);
721 {
722 lwip_tcpip_init(devINIPTcpipInitDone, &pThis->LWIPTcpInitSem);
723 lwip_sys_sem_wait(pThis->LWIPTcpInitSem);
724 }
725
726 /*
727 * Set up global pointer to interface data.
728 */
729 g_pDevINIPData = pThis;
730
731 struct netif *ret;
732 pThis->IntNetIF.name[0] = 'I';
733 pThis->IntNetIF.name[1] = 'N';
734 ret = netif_add(&pThis->IntNetIF, &ipaddr, &netmask, &gw, NULL,
735 devINIPInterface, lwip_tcpip_input);
736 if (!ret)
737 {
738 rc = VERR_NET_NO_NETWORK;
739 goto out;
740 }
741
742 lwip_netif_set_default(&pThis->IntNetIF);
743 lwip_netif_set_up(&pThis->IntNetIF);
744
745 /* link hack */
746 pThis->pLinkHack = g_pDevINILinkHack;
747
748out:
749 LogFlow(("%s: return %Rrc\n", __FUNCTION__, rc));
750 return rc;
751}
752
753
754/**
755 * Query whether lwIP is initialized or not. Since there is only a single
756 * instance of this device ever for a VM, it can be a global function.
757 *
758 * @returns True if lwIP is initialized.
759 */
760bool DevINIPConfigured(void)
761{
762 return g_pDevINIPData != NULL;
763}
764
765
766/**
767 * Internal network IP stack device registration record.
768 */
769const PDMDEVREG g_DeviceINIP =
770{
771 /* u32Version */
772 PDM_DEVREG_VERSION,
773 /* szName */
774 "IntNetIP",
775 /* szRCMod/szR0Mod */
776 "",
777 "",
778 /* pszDescription */
779 "Internal Network IP stack device",
780 /* fFlags */
781 PDM_DEVREG_FLAGS_DEFAULT_BITS,
782 /* fClass. As this is used by the storage devices, it must come earlier. */
783 PDM_DEVREG_CLASS_VMM_DEV,
784 /* cMaxInstances */
785 1,
786 /* cbInstance */
787 sizeof(DEVINTNETIP),
788 /* pfnConstruct */
789 devINIPConstruct,
790 /* pfnDestruct */
791 devINIPDestruct,
792 /* pfnRelocate */
793 NULL,
794 /* pfnIOCtl */
795 NULL,
796 /* pfnPowerOn */
797 NULL,
798 /* pfnReset */
799 NULL,
800 /* pfnSuspend */
801 NULL,
802 /* pfnResume */
803 NULL,
804 /* pfnAttach */
805 NULL,
806 /* pfnDetach */
807 NULL,
808 /* pfnQueryInterface */
809 NULL,
810 /* pfnInitComplete */
811 NULL,
812 /* pfnPowerOff */
813 NULL,
814 /* pfnSoftReset */
815 NULL,
816 /* u32VersionEnd */
817 PDM_DEVREG_VERSION
818};
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