VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxNetAdp/VBoxNetAdp.c@ 28800

Last change on this file since 28800 was 28800, checked in by vboxsync, 15 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: 35.0 KB
Line 
1/* $Id: VBoxNetAdp.c 28800 2010-04-27 08:22:32Z vboxsync $ */
2/** @file
3 * VBoxNetAdp - Virtual Network Adapter Driver (Host), Common Code.
4 */
5
6/*
7 * Copyright (C) 2008-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/** @page pg_netadp VBoxNetAdp - Network Adapter
19 *
20 * This is a kernel module that creates a virtual interface that can be attached
21 * to an internal network.
22 *
23 * In the big picture we're one of the three trunk interface on the internal
24 * network, the one named "TAP Interface": @image html Networking_Overview.gif
25 *
26 */
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#define LOG_GROUP LOG_GROUP_NET_ADP_DRV
32#include "VBoxNetAdpInternal.h"
33
34#include <VBox/log.h>
35#include <VBox/err.h>
36#include <iprt/string.h>
37
38#ifdef VBOXANETADP_DO_NOT_USE_NETFLT
39
40#include <VBox/sup.h>
41#include <iprt/assert.h>
42#include <iprt/spinlock.h>
43#include <iprt/uuid.h>
44#include <VBox/version.h>
45
46/** r=bird: why is this here in the agnositc code? */
47#ifdef RT_OS_DARWIN
48# include <net/ethernet.h>
49# include <net/if_ether.h>
50# include <net/if_types.h>
51# include <sys/socket.h>
52# include <net/if.h>
53# include <net/if_dl.h>
54# include <sys/errno.h>
55# include <sys/param.h>
56#endif
57
58
59/*******************************************************************************
60* Defined Constants And Macros *
61*******************************************************************************/
62#define IFPORT_2_VBOXNETADP(pIfPort) \
63 ( (PVBOXNETADP)((uint8_t *)pIfPort - RT_OFFSETOF(VBOXNETADP, MyPort)) )
64
65
66AssertCompileMemberSize(VBOXNETADP, enmState, sizeof(uint32_t));
67
68/**
69 * Gets the enmState member atomically.
70 *
71 * Used for all reads.
72 *
73 * @returns The enmState value.
74 * @param pThis The instance.
75 */
76DECLINLINE(VBOXNETADPSTATE) vboxNetAdpGetState(PVBOXNETADP pThis)
77{
78 return (VBOXNETADPSTATE)ASMAtomicUoReadU32((uint32_t volatile *)&pThis->enmState);
79}
80
81
82/**
83 * Sets the enmState member atomically.
84 *
85 * Used for all updates.
86 *
87 * @param pThis The instance.
88 * @param enmNewState The new value.
89 */
90DECLINLINE(void) vboxNetAdpSetState(PVBOXNETADP pThis, VBOXNETADPSTATE enmNewState)
91{
92 Log(("vboxNetAdpSetState: pThis=%p, state change: %d -> %d.\n", pThis, vboxNetAdpGetState(pThis), enmNewState));
93 ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, enmNewState);
94}
95
96
97/**
98 * Sets the enmState member atomically after first acquiring the spinlock.
99 *
100 * Used for all updates.
101 *
102 * @param pThis The instance.
103 * @param enmNewState The new value.
104 */
105DECLINLINE(void) vboxNetAdpSetStateWithLock(PVBOXNETADP pThis, VBOXNETADPSTATE enmNewState)
106{
107 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
108 Log(("vboxNetAdpSetStateWithLock: pThis=%p, state=%d.\n", pThis, enmNewState));
109 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
110 vboxNetAdpSetState(pThis, enmNewState);
111 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
112}
113
114
115/**
116 * Gets the enmState member with locking.
117 *
118 * Used for all reads.
119 *
120 * @returns The enmState value.
121 * @param pThis The instance.
122 */
123DECLINLINE(VBOXNETADPSTATE) vboxNetAdpGetStateWithLock(PVBOXNETADP pThis)
124{
125 VBOXNETADPSTATE enmState;
126 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
127 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
128 enmState = vboxNetAdpGetState(pThis);
129 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
130 Log(("vboxNetAdpGetStateWithLock: pThis=%p, state=%d.\n", pThis, enmState));
131 return enmState;
132}
133
134
135/**
136 * Checks and sets the enmState member atomically.
137 *
138 * Used for all updates.
139 *
140 * @returns true if the state has been changed.
141 * @param pThis The instance.
142 * @param enmNewState The new value.
143 */
144DECLINLINE(bool) vboxNetAdpCheckAndSetState(PVBOXNETADP pThis, VBOXNETADPSTATE enmOldState, VBOXNETADPSTATE enmNewState)
145{
146 VBOXNETADPSTATE enmActualState;
147 bool fRc = true; /* be optimistic */
148 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
149
150 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
151 enmActualState = vboxNetAdpGetState(pThis); /** @todo r=bird: ASMAtomicCmpXchgU32()*/
152 if (enmActualState == enmOldState)
153 vboxNetAdpSetState(pThis, enmNewState);
154 else
155 fRc = false;
156 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
157
158 if (fRc)
159 Log(("vboxNetAdpCheckAndSetState: pThis=%p, state changed: %d -> %d.\n", pThis, enmOldState, enmNewState));
160 else
161 Log(("vboxNetAdpCheckAndSetState: pThis=%p, no state change: %d != %d (expected).\n", pThis, enmActualState, enmOldState));
162 return fRc;
163}
164
165
166/**
167 * Finds a instance by its name, the caller does the locking.
168 *
169 * @returns Pointer to the instance by the given name. NULL if not found.
170 * @param pGlobals The globals.
171 * @param pszName The name of the instance.
172 */
173static PVBOXNETADP vboxNetAdpFind(PVBOXNETADPGLOBALS pGlobals, const char *pszName)
174{
175 unsigned i;
176
177 for (i = 0; i < RT_ELEMENTS(pGlobals->aAdapters); i++)
178 {
179 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
180 PVBOXNETADP pThis = &pGlobals->aAdapters[i];
181 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
182 if ( vboxNetAdpGetState(pThis)
183 && !strcmp(pThis->szName, pszName))
184 {
185 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
186 return pThis;
187 }
188 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
189 }
190 return NULL;
191}
192
193
194/**
195 * Releases a reference to the specified instance.
196 *
197 * @param pThis The instance.
198 * @param fBusy Whether the busy counter should be decremented too.
199 */
200DECLHIDDEN(void) vboxNetAdpRelease(PVBOXNETADP pThis)
201{
202 uint32_t cRefs;
203
204 /*
205 * Paranoid Android.
206 */
207 AssertPtr(pThis);
208 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
209 Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
210 Assert(vboxNetAdpGetState(pThis) > kVBoxNetAdpState_Invalid);
211 AssertPtr(pThis->pGlobals);
212 Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
213 Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
214 Assert(pThis->szName[0]);
215
216 /*
217 * The object reference counting.
218 */
219 cRefs = ASMAtomicDecU32(&pThis->cRefs);
220 Assert(cRefs < UINT32_MAX / 2);
221}
222
223
224/**
225 * Decrements the busy counter and does idle wakeup.
226 *
227 * @param pThis The instance.
228 */
229DECLHIDDEN(void) vboxNetAdpIdle(PVBOXNETADP pThis)
230{
231 uint32_t cBusy;
232
233 /*
234 * Paranoid Android.
235 */
236 AssertPtr(pThis);
237 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
238 Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
239 Assert(vboxNetAdpGetState(pThis) >= kVBoxNetAdpState_Connected);
240 AssertPtr(pThis->pGlobals);
241 Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
242
243 cBusy = ASMAtomicDecU32(&pThis->cBusy);
244 if (!cBusy)
245 {
246 int rc = RTSemEventSignal(pThis->hEventIdle);
247 AssertRC(rc);
248 }
249 else
250 Assert(cBusy < UINT32_MAX / 2);
251}
252
253
254/**
255 * Retains a reference to the specified instance.
256 *
257 * @param pThis The instance.
258 */
259DECLHIDDEN(void) vboxNetAdpRetain(PVBOXNETADP pThis)
260{
261 uint32_t cRefs;
262
263 /*
264 * Paranoid Android.
265 */
266 AssertPtr(pThis);
267 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
268 Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
269 Assert(vboxNetAdpGetState(pThis) > kVBoxNetAdpState_Invalid);
270 AssertPtr(pThis->pGlobals);
271 Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
272 Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
273 Assert(pThis->szName[0]);
274
275 /*
276 * Retain the object.
277 */
278 cRefs = ASMAtomicIncU32(&pThis->cRefs);
279 Assert(cRefs > 1 && cRefs < UINT32_MAX / 2);
280
281 NOREF(cRefs);
282}
283
284
285/**
286 * Increments busy counter.
287 *
288 * @param pThis The instance.
289 */
290DECLHIDDEN(void) vboxNetAdpBusy(PVBOXNETADP pThis)
291{
292 uint32_t cBusy;
293
294 /*
295 * Are we vigilant enough?
296 */
297 AssertPtr(pThis);
298 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
299 Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
300 Assert(vboxNetAdpGetState(pThis) >= kVBoxNetAdpState_Connected);
301 AssertPtr(pThis->pGlobals);
302 Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
303 cBusy = ASMAtomicIncU32(&pThis->cBusy);
304 Assert(cBusy > 0 && cBusy < UINT32_MAX / 2);
305
306 NOREF(cBusy);
307}
308
309
310/**
311 * Generate a suitable MAC address.
312 *
313 * @param pThis The instance.
314 * @param pMac Where to return the MAC address.
315 */
316DECLHIDDEN(void) vboxNetAdpComposeMACAddress(PVBOXNETADP pThis, PRTMAC pMac)
317{
318#if 0 /* Use a locally administered version of the OUI we use for the guest NICs. */
319 pMac->au8[0] = 0x08 | 2;
320 pMac->au8[1] = 0x00;
321 pMac->au8[2] = 0x27;
322#else /* this is what \0vb comes down to. It seems to be unassigned atm. */
323 pMac->au8[0] = 0;
324 pMac->au8[1] = 0x76;
325 pMac->au8[2] = 0x62;
326#endif
327
328 pMac->au8[3] = 0; /* pThis->uUnit >> 16; */
329 pMac->au8[4] = 0; /* pThis->uUnit >> 8; */
330 pMac->au8[5] = pThis->uUnit;
331}
332
333
334/**
335 * Checks if receive is possible and increases busy and ref counters if so.
336 *
337 * @param pThis The instance.
338 */
339DECLHIDDEN(bool) vboxNetAdpPrepareToReceive(PVBOXNETADP pThis)
340{
341 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
342 bool fCanReceive = false;
343 /*
344 * Input validation.
345 */
346 AssertPtr(pThis);
347 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
348 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
349 if (vboxNetAdpGetState(pThis) == kVBoxNetAdpState_Active)
350 {
351 fCanReceive = true;
352 vboxNetAdpRetain(pThis);
353 vboxNetAdpBusy(pThis);
354 }
355 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
356 Log(("vboxNetAdpPrepareToReceive: fCanReceive=%d.\n", fCanReceive));
357
358 return fCanReceive;
359}
360
361
362/**
363 * Forwards scatter/gather list to internal network and decreases busy and ref counters.
364 *
365 * @param pThis The instance.
366 */
367DECLHIDDEN(void) vboxNetAdpReceive(PVBOXNETADP pThis, PINTNETSG pSG)
368{
369 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
370 /*
371 * Input validation.
372 */
373 AssertPtr(pThis);
374 AssertPtr(pSG);
375 AssertPtr(pThis->pSwitchPort);
376 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
377 Log(("vboxNetAdpReceive: forwarding packet to internal net...\n"));
378 pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
379 vboxNetAdpIdle(pThis);
380 vboxNetAdpRelease(pThis);
381}
382
383
384/**
385 * Decreases busy and ref counters.
386 *
387 * @param pThis The instance.
388 */
389DECLHIDDEN(void) vboxNetAdpCancelReceive(PVBOXNETADP pThis)
390{
391 Log(("vboxNetAdpCancelReceive: cancelled.\n"));
392 vboxNetAdpIdle(pThis);
393 vboxNetAdpRelease(pThis);
394}
395
396
397/**
398 * @copydoc INTNETTRUNKIFPORT::pfnXmit
399 */
400static DECLCALLBACK(int) vboxNetAdpPortXmit(PINTNETTRUNKIFPORT pIfPort, PINTNETSG pSG, uint32_t fDst)
401{
402 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
403 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
404 int rc = VINF_SUCCESS;
405
406 /*
407 * Input validation.
408 */
409 AssertPtr(pThis);
410 AssertPtr(pSG);
411 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
412
413 Log(("vboxNetAdpPortXmit: outgoing packet (len=%d)\n", pSG->cbTotal));
414
415 /*
416 * Do a retain/busy, invoke the OS specific code.
417 */
418 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
419 if (vboxNetAdpGetState(pThis) != kVBoxNetAdpState_Active)
420 {
421 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
422 Log(("vboxNetAdpReceive: Dropping incoming packet for inactive interface %s.\n",
423 pThis->szName));
424 return VERR_INVALID_STATE;
425 }
426 vboxNetAdpRetain(pThis);
427 vboxNetAdpBusy(pThis);
428 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
429
430 rc = vboxNetAdpPortOsXmit(pThis, pSG, fDst);
431 vboxNetAdpIdle(pThis);
432 vboxNetAdpRelease(pThis);
433
434 return rc;
435}
436
437
438/**
439 * @copydoc INTNETTRUNKIFPORT::pfnGetMacAddress
440 */
441static DECLCALLBACK(void) vboxNetAdpPortGetMacAddress(PINTNETTRUNKIFPORT pIfPort, PRTMAC pMac)
442{
443 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
444
445 /*
446 * Input validation.
447 */
448 AssertPtr(pThis);
449 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
450 Assert(vboxNetAdpGetStateWithLock(pThis) == kVBoxNetAdpState_Active);
451
452 /*
453 * Forward the question to the OS specific code.
454 */
455 vboxNetAdpPortOsGetMacAddress(pThis, pMac);
456}
457
458
459/**
460 * @copydoc INTNETTRUNKIFPORT::pfnWaitForIdle
461 */
462static DECLCALLBACK(int) vboxNetAdpPortWaitForIdle(PINTNETTRUNKIFPORT pIfPort, uint32_t cMillies)
463{
464 int rc;
465 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
466
467 /*
468 * Input validation.
469 */
470 AssertPtr(pThis);
471 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
472 AssertReturn(vboxNetAdpGetStateWithLock(pThis) >= kVBoxNetAdpState_Connected, VERR_INVALID_STATE);
473
474 /*
475 * Go to sleep on the semaphore after checking the busy count.
476 */
477 vboxNetAdpRetain(pThis);
478
479 rc = VINF_SUCCESS;
480 while (pThis->cBusy && RT_SUCCESS(rc))
481 rc = RTSemEventWait(pThis->hEventIdle, cMillies); /** @todo make interruptible? */
482
483 vboxNetAdpRelease(pThis);
484
485 return rc;
486}
487
488
489/**
490 * @copydoc INTNETTRUNKIFPORT::pfnSetActive
491 */
492static DECLCALLBACK(bool) vboxNetAdpPortSetActive(PINTNETTRUNKIFPORT pIfPort, bool fActive)
493{
494 bool fPreviouslyActive;
495 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
496 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
497
498 /*
499 * Input validation.
500 */
501 AssertPtr(pThis);
502 AssertPtr(pThis->pGlobals);
503 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
504
505 Log(("vboxNetAdpPortSetActive: pThis=%p, fActive=%d, state before: %d.\n", pThis, fActive, vboxNetAdpGetState(pThis)));
506 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
507
508 fPreviouslyActive = vboxNetAdpGetState(pThis) == kVBoxNetAdpState_Active;
509 if (fPreviouslyActive != fActive)
510 {
511 switch (vboxNetAdpGetState(pThis))
512 {
513 case kVBoxNetAdpState_Connected:
514 vboxNetAdpSetState(pThis, kVBoxNetAdpState_Active);
515 break;
516 case kVBoxNetAdpState_Active:
517 vboxNetAdpSetState(pThis, kVBoxNetAdpState_Connected);
518 break;
519 default:
520 break;
521 }
522 }
523
524 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
525 Log(("vboxNetAdpPortSetActive: state after: %RTbool.\n", vboxNetAdpGetState(pThis)));
526 return fPreviouslyActive;
527}
528
529
530/**
531 * @copydoc INTNETTRUNKIFPORT::pfnDisconnectAndRelease
532 */
533static DECLCALLBACK(void) vboxNetAdpPortDisconnectAndRelease(PINTNETTRUNKIFPORT pIfPort)
534{
535 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
536 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
537
538 /*
539 * Serious paranoia.
540 */
541 AssertPtr(pThis);
542 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
543 Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
544 AssertPtr(pThis->pGlobals);
545 Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
546 Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
547
548
549 /*
550 * Disconnect and release it.
551 */
552 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
553 //Assert(vboxNetAdpGetState(pThis) == kVBoxNetAdpState_Connected);
554 Assert(!pThis->cBusy);
555 vboxNetAdpSetState(pThis, kVBoxNetAdpState_Transitional);
556 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
557
558 vboxNetAdpOsDisconnectIt(pThis);
559 pThis->pSwitchPort = NULL;
560
561 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
562 vboxNetAdpSetState(pThis, kVBoxNetAdpState_Available);
563 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
564
565 vboxNetAdpRelease(pThis);
566}
567
568
569/**
570 * @copydoc INTNETTRUNKIFPORT::pfnRelease
571 */
572static DECLCALLBACK(void) vboxNetAdpPortRelease(PINTNETTRUNKIFPORT pIfPort)
573{
574 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
575 vboxNetAdpRelease(pThis);
576}
577
578
579/**
580 * @copydoc INTNETTRUNKIFPORT::pfnRetain
581 */
582static DECLCALLBACK(void) vboxNetAdpPortRetain(PINTNETTRUNKIFPORT pIfPort)
583{
584 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
585 vboxNetAdpRetain(pThis);
586}
587
588
589int vboxNetAdpCreate (PINTNETTRUNKFACTORY pIfFactory, PVBOXNETADP *ppNew)
590{
591 int rc;
592 unsigned i;
593 PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETADPGLOBALS, TrunkFactory));
594
595 for (i = 0; i < RT_ELEMENTS(pGlobals->aAdapters); i++)
596 {
597 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
598 PVBOXNETADP pThis = &pGlobals->aAdapters[i];
599
600 if (vboxNetAdpCheckAndSetState(pThis, kVBoxNetAdpState_Invalid, kVBoxNetAdpState_Transitional))
601 {
602 /* Found an empty slot -- use it. */
603 RTMAC Mac;
604 Assert(ASMAtomicIncU32(&pThis->cRefs) == 1);
605 vboxNetAdpComposeMACAddress(pThis, &Mac);
606 rc = vboxNetAdpOsCreate(pThis, &Mac);
607 *ppNew = pThis;
608 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
609 vboxNetAdpSetState(pThis, kVBoxNetAdpState_Available);
610 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
611 return rc;
612 }
613 }
614
615 /* All slots in adapter array are busy. */
616 return VERR_OUT_OF_RESOURCES;
617}
618
619int vboxNetAdpDestroy (PVBOXNETADP pThis)
620{
621 int rc = VINF_SUCCESS;
622 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
623
624 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
625 if (vboxNetAdpGetState(pThis) != kVBoxNetAdpState_Available || pThis->cBusy)
626 {
627 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
628 return VERR_INTNET_FLT_IF_BUSY;
629 }
630 vboxNetAdpSetState(pThis, kVBoxNetAdpState_Transitional);
631 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
632 vboxNetAdpRelease(pThis);
633
634 vboxNetAdpOsDestroy(pThis);
635
636 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
637 vboxNetAdpSetState(pThis, kVBoxNetAdpState_Invalid);
638 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
639
640 return rc;
641}
642
643/**
644 * Connects the instance to the specified switch port.
645 *
646 * Called while owning the lock. We're ASSUMING that the internal
647 * networking code is already owning an recursive mutex, so, there
648 * will be no deadlocks when vboxNetAdpOsConnectIt calls back into
649 * it for setting preferences.
650 *
651 * @returns VBox status code.
652 * @param pThis The instance.
653 * @param pSwitchPort The port on the internal network 'switch'.
654 * @param ppIfPort Where to return our port interface.
655 */
656static int vboxNetAdpConnectIt(PVBOXNETADP pThis, PINTNETTRUNKSWPORT pSwitchPort, PINTNETTRUNKIFPORT *ppIfPort)
657{
658 int rc;
659
660 /*
661 * Validate state.
662 */
663 Assert(!pThis->cBusy);
664 Assert(vboxNetAdpGetStateWithLock(pThis) == kVBoxNetAdpState_Transitional);
665
666 /*
667 * Do the job.
668 * Note that we're calling the os stuff while owning the semaphore here.
669 */
670 pThis->pSwitchPort = pSwitchPort;
671 rc = vboxNetAdpOsConnectIt(pThis);
672 if (RT_SUCCESS(rc))
673 {
674 *ppIfPort = &pThis->MyPort;
675 }
676 else
677 pThis->pSwitchPort = NULL;
678
679 return rc;
680}
681
682
683/**
684 * @copydoc INTNETTRUNKFACTORY::pfnCreateAndConnect
685 */
686static DECLCALLBACK(int) vboxNetAdpFactoryCreateAndConnect(PINTNETTRUNKFACTORY pIfFactory, const char *pszName,
687 PINTNETTRUNKSWPORT pSwitchPort, uint32_t fFlags,
688 PINTNETTRUNKIFPORT *ppIfPort)
689{
690 PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETADPGLOBALS, TrunkFactory));
691 PVBOXNETADP pThis;
692 int rc;
693
694 LogFlow(("vboxNetAdpFactoryCreateAndConnect: pszName=%p:{%s} fFlags=%#x\n", pszName, pszName, fFlags));
695 Assert(pGlobals->cFactoryRefs > 0);
696 AssertMsgReturn(!fFlags,
697 ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
698
699 /*
700 * Find instance, check if busy, connect if not.
701 */
702 pThis = vboxNetAdpFind(pGlobals, pszName);
703 if (pThis)
704 {
705 if (vboxNetAdpCheckAndSetState(pThis, kVBoxNetAdpState_Available, kVBoxNetAdpState_Transitional))
706 {
707 vboxNetAdpRetain(pThis);
708 rc = vboxNetAdpConnectIt(pThis, pSwitchPort, ppIfPort);
709 vboxNetAdpSetStateWithLock(pThis, RT_SUCCESS(rc) ? kVBoxNetAdpState_Connected : kVBoxNetAdpState_Available);
710 }
711 else
712 rc = VERR_INTNET_FLT_IF_BUSY;
713 }
714 else
715 rc = VERR_INTNET_FLT_IF_NOT_FOUND;
716
717 return rc;
718}
719
720
721/**
722 * @copydoc INTNETTRUNKFACTORY::pfnRelease
723 */
724static DECLCALLBACK(void) vboxNetAdpFactoryRelease(PINTNETTRUNKFACTORY pIfFactory)
725{
726 PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETADPGLOBALS, TrunkFactory));
727
728 int32_t cRefs = ASMAtomicDecS32(&pGlobals->cFactoryRefs);
729 Assert(cRefs >= 0); NOREF(cRefs);
730 LogFlow(("vboxNetAdpFactoryRelease: cRefs=%d (new)\n", cRefs));
731}
732
733
734/**
735 * Implements the SUPDRV component factor interface query method.
736 *
737 * @returns Pointer to an interface. NULL if not supported.
738 *
739 * @param pSupDrvFactory Pointer to the component factory registration structure.
740 * @param pSession The session - unused.
741 * @param pszInterfaceUuid The factory interface id.
742 */
743static DECLCALLBACK(void *) vboxNetAdpQueryFactoryInterface(PCSUPDRVFACTORY pSupDrvFactory, PSUPDRVSESSION pSession, const char *pszInterfaceUuid)
744{
745 PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pSupDrvFactory - RT_OFFSETOF(VBOXNETADPGLOBALS, SupDrvFactory));
746
747 /*
748 * Convert the UUID strings and compare them.
749 */
750 RTUUID UuidReq;
751 int rc = RTUuidFromStr(&UuidReq, pszInterfaceUuid);
752 if (RT_SUCCESS(rc))
753 {
754 if (!RTUuidCompareStr(&UuidReq, INTNETTRUNKFACTORY_UUID_STR))
755 {
756 ASMAtomicIncS32(&pGlobals->cFactoryRefs);
757 return &pGlobals->TrunkFactory;
758 }
759#ifdef LOG_ENABLED
760 else
761 Log(("VBoxNetAdp: unknown factory interface query (%s)\n", pszInterfaceUuid));
762#endif
763 }
764 else
765 Log(("VBoxNetAdp: rc=%Rrc, uuid=%s\n", rc, pszInterfaceUuid));
766
767 return NULL;
768}
769
770
771/**
772 * Checks whether the VBoxNetAdp wossname can be unloaded.
773 *
774 * This will return false if someone is currently using the module.
775 *
776 * @returns true if it's relatively safe to unload it, otherwise false.
777 * @param pGlobals Pointer to the globals.
778 */
779DECLHIDDEN(bool) vboxNetAdpCanUnload(PVBOXNETADPGLOBALS pGlobals)
780{
781 bool fRc = true; /* Assume it can be unloaded. */
782 unsigned i;
783
784 for (i = 0; i < RT_ELEMENTS(pGlobals->aAdapters); i++)
785 {
786 PVBOXNETADP pThis = &pGlobals->aAdapters[i];
787 if (vboxNetAdpGetStateWithLock(&pGlobals->aAdapters[i]) >= kVBoxNetAdpState_Connected)
788 {
789 fRc = false;
790 break; /* We already know the answer. */
791 }
792 }
793 return fRc && ASMAtomicUoReadS32((int32_t volatile *)&pGlobals->cFactoryRefs) <= 0;
794}
795
796/**
797 * tries to deinitialize Idc
798 * we separate the globals settings "base" which is actually
799 * "general" globals settings except for Idc, and idc.
800 * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
801 * thus it's not possible to make idc initialization from the driver startup routine for it,
802 * though the "base is still needed for the driver to functions".
803 * @param pGlobals
804 * @return VINF_SUCCESS on succes, VERR_WRONG_ORDER if we're busy.
805 */
806DECLHIDDEN(int) vboxNetAdpTryDeleteIdc(PVBOXNETADPGLOBALS pGlobals)
807{
808 int rc;
809
810 Assert(pGlobals->hFastMtx != NIL_RTSEMFASTMUTEX);
811
812 /*
813 * Check before trying to deregister the factory.
814 */
815 if (!vboxNetAdpCanUnload(pGlobals))
816 return VERR_WRONG_ORDER;
817
818 /*
819 * Disconnect from SUPDRV and check that nobody raced us,
820 * reconnect if that should happen.
821 */
822 rc = SUPR0IdcComponentDeregisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
823 AssertRC(rc);
824 if (!vboxNetAdpCanUnload(pGlobals))
825 {
826 rc = SUPR0IdcComponentRegisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
827 AssertRC(rc);
828 return VERR_WRONG_ORDER;
829 }
830
831 SUPR0IdcClose(&pGlobals->SupDrvIDC);
832
833 return rc;
834}
835
836static int vboxNetAdpSlotCreate(PVBOXNETADPGLOBALS pGlobals, unsigned uUnit, PVBOXNETADP pNew)
837{
838 int rc;
839
840 pNew->MyPort.u32Version = INTNETTRUNKIFPORT_VERSION;
841 pNew->MyPort.pfnRetain = vboxNetAdpPortRetain;
842 pNew->MyPort.pfnRelease = vboxNetAdpPortRelease;
843 pNew->MyPort.pfnDisconnectAndRelease= vboxNetAdpPortDisconnectAndRelease;
844 pNew->MyPort.pfnSetActive = vboxNetAdpPortSetActive;
845 pNew->MyPort.pfnWaitForIdle = vboxNetAdpPortWaitForIdle;
846 pNew->MyPort.pfnGetMacAddress = vboxNetAdpPortGetMacAddress;
847 pNew->MyPort.pfnXmit = vboxNetAdpPortXmit;
848 pNew->MyPort.u32VersionEnd = INTNETTRUNKIFPORT_VERSION;
849 pNew->pSwitchPort = NULL;
850 pNew->pGlobals = pGlobals;
851 pNew->hSpinlock = NIL_RTSPINLOCK;
852 pNew->enmState = kVBoxNetAdpState_Invalid;
853 pNew->cRefs = 0;
854 pNew->cBusy = 0;
855 pNew->hEventIdle = NIL_RTSEMEVENT;
856
857 rc = RTSpinlockCreate(&pNew->hSpinlock);
858 if (RT_SUCCESS(rc))
859 {
860 rc = RTSemEventCreate(&pNew->hEventIdle);
861 if (RT_SUCCESS(rc))
862 {
863 rc = vboxNetAdpOsInit(pNew);
864 if (RT_SUCCESS(rc))
865 {
866 return rc;
867 }
868 RTSemEventDestroy(pNew->hEventIdle);
869 pNew->hEventIdle = NIL_RTSEMEVENT;
870 }
871 RTSpinlockDestroy(pNew->hSpinlock);
872 pNew->hSpinlock = NIL_RTSPINLOCK;
873 }
874 return rc;
875}
876
877static void vboxNetAdpSlotDestroy(PVBOXNETADP pThis)
878{
879 Assert(pThis->cRefs == 0);
880 Assert(pThis->cBusy == 0);
881 Assert(vboxNetAdpGetState(pThis) == kVBoxNetAdpState_Invalid);
882 if (pThis->hEventIdle != NIL_RTSEMEVENT)
883 {
884 RTSemEventDestroy(pThis->hEventIdle);
885 pThis->hEventIdle = NIL_RTSEMEVENT;
886 }
887 if (pThis->hSpinlock != NIL_RTSPINLOCK)
888 {
889 RTSpinlockDestroy(pThis->hSpinlock);
890 pThis->hSpinlock = NIL_RTSPINLOCK;
891 }
892}
893
894/**
895 * performs "base" globals deinitialization
896 * we separate the globals settings "base" which is actually
897 * "general" globals settings except for Idc, and idc.
898 * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
899 * thus it's not possible to make idc initialization from the driver startup routine for it,
900 * though the "base is still needed for the driver to functions".
901 * @param pGlobals
902 * @return none
903 */
904DECLHIDDEN(void) vboxNetAdpDeleteGlobalsBase(PVBOXNETADPGLOBALS pGlobals)
905{
906 int i;
907 /*
908 * Release resources.
909 */
910 for (i = 0; i < (int)RT_ELEMENTS(pGlobals->aAdapters); i++)
911 if (RT_SUCCESS(vboxNetAdpDestroy(&pGlobals->aAdapters[i])))
912 vboxNetAdpSlotDestroy(&pGlobals->aAdapters[i]);
913
914 RTSemFastMutexDestroy(pGlobals->hFastMtx);
915 pGlobals->hFastMtx = NIL_RTSEMFASTMUTEX;
916
917#ifdef VBOXNETADP_STATIC_CONFIG
918 RTSemEventDestroy(pGlobals->hTimerEvent);
919 pGlobals->hTimerEvent = NIL_RTSEMEVENT;
920#endif
921
922}
923
924
925/**
926 * Called by the native part when the OS wants the driver to unload.
927 *
928 * @returns VINF_SUCCESS on succes, VERR_WRONG_ORDER if we're busy.
929 *
930 * @param pGlobals Pointer to the globals.
931 */
932DECLHIDDEN(int) vboxNetAdpTryDeleteGlobals(PVBOXNETADPGLOBALS pGlobals)
933{
934 int rc = vboxNetAdpTryDeleteIdc(pGlobals);
935 if (RT_SUCCESS(rc))
936 {
937 vboxNetAdpDeleteGlobalsBase(pGlobals);
938 }
939 return rc;
940}
941
942
943/**
944 * performs the "base" globals initialization
945 * we separate the globals initialization to globals "base" initialization which is actually
946 * "general" globals initialization except for Idc not being initialized, and idc initialization.
947 * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
948 * thus it's not possible to make idc initialization from the driver startup routine for it.
949 *
950 * @returns VBox status code.
951 * @param pGlobals Pointer to the globals. */
952DECLHIDDEN(int) vboxNetAdpInitGlobalsBase(PVBOXNETADPGLOBALS pGlobals)
953{
954 /*
955 * Initialize the common portions of the structure.
956 */
957 int i;
958 int rc = RTSemFastMutexCreate(&pGlobals->hFastMtx);
959 if (RT_SUCCESS(rc))
960 {
961 memset(pGlobals->aAdapters, 0, sizeof(pGlobals->aAdapters));
962 for (i = 0; i < (int)RT_ELEMENTS(pGlobals->aAdapters); i++)
963 {
964 rc = vboxNetAdpSlotCreate(pGlobals, i, &pGlobals->aAdapters[i]);
965 if (RT_FAILURE(rc))
966 {
967 /* Clean up. */
968 while (--i >= 0)
969 vboxNetAdpSlotDestroy(&pGlobals->aAdapters[i]);
970 Log(("vboxNetAdpInitGlobalsBase: Failed to create fast mutex (rc=%Rrc).\n", rc));
971 RTSemFastMutexDestroy(pGlobals->hFastMtx);
972 return rc;
973 }
974 }
975 pGlobals->TrunkFactory.pfnRelease = vboxNetAdpFactoryRelease;
976 pGlobals->TrunkFactory.pfnCreateAndConnect = vboxNetAdpFactoryCreateAndConnect;
977
978 strcpy(pGlobals->SupDrvFactory.szName, "VBoxNetAdp");
979 pGlobals->SupDrvFactory.pfnQueryFactoryInterface = vboxNetAdpQueryFactoryInterface;
980 }
981
982 return rc;
983}
984
985/**
986 * performs the Idc initialization
987 * we separate the globals initialization to globals "base" initialization which is actually
988 * "general" globals initialization except for Idc not being initialized, and idc initialization.
989 * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
990 * thus it's not possible to make idc initialization from the driver startup routine for it.
991 *
992 * @returns VBox status code.
993 * @param pGlobals Pointer to the globals. */
994DECLHIDDEN(int) vboxNetAdpInitIdc(PVBOXNETADPGLOBALS pGlobals)
995{
996 int rc;
997 /*
998 * Establish a connection to SUPDRV and register our component factory.
999 */
1000 rc = SUPR0IdcOpen(&pGlobals->SupDrvIDC, 0 /* iReqVersion = default */, 0 /* iMinVersion = default */, NULL, NULL, NULL);
1001 if (RT_SUCCESS(rc))
1002 {
1003 rc = SUPR0IdcComponentRegisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
1004 if (RT_SUCCESS(rc))
1005 {
1006#if 1 /** @todo REMOVE ME! */
1007 PVBOXNETADP pTmp;
1008 rc = vboxNetAdpCreate(&pGlobals->TrunkFactory, &pTmp);
1009 if (RT_FAILURE(rc))
1010 Log(("Failed to create vboxnet0, rc=%Rrc.\n", rc));
1011#endif
1012 Log(("VBoxNetAdp: pSession=%p\n", SUPR0IdcGetSession(&pGlobals->SupDrvIDC)));
1013 return rc;
1014 }
1015
1016 /* bail out. */
1017 LogRel(("VBoxNetAdp: Failed to register component factory, rc=%Rrc\n", rc));
1018 SUPR0IdcClose(&pGlobals->SupDrvIDC);
1019 }
1020
1021 return rc;
1022}
1023
1024/**
1025 * Called by the native driver/kext module initialization routine.
1026 *
1027 * It will initialize the common parts of the globals, assuming the caller
1028 * has already taken care of the OS specific bits.
1029 *
1030 * @returns VBox status code.
1031 * @param pGlobals Pointer to the globals.
1032 */
1033DECLHIDDEN(int) vboxNetAdpInitGlobals(PVBOXNETADPGLOBALS pGlobals)
1034{
1035 /*
1036 * Initialize the common portions of the structure.
1037 */
1038 int rc = vboxNetAdpInitGlobalsBase(pGlobals);
1039 if (RT_SUCCESS(rc))
1040 {
1041 rc = vboxNetAdpInitIdc(pGlobals);
1042 if (RT_SUCCESS(rc))
1043 {
1044 return rc;
1045 }
1046
1047 /* bail out. */
1048 vboxNetAdpDeleteGlobalsBase(pGlobals);
1049 }
1050
1051 return rc;
1052}
1053
1054#else /* !VBOXANETADP_DO_NOT_USE_NETFLT */
1055
1056
1057VBOXNETADP g_aAdapters[VBOXNETADP_MAX_INSTANCES];
1058
1059
1060
1061/**
1062 * Generate a suitable MAC address.
1063 *
1064 * @param pThis The instance.
1065 * @param pMac Where to return the MAC address.
1066 */
1067DECLHIDDEN(void) vboxNetAdpComposeMACAddress(PVBOXNETADP pThis, PRTMAC pMac)
1068{
1069 /* Use a locally administered version of the OUI we use for the guest NICs. */
1070 pMac->au8[0] = 0x08 | 2;
1071 pMac->au8[1] = 0x00;
1072 pMac->au8[2] = 0x27;
1073
1074 pMac->au8[3] = 0; /* pThis->uUnit >> 16; */
1075 pMac->au8[4] = 0; /* pThis->uUnit >> 8; */
1076 pMac->au8[5] = pThis->uUnit;
1077}
1078
1079int vboxNetAdpCreate (PVBOXNETADP *ppNew)
1080{
1081 int rc;
1082 unsigned i;
1083 for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
1084 {
1085 PVBOXNETADP pThis = &g_aAdapters[i];
1086
1087 if (ASMAtomicCmpXchgU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Transitional, kVBoxNetAdpState_Invalid))
1088 {
1089 RTMAC Mac;
1090 /* Found an empty slot -- use it. */
1091 Log(("vboxNetAdpCreate: found empty slot: %d\n", i));
1092 vboxNetAdpComposeMACAddress(pThis, &Mac);
1093 rc = vboxNetAdpOsCreate(pThis, &Mac);
1094 Log(("vboxNetAdpCreate: pThis=%p pThis->szName=%p\n", pThis, pThis->szName));
1095 if (RT_SUCCESS(rc))
1096 {
1097 *ppNew = pThis;
1098 ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Active);
1099 }
1100 else
1101 {
1102 ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Invalid);
1103 Log(("vboxNetAdpCreate: vboxNetAdpOsCreate failed with '%Rrc'.\n", rc));
1104 }
1105 Log2(("VBoxNetAdpCreate: Created %s\n", g_aAdapters[i].szName));
1106 for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
1107 Log2(("VBoxNetAdpCreate: Scanning entry: state=%d name=%s\n", g_aAdapters[i].enmState, g_aAdapters[i].szName));
1108 return rc;
1109 }
1110 }
1111 Log(("vboxNetAdpCreate: no empty slots!\n"));
1112
1113 /* All slots in adapter array are busy. */
1114 return VERR_OUT_OF_RESOURCES;
1115}
1116
1117int vboxNetAdpDestroy (PVBOXNETADP pThis)
1118{
1119 int rc = VINF_SUCCESS;
1120
1121 if (!ASMAtomicCmpXchgU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Transitional, kVBoxNetAdpState_Active))
1122 return VERR_INTNET_FLT_IF_BUSY;
1123
1124 vboxNetAdpOsDestroy(pThis);
1125
1126 ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Invalid);
1127
1128 return rc;
1129}
1130
1131int vboxNetAdpInit(void)
1132{
1133 unsigned i;
1134 PVBOXNETADP pVboxnet0;
1135 /*
1136 * Init common members and call OS-specific init.
1137 */
1138 for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
1139 {
1140 g_aAdapters[i].enmState = kVBoxNetAdpState_Invalid;
1141 g_aAdapters[i].uUnit = i;
1142 vboxNetAdpOsInit(&g_aAdapters[i]);
1143 }
1144
1145 /* Create vboxnet0 */
1146 return vboxNetAdpCreate(&pVboxnet0);
1147}
1148
1149/**
1150 * Finds an adapter by its name.
1151 *
1152 * @returns Pointer to the instance by the given name. NULL if not found.
1153 * @param pGlobals The globals.
1154 * @param pszName The name of the instance.
1155 */
1156PVBOXNETADP vboxNetAdpFindByName(const char *pszName)
1157{
1158 unsigned i;
1159
1160 for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
1161 {
1162 PVBOXNETADP pThis = &g_aAdapters[i];
1163 Log2(("VBoxNetAdp: Scanning entry: state=%d name=%s\n", pThis->enmState, pThis->szName));
1164 if ( strcmp(pThis->szName, pszName) == 0
1165 && ASMAtomicReadU32((uint32_t volatile *)&pThis->enmState) == kVBoxNetAdpState_Active)
1166 return pThis;
1167 }
1168 return NULL;
1169}
1170
1171void vboxNetAdpShutdown(void)
1172{
1173 unsigned i;
1174
1175 /* Remove virtual adapters */
1176 for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
1177 vboxNetAdpDestroy(&g_aAdapters[i]);
1178}
1179#endif /* !VBOXANETADP_DO_NOT_USE_NETFLT */
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