VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/USBProxyService.cpp@ 59633

Last change on this file since 59633 was 59475, checked in by vboxsync, 9 years ago

Main: Fix crashes introduced after USB proxy service rework

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.8 KB
Line 
1/* $Id: USBProxyService.cpp 59475 2016-01-26 12:57:54Z vboxsync $ */
2/** @file
3 * VirtualBox USB Proxy Service (base) class.
4 */
5
6/*
7 * Copyright (C) 2006-2014 Oracle Corporation
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
18#include "USBProxyService.h"
19#include "HostUSBDeviceImpl.h"
20#include "HostImpl.h"
21#include "MachineImpl.h"
22#include "VirtualBoxImpl.h"
23
24#include "AutoCaller.h"
25#include "Logging.h"
26
27#include <VBox/com/array.h>
28#include <VBox/err.h>
29#include <iprt/asm.h>
30#include <iprt/semaphore.h>
31#include <iprt/thread.h>
32#include <iprt/mem.h>
33#include <iprt/string.h>
34
35/** Pair of a USB proxy backend and the opaque filter data assigned by the backend. */
36typedef std::pair<USBProxyBackend *, void *> USBFilterPair;
37/** List of USB filter pairs. */
38typedef std::list<USBFilterPair> USBFilterList;
39
40/**
41 * Data for a USB device filter.
42 */
43struct USBFilterData
44{
45 USBFilterData()
46 : llUsbFilters()
47 { }
48
49 USBFilterList llUsbFilters;
50};
51
52/**
53 * Initialize data members.
54 */
55USBProxyService::USBProxyService(Host *aHost)
56 : mHost(aHost), mDevices(), mBackends()
57{
58 LogFlowThisFunc(("aHost=%p\n", aHost));
59}
60
61
62/**
63 * Stub needed as long as the class isn't virtual
64 */
65HRESULT USBProxyService::init(void)
66{
67 USBProxyBackend *pUsbProxyBackendHost;
68# if defined(RT_OS_DARWIN)
69 pUsbProxyBackendHost = new USBProxyBackendDarwin(this);
70# elif defined(RT_OS_LINUX)
71 pUsbProxyBackendHost = new USBProxyBackendLinux(this);
72# elif defined(RT_OS_OS2)
73 pUsbProxyBackendHost = new USBProxyBackendOs2(this);
74# elif defined(RT_OS_SOLARIS)
75 pUsbProxyBackendHost = new USBProxyBackendSolaris(this);
76# elif defined(RT_OS_WINDOWS)
77 pUsbProxyBackendHost = new USBProxyBackendWindows(this);
78# elif defined(RT_OS_FREEBSD)
79 pUsbProxyBackendHost = new USBProxyBackendFreeBSD(this);
80# else
81 pUsbProxyBackendHost = new USBProxyBackend(this);
82# endif
83 int vrc = pUsbProxyBackendHost->init();
84 if (RT_FAILURE(vrc))
85 {
86 delete pUsbProxyBackendHost;
87 mLastError = vrc;
88 }
89 else
90 mBackends.push_back(pUsbProxyBackendHost);
91
92#if 0 /** @todo: Pass in the config. */
93 pUsbProxyBackendHost = new USBProxyBackendUsbIp(this);
94 hrc = pUsbProxyBackendHost->init();
95 if (FAILED(hrc))
96 {
97 delete pUsbProxyBackendHost;
98 return hrc;
99 }
100#endif
101
102 return S_OK;
103}
104
105
106/**
107 * Empty destructor.
108 */
109USBProxyService::~USBProxyService()
110{
111 LogFlowThisFunc(("\n"));
112 while (!mBackends.empty())
113 {
114 USBProxyBackend *pUsbProxyBackend = mBackends.front();
115 mBackends.pop_front();
116 delete pUsbProxyBackend;
117 }
118
119 mDevices.clear();
120 mBackends.clear();
121 mHost = NULL;
122}
123
124
125/**
126 * Query if the service is active and working.
127 *
128 * @returns true if the service is up running.
129 * @returns false if the service isn't running.
130 */
131bool USBProxyService::isActive(void)
132{
133 return mBackends.size() > 0;
134}
135
136
137/**
138 * Get last error.
139 * Can be used to check why the proxy !isActive() upon construction.
140 *
141 * @returns VBox status code.
142 */
143int USBProxyService::getLastError(void)
144{
145 return mLastError;
146}
147
148
149/**
150 * We're using the Host object lock.
151 *
152 * This is just a temporary measure until all the USB refactoring is
153 * done, probably... For now it help avoiding deadlocks we don't have
154 * time to fix.
155 *
156 * @returns Lock handle.
157 */
158RWLockHandle *USBProxyService::lockHandle() const
159{
160 return mHost->lockHandle();
161}
162
163
164void *USBProxyService::insertFilter(PCUSBFILTER aFilter)
165{
166 USBFilterData *pFilterData = new USBFilterData();
167
168 for (USBProxyBackendList::iterator it = mBackends.begin();
169 it != mBackends.end();
170 ++it)
171 {
172 USBProxyBackend *pUsbProxyBackend = *it;
173 void *pvId = pUsbProxyBackend->insertFilter(aFilter);
174
175 pFilterData->llUsbFilters.push_back(USBFilterPair(pUsbProxyBackend, pvId));
176 }
177
178 return pFilterData;
179}
180
181void USBProxyService::removeFilter(void *aId)
182{
183 USBFilterData *pFilterData = (USBFilterData *)aId;
184
185 for (USBFilterList::iterator it = pFilterData->llUsbFilters.begin();
186 it != pFilterData->llUsbFilters.end();
187 ++it)
188 {
189 USBProxyBackend *pUsbProxyBackend = it->first;
190 pUsbProxyBackend->removeFilter(it->second);
191 }
192
193 pFilterData->llUsbFilters.clear();
194 delete pFilterData;
195}
196
197/**
198 * Gets the collection of USB devices, slave of Host::USBDevices.
199 *
200 * This is an interface for the HostImpl::USBDevices property getter.
201 *
202 *
203 * @param aUSBDevices Where to store the pointer to the collection.
204 *
205 * @returns COM status code.
206 *
207 * @remarks The caller must own the write lock of the host object.
208 */
209HRESULT USBProxyService::getDeviceCollection(std::vector<ComPtr<IHostUSBDevice> > &aUSBDevices)
210{
211 AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
212
213 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
214
215 aUSBDevices.resize(mDevices.size());
216 size_t i = 0;
217 for (HostUSBDeviceList::const_iterator it = mDevices.begin(); it != mDevices.end(); ++it, ++i)
218 aUSBDevices[i] = *it;
219
220 return S_OK;
221}
222
223
224/**
225 * Request capture of a specific device.
226 *
227 * This is in an interface for SessionMachine::CaptureUSBDevice(), which is
228 * an internal worker used by Console::AttachUSBDevice() from the VM process.
229 *
230 * When the request is completed, SessionMachine::onUSBDeviceAttach() will
231 * be called for the given machine object.
232 *
233 *
234 * @param aMachine The machine to attach the device to.
235 * @param aId The UUID of the USB device to capture and attach.
236 *
237 * @returns COM status code and error info.
238 *
239 * @remarks This method may operate synchronously as well as asynchronously. In the
240 * former case it will temporarily abandon locks because of IPC.
241 */
242HRESULT USBProxyService::captureDeviceForVM(SessionMachine *aMachine, IN_GUID aId, const com::Utf8Str &aCaptureFilename)
243{
244 ComAssertRet(aMachine, E_INVALIDARG);
245 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
246
247 /*
248 * Translate the device id into a device object.
249 */
250 ComObjPtr<HostUSBDevice> pHostDevice = findDeviceById(aId);
251 if (pHostDevice.isNull())
252 return setError(E_INVALIDARG,
253 tr("The USB device with UUID {%RTuuid} is not currently attached to the host"), Guid(aId).raw());
254
255 /*
256 * Try to capture the device
257 */
258 alock.release();
259 return pHostDevice->i_requestCaptureForVM(aMachine, true /* aSetError */, aCaptureFilename);
260}
261
262
263/**
264 * Notification from VM process about USB device detaching progress.
265 *
266 * This is in an interface for SessionMachine::DetachUSBDevice(), which is
267 * an internal worker used by Console::DetachUSBDevice() from the VM process.
268 *
269 * @param aMachine The machine which is sending the notification.
270 * @param aId The UUID of the USB device is concerns.
271 * @param aDone \a false for the pre-action notification (necessary
272 * for advancing the device state to avoid confusing
273 * the guest).
274 * \a true for the post-action notification. The device
275 * will be subjected to all filters except those of
276 * of \a Machine.
277 *
278 * @returns COM status code.
279 *
280 * @remarks When \a aDone is \a true this method may end up doing IPC to other
281 * VMs when running filters. In these cases it will temporarily
282 * abandon its locks.
283 */
284HRESULT USBProxyService::detachDeviceFromVM(SessionMachine *aMachine, IN_GUID aId, bool aDone)
285{
286 LogFlowThisFunc(("aMachine=%p{%s} aId={%RTuuid} aDone=%RTbool\n",
287 aMachine,
288 aMachine->i_getName().c_str(),
289 Guid(aId).raw(),
290 aDone));
291
292 // get a list of all running machines while we're outside the lock
293 // (getOpenedMachines requests locks which are incompatible with the lock of the machines list)
294 SessionMachinesList llOpenedMachines;
295 mHost->i_parent()->i_getOpenedMachines(llOpenedMachines);
296
297 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
298
299 ComObjPtr<HostUSBDevice> pHostDevice = findDeviceById(aId);
300 ComAssertRet(!pHostDevice.isNull(), E_FAIL);
301 AutoWriteLock devLock(pHostDevice COMMA_LOCKVAL_SRC_POS);
302
303 /*
304 * Work the state machine.
305 */
306 LogFlowThisFunc(("id={%RTuuid} state=%s aDone=%RTbool name={%s}\n",
307 pHostDevice->i_getId().raw(), pHostDevice->i_getStateName(), aDone, pHostDevice->i_getName().c_str()));
308 bool fRunFilters = false;
309 HRESULT hrc = pHostDevice->i_onDetachFromVM(aMachine, aDone, &fRunFilters);
310
311 /*
312 * Run filters if necessary.
313 */
314 if ( SUCCEEDED(hrc)
315 && fRunFilters)
316 {
317 USBProxyBackend *pUsbProxyBackend = pHostDevice->i_getUsbProxyBackend();
318 Assert(aDone && pHostDevice->i_getUnistate() == kHostUSBDeviceState_HeldByProxy && pHostDevice->i_getMachine().isNull());
319 devLock.release();
320 alock.release();
321 HRESULT hrc2 = pUsbProxyBackend->runAllFiltersOnDevice(pHostDevice, llOpenedMachines, aMachine);
322 ComAssertComRC(hrc2);
323 }
324 return hrc;
325}
326
327
328/**
329 * Apply filters for the machine to all eligible USB devices.
330 *
331 * This is in an interface for SessionMachine::CaptureUSBDevice(), which
332 * is an internal worker used by Console::AutoCaptureUSBDevices() from the
333 * VM process at VM startup.
334 *
335 * Matching devices will be attached to the VM and may result IPC back
336 * to the VM process via SessionMachine::onUSBDeviceAttach() depending
337 * on whether the device needs to be captured or not. If capture is
338 * required, SessionMachine::onUSBDeviceAttach() will be called
339 * asynchronously by the USB proxy service thread.
340 *
341 * @param aMachine The machine to capture devices for.
342 *
343 * @returns COM status code, perhaps with error info.
344 *
345 * @remarks Temporarily locks this object, the machine object and some USB
346 * device, and the called methods will lock similar objects.
347 */
348HRESULT USBProxyService::autoCaptureDevicesForVM(SessionMachine *aMachine)
349{
350 LogFlowThisFunc(("aMachine=%p{%s}\n",
351 aMachine,
352 aMachine->i_getName().c_str()));
353
354 /*
355 * Make a copy of the list because we cannot hold the lock protecting it.
356 * (This will not make copies of any HostUSBDevice objects, only reference them.)
357 */
358 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
359 HostUSBDeviceList ListCopy = mDevices;
360 alock.release();
361
362 for (HostUSBDeviceList::iterator it = ListCopy.begin();
363 it != ListCopy.end();
364 ++it)
365 {
366 ComObjPtr<HostUSBDevice> pHostDevice = *it;
367 AutoReadLock devLock(pHostDevice COMMA_LOCKVAL_SRC_POS);
368 if ( pHostDevice->i_getUnistate() == kHostUSBDeviceState_HeldByProxy
369 || pHostDevice->i_getUnistate() == kHostUSBDeviceState_Unused
370 || pHostDevice->i_getUnistate() == kHostUSBDeviceState_Capturable)
371 {
372 USBProxyBackend *pUsbProxyBackend = pHostDevice->i_getUsbProxyBackend();
373 devLock.release();
374 pUsbProxyBackend->runMachineFilters(aMachine, pHostDevice);
375 }
376 }
377
378 return S_OK;
379}
380
381
382/**
383 * Detach all USB devices currently attached to a VM.
384 *
385 * This is in an interface for SessionMachine::DetachAllUSBDevices(), which
386 * is an internal worker used by Console::powerDown() from the VM process
387 * at VM startup, and SessionMachine::uninit() at VM abend.
388 *
389 * This is, like #detachDeviceFromVM(), normally a two stage journey
390 * where \a aDone indicates where we are. In addition we may be called
391 * to clean up VMs that have abended, in which case there will be no
392 * preparatory call. Filters will be applied to the devices in the final
393 * call with the risk that we have to do some IPC when attaching them
394 * to other VMs.
395 *
396 * @param aMachine The machine to detach devices from.
397 *
398 * @returns COM status code, perhaps with error info.
399 *
400 * @remarks Write locks the host object and may temporarily abandon
401 * its locks to perform IPC.
402 */
403HRESULT USBProxyService::detachAllDevicesFromVM(SessionMachine *aMachine, bool aDone, bool aAbnormal)
404{
405 // get a list of all running machines while we're outside the lock
406 // (getOpenedMachines requests locks which are incompatible with the host object lock)
407 SessionMachinesList llOpenedMachines;
408 mHost->i_parent()->i_getOpenedMachines(llOpenedMachines);
409
410 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
411
412 /*
413 * Make a copy of the device list (not the HostUSBDevice objects, just
414 * the list) since we may end up performing IPC and temporarily have
415 * to abandon locks when applying filters.
416 */
417 HostUSBDeviceList ListCopy = mDevices;
418
419 for (HostUSBDeviceList::iterator it = ListCopy.begin();
420 it != ListCopy.end();
421 ++it)
422 {
423 ComObjPtr<HostUSBDevice> pHostDevice = *it;
424 AutoWriteLock devLock(pHostDevice COMMA_LOCKVAL_SRC_POS);
425 if (pHostDevice->i_getMachine() == aMachine)
426 {
427 /*
428 * Same procedure as in detachUSBDevice().
429 */
430 bool fRunFilters = false;
431 HRESULT hrc = pHostDevice->i_onDetachFromVM(aMachine, aDone, &fRunFilters, aAbnormal);
432 if ( SUCCEEDED(hrc)
433 && fRunFilters)
434 {
435 USBProxyBackend *pUsbProxyBackend = pHostDevice->i_getUsbProxyBackend();
436 Assert( aDone
437 && pHostDevice->i_getUnistate() == kHostUSBDeviceState_HeldByProxy
438 && pHostDevice->i_getMachine().isNull());
439 devLock.release();
440 alock.release();
441 HRESULT hrc2 = pUsbProxyBackend->runAllFiltersOnDevice(pHostDevice, llOpenedMachines, aMachine);
442 ComAssertComRC(hrc2);
443 alock.acquire();
444 }
445 }
446 }
447
448 return S_OK;
449}
450
451
452// Internals
453/////////////////////////////////////////////////////////////////////////////
454
455
456/**
457 * Sort a list of USB devices.
458 *
459 * @returns Pointer to the head of the sorted doubly linked list.
460 * @param aDevices Head pointer (can be both singly and doubly linked list).
461 */
462static PUSBDEVICE sortDevices(PUSBDEVICE pDevices)
463{
464 PUSBDEVICE pHead = NULL;
465 PUSBDEVICE pTail = NULL;
466 while (pDevices)
467 {
468 /* unlink head */
469 PUSBDEVICE pDev = pDevices;
470 pDevices = pDev->pNext;
471 if (pDevices)
472 pDevices->pPrev = NULL;
473
474 /* find location. */
475 PUSBDEVICE pCur = pTail;
476 while ( pCur
477 && HostUSBDevice::i_compare(pCur, pDev) > 0)
478 pCur = pCur->pPrev;
479
480 /* insert (after pCur) */
481 pDev->pPrev = pCur;
482 if (pCur)
483 {
484 pDev->pNext = pCur->pNext;
485 pCur->pNext = pDev;
486 if (pDev->pNext)
487 pDev->pNext->pPrev = pDev;
488 else
489 pTail = pDev;
490 }
491 else
492 {
493 pDev->pNext = pHead;
494 if (pHead)
495 pHead->pPrev = pDev;
496 else
497 pTail = pDev;
498 pHead = pDev;
499 }
500 }
501
502 LogFlowFuncLeave();
503 return pHead;
504}
505
506
507/**
508 * Process any relevant changes in the attached USB devices.
509 *
510 * This is called from any available USB proxy backends service thread when they discover
511 * a change.
512 */
513void USBProxyService::i_updateDeviceList(USBProxyBackend *pUsbProxyBackend, PUSBDEVICE pDevices)
514{
515 LogFlowThisFunc(("\n"));
516
517 pDevices = sortDevices(pDevices);
518
519 // get a list of all running machines while we're outside the lock
520 // (getOpenedMachines requests higher priority locks)
521 SessionMachinesList llOpenedMachines;
522 mHost->i_parent()->i_getOpenedMachines(llOpenedMachines);
523
524 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
525
526 /*
527 * Compare previous list with the new list of devices
528 * and merge in any changes while notifying Host.
529 */
530 HostUSBDeviceList::iterator it = this->mDevices.begin();
531 while ( it != mDevices.end()
532 || pDevices)
533 {
534 ComObjPtr<HostUSBDevice> pHostDevice;
535
536 if (it != mDevices.end())
537 pHostDevice = *it;
538
539 /*
540 * Assert that the object is still alive (we still reference it in
541 * the collection and we're the only one who calls uninit() on it.
542 */
543 AutoCaller devCaller(pHostDevice.isNull() ? NULL : pHostDevice);
544 AssertComRC(devCaller.rc());
545
546 /*
547 * Lock the device object since we will read/write its
548 * properties. All Host callbacks also imply the object is locked.
549 */
550 AutoWriteLock devLock(pHostDevice.isNull() ? NULL : pHostDevice
551 COMMA_LOCKVAL_SRC_POS);
552
553 /* Skip all devices not belonging to the same backend. */
554 if ( !pHostDevice.isNull()
555 && pHostDevice->i_getUsbProxyBackend() != pUsbProxyBackend)
556 {
557 ++it;
558 continue;
559 }
560
561 /*
562 * Compare.
563 */
564 int iDiff;
565 if (pHostDevice.isNull())
566 iDiff = 1;
567 else
568 {
569 if (!pDevices)
570 iDiff = -1;
571 else
572 iDiff = pHostDevice->i_compare(pDevices);
573 }
574 if (!iDiff)
575 {
576 /*
577 * The device still there, update the state and move on. The PUSBDEVICE
578 * structure is eaten by updateDeviceState / HostUSBDevice::updateState().
579 */
580 PUSBDEVICE pCur = pDevices;
581 pDevices = pDevices->pNext;
582 pCur->pPrev = pCur->pNext = NULL;
583
584 bool fRunFilters = false;
585 SessionMachine *pIgnoreMachine = NULL;
586 devLock.release();
587 alock.release();
588 if (pUsbProxyBackend->updateDeviceState(pHostDevice, pCur, &fRunFilters, &pIgnoreMachine))
589 pUsbProxyBackend->deviceChanged(pHostDevice,
590 (fRunFilters ? &llOpenedMachines : NULL),
591 pIgnoreMachine);
592 alock.acquire();
593 ++it;
594 }
595 else
596 {
597 if (iDiff > 0)
598 {
599 /*
600 * Head of pDevices was attached.
601 */
602 PUSBDEVICE pNew = pDevices;
603 pDevices = pDevices->pNext;
604 pNew->pPrev = pNew->pNext = NULL;
605
606 ComObjPtr<HostUSBDevice> NewObj;
607 NewObj.createObject();
608 NewObj->init(pNew, pUsbProxyBackend);
609 Log(("USBProxyService::processChanges: attached %p {%s} %s / %p:{.idVendor=%#06x, .idProduct=%#06x, .pszProduct=\"%s\", .pszManufacturer=\"%s\"}\n",
610 (HostUSBDevice *)NewObj,
611 NewObj->i_getName().c_str(),
612 NewObj->i_getStateName(),
613 pNew,
614 pNew->idVendor,
615 pNew->idProduct,
616 pNew->pszProduct,
617 pNew->pszManufacturer));
618
619 mDevices.insert(it, NewObj);
620
621 devLock.release();
622 alock.release();
623 pUsbProxyBackend->deviceAdded(NewObj, llOpenedMachines, pNew);
624 alock.acquire();
625 }
626 else
627 {
628 /*
629 * Check if the device was actually detached or logically detached
630 * as the result of a re-enumeration.
631 */
632 if (!pHostDevice->i_wasActuallyDetached())
633 ++it;
634 else
635 {
636 it = mDevices.erase(it);
637 devLock.release();
638 alock.release();
639 pUsbProxyBackend->deviceRemoved(pHostDevice);
640 Log(("USBProxyService::processChanges: detached %p {%s}\n",
641 (HostUSBDevice *)pHostDevice,
642 pHostDevice->i_getName().c_str()));
643
644 /* from now on, the object is no more valid,
645 * uninitialize to avoid abuse */
646 devCaller.release();
647 pHostDevice->uninit();
648 alock.acquire();
649 }
650 }
651 }
652 } /* while */
653
654 LogFlowThisFunc(("returns void\n"));
655}
656
657
658/**
659 * Returns the global USB filter list stored in the Host object.
660 *
661 * @returns nothing.
662 * @param pGlobalFilters Where to store the global filter list on success.
663 */
664void USBProxyService::i_getUSBFilters(USBDeviceFilterList *pGlobalFilters)
665{
666 mHost->i_getUSBFilters(pGlobalFilters);
667}
668
669
670/**
671 * Searches the list of devices (mDevices) for the given device.
672 *
673 *
674 * @returns Smart pointer to the device on success, NULL otherwise.
675 * @param aId The UUID of the device we're looking for.
676 */
677ComObjPtr<HostUSBDevice> USBProxyService::findDeviceById(IN_GUID aId)
678{
679 Guid Id(aId);
680 ComObjPtr<HostUSBDevice> Dev;
681 for (HostUSBDeviceList::iterator it = mDevices.begin();
682 it != mDevices.end();
683 ++it)
684 if ((*it)->i_getId() == Id)
685 {
686 Dev = (*it);
687 break;
688 }
689
690 return Dev;
691}
692
693/*static*/
694HRESULT USBProxyService::setError(HRESULT aResultCode, const char *aText, ...)
695{
696 va_list va;
697 va_start(va, aText);
698 HRESULT rc = VirtualBoxBase::setErrorInternal(aResultCode,
699 COM_IIDOF(IHost),
700 "USBProxyService",
701 Utf8StrFmt(aText, va),
702 false /* aWarning*/,
703 true /* aLogIt*/);
704 va_end(va);
705 return rc;
706}
707
708/* vi: set tabstop=4 shiftwidth=4 expandtab: */
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