VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/DHCPConfigImpl.cpp@ 79845

Last change on this file since 79845 was 79845, checked in by vboxsync, 5 years ago

Main/DHCPServer,VBoxManage,Dhcpd: Created a new DHCPOption enum that replaced the incorrectly cased DhcpOpt enum in new APIs. Adjusted and documented each and every option and its format as best as I could. Also added two new attributes to IDHCPConfig, one for supressing options (from higher up the configuration scope) and one for forcing unsolicited options on a client. These attributes have not yet been pushed down to Dhcpd. bugref:9288

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 45.8 KB
Line 
1/* $Id: DHCPConfigImpl.cpp 79845 2019-07-17 21:12:50Z vboxsync $ */
2/** @file
3 * VirtualBox Main - IDHCPConfig, IDHCPConfigGlobal, IDHCPConfigGroup, IDHCPConfigIndividual implementation.
4 */
5
6/*
7 * Copyright (C) 2006-2019 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_MAIN_DHCPCONFIG
23#include "DHCPConfigImpl.h"
24#include "LoggingNew.h"
25
26#include <iprt/ctype.h>
27#include <iprt/errcore.h>
28#include <iprt/net.h>
29#include <iprt/cpp/utils.h>
30#include <iprt/cpp/xml.h>
31
32#include <VBox/com/array.h>
33#include <VBox/settings.h>
34
35#include "AutoCaller.h"
36#include "DHCPServerImpl.h"
37#include "MachineImpl.h"
38#include "VirtualBoxImpl.h"
39
40#include "../../NetworkServices/Dhcpd/DhcpOptions.h"
41
42
43
44/*********************************************************************************************************************************
45* DHCPConfig Implementation *
46*********************************************************************************************************************************/
47
48HRESULT DHCPConfig::i_initWithDefaults(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent)
49{
50 unconst(m_pVirtualBox) = a_pVirtualBox;
51 unconst(m_pParent) = a_pParent;
52 return S_OK;
53}
54
55
56HRESULT DHCPConfig::i_initWithSettings(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent, const settings::DHCPConfig &rConfig)
57{
58 unconst(m_pVirtualBox) = a_pVirtualBox;
59 unconst(m_pParent) = a_pParent;
60
61 m_secMinLeaseTime = rConfig.secMinLeaseTime;
62 m_secDefaultLeaseTime = rConfig.secDefaultLeaseTime;
63 m_secMaxLeaseTime = rConfig.secMaxLeaseTime;
64
65 /*
66 * The two option list:
67 */
68 struct
69 {
70 const char *psz;
71 std::vector<DHCPOption_T> *pDst;
72 } aStr2Vec[] =
73 {
74 { rConfig.strForcedOptions.c_str(), &m_vecForcedOptions },
75 { rConfig.strSuppressedOptions.c_str(), &m_vecSuppressedOptions },
76 };
77 for (size_t i = 0; i < RT_ELEMENTS(aStr2Vec); i++)
78 {
79 Assert(aStr2Vec[i].pDst->size() == 0);
80 const char *psz = RTStrStripL(aStr2Vec[i].psz);
81 while (*psz != '\0')
82 {
83 uint8_t bOpt;
84 char *pszNext;
85 int vrc = RTStrToUInt8Ex(psz, &pszNext, 10, &bOpt);
86 if (vrc == VINF_SUCCESS || vrc == VWRN_TRAILING_SPACES)
87 {
88 try
89 {
90 aStr2Vec[i].pDst->push_back((DHCPOption_T)bOpt);
91 }
92 catch (std::bad_alloc &)
93 {
94 return E_OUTOFMEMORY;
95 }
96 }
97 else
98 {
99 LogRelFunc(("Trouble at offset %#zu converting '%s' to a DHCPOption_T vector (vrc=%Rrc)! Ignornig the remainder.\n",
100 psz - aStr2Vec[i].psz, aStr2Vec[i].psz, vrc));
101 break;
102 }
103 psz = RTStrStripL(pszNext);
104 }
105 }
106
107 /*
108 * The option map:
109 */
110 for (settings::DhcpOptionMap::const_iterator it = rConfig.mapOptions.begin(); it != rConfig.mapOptions.end(); ++it)
111 {
112 try
113 {
114 m_OptionMap[it->first] = settings::DhcpOptValue(it->second.strValue, it->second.enmEncoding);
115 }
116 catch (std::bad_alloc &)
117 {
118 return E_OUTOFMEMORY;
119 }
120 }
121
122 return S_OK;
123}
124
125
126HRESULT DHCPConfig::i_saveSettings(settings::DHCPConfig &a_rDst)
127{
128 /* lease times */
129 a_rDst.secMinLeaseTime = m_secMinLeaseTime;
130 a_rDst.secDefaultLeaseTime = m_secDefaultLeaseTime;
131 a_rDst.secMaxLeaseTime = m_secMaxLeaseTime;
132
133 /* Forced and suppressed vectors: */
134 try
135 {
136 a_rDst.strForcedOptions.setNull();
137 for (size_t i = 0; i < m_vecForcedOptions.size(); i++)
138 a_rDst.strForcedOptions.appendPrintf(i ? " %d" : "%d", m_vecForcedOptions[i]);
139
140 a_rDst.strSuppressedOptions.setNull();
141 for (size_t i = 0; i < m_vecSuppressedOptions.size(); i++)
142 a_rDst.strSuppressedOptions.appendPrintf(i ? " %d" : "%d", m_vecSuppressedOptions[i]);
143 }
144 catch (std::bad_alloc &)
145 {
146 return E_OUTOFMEMORY;
147 }
148
149
150 /* Options: */
151 try
152 {
153 a_rDst.mapOptions = m_OptionMap;
154 }
155 catch (std::bad_alloc &)
156 {
157 return E_OUTOFMEMORY;
158 }
159 return S_OK;
160}
161
162
163HRESULT DHCPConfig::i_getScope(DHCPConfigScope_T *aScope)
164{
165 /* No locking needed. */
166 *aScope = m_enmScope;
167 return S_OK;
168}
169
170
171HRESULT DHCPConfig::i_getMinLeaseTime(ULONG *aMinLeaseTime)
172{
173 AutoReadLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
174 *aMinLeaseTime = m_secMinLeaseTime;
175 return S_OK;
176}
177
178
179HRESULT DHCPConfig::i_setMinLeaseTime(ULONG aMinLeaseTime)
180{
181 {
182 AutoWriteLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
183 m_secMinLeaseTime = aMinLeaseTime;
184 }
185 return i_doWriteConfig();
186}
187
188
189HRESULT DHCPConfig::i_getDefaultLeaseTime(ULONG *aDefaultLeaseTime)
190{
191 AutoReadLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
192 *aDefaultLeaseTime = m_secDefaultLeaseTime;
193 return S_OK;
194}
195
196
197HRESULT DHCPConfig::i_setDefaultLeaseTime(ULONG aDefaultLeaseTime)
198{
199 {
200 AutoWriteLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
201 m_secDefaultLeaseTime = aDefaultLeaseTime;
202 }
203 return i_doWriteConfig();
204}
205
206
207HRESULT DHCPConfig::i_getMaxLeaseTime(ULONG *aMaxLeaseTime)
208{
209 AutoReadLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
210 *aMaxLeaseTime = m_secMaxLeaseTime;
211 return S_OK;
212}
213
214
215HRESULT DHCPConfig::i_setMaxLeaseTime(ULONG aMaxLeaseTime)
216{
217 {
218 AutoWriteLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
219 m_secMaxLeaseTime = aMaxLeaseTime;
220 }
221 return i_doWriteConfig();
222}
223
224
225HRESULT DHCPConfig::i_getForcedOptions(std::vector<DHCPOption_T> &aOptions)
226{
227 AutoReadLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
228 try
229 {
230 aOptions = m_vecForcedOptions;
231 }
232 catch (std::bad_alloc &)
233 {
234 return E_OUTOFMEMORY;
235 }
236 return S_OK;
237}
238
239
240HRESULT DHCPConfig::i_setForcedOptions(const std::vector<DHCPOption_T> &aOptions)
241{
242 /*
243 * Validate the options.
244 */
245 try
246 {
247 std::map<DHCPOption_T, bool> mapDuplicates;
248 for (size_t i = 0; i < aOptions.size(); i++)
249 {
250 DHCPOption_T enmOpt = aOptions[i];
251 if ((int)enmOpt > 0 && (int)enmOpt < 255)
252 {
253 if (mapDuplicates.find(enmOpt) == mapDuplicates.end())
254 mapDuplicates[enmOpt] = true;
255 else
256 return m_pHack->setError(E_INVALIDARG, m_pHack->tr("Duplicate option value: %d"), (int)enmOpt);
257 }
258 else
259 return m_pHack->setError(E_INVALIDARG, m_pHack->tr("Invalid option value: %d"), (int)enmOpt);
260 }
261 }
262 catch (std::bad_alloc &)
263 {
264 return E_OUTOFMEMORY;
265 }
266
267 /*
268 * Do the updating.
269 */
270 {
271 AutoWriteLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
272
273 /* Actually changed? */
274 if (m_vecForcedOptions.size() == aOptions.size())
275 {
276 ssize_t i = m_vecForcedOptions.size();
277 while (i-- > 0)
278 if (m_vecForcedOptions[i] != aOptions[i])
279 break;
280 if (i < 0)
281 return S_OK;
282 }
283
284 /* Copy over the changes: */
285 try
286 {
287 m_vecForcedOptions = aOptions;
288 }
289 catch (std::bad_alloc &)
290 {
291 return E_OUTOFMEMORY;
292 }
293 }
294
295 return i_doWriteConfig();
296}
297
298
299HRESULT DHCPConfig::i_getSuppressedOptions(std::vector<DHCPOption_T> &aOptions)
300{
301 AutoReadLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
302 try
303 {
304 aOptions = m_vecSuppressedOptions;
305 }
306 catch (std::bad_alloc &)
307 {
308 return E_OUTOFMEMORY;
309 }
310 return S_OK;
311}
312
313
314HRESULT DHCPConfig::i_setSuppressedOptions(const std::vector<DHCPOption_T> &aOptions)
315{
316 /*
317 * Validate and normalize it.
318 */
319 std::map<DHCPOption_T, bool> mapNormalized;
320 try
321 {
322 for (size_t i = 0; i < aOptions.size(); i++)
323 {
324 DHCPOption_T enmOpt = aOptions[i];
325 if ((int)enmOpt > 0 && (int)enmOpt < 255)
326 mapNormalized[enmOpt] = true;
327 else
328 return m_pHack->setError(E_INVALIDARG, m_pHack->tr("Invalid option value: %d"), (int)enmOpt);
329 }
330 }
331 catch (std::bad_alloc &)
332 {
333 return E_OUTOFMEMORY;
334 }
335
336 /*
337 * Do the updating.
338 */
339 {
340 AutoWriteLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
341
342 /* Actually changed? */
343 if (m_vecSuppressedOptions.size() == mapNormalized.size())
344 {
345 size_t i = 0;
346 for (std::map<DHCPOption_T, bool>::const_iterator itMap = mapNormalized.begin();; ++itMap, i++)
347 {
348 if (itMap == mapNormalized.end())
349 return S_OK; /* no change */
350 if (itMap->first != m_vecSuppressedOptions[i])
351 break;
352 }
353 }
354
355 /* Copy over the changes: */
356 try
357 {
358 m_vecSuppressedOptions.resize(mapNormalized.size());
359 size_t i = 0;
360 for (std::map<DHCPOption_T, bool>::const_iterator itMap = mapNormalized.begin();
361 itMap != mapNormalized.end(); ++itMap, i++)
362 m_vecSuppressedOptions[i] = itMap->first;
363 }
364 catch (std::bad_alloc &)
365 {
366 return E_OUTOFMEMORY;
367 }
368 }
369
370 return i_doWriteConfig();
371}
372
373
374HRESULT DHCPConfig::i_setOption(DHCPOption_T aOption, DHCPOptionEncoding_T aEncoding, const com::Utf8Str &aValue)
375{
376 /*
377 * Validate the option as there is no point in allowing the user to set
378 * something that the DHCP server does not grok. It will only lead to
379 * startup failures an no DHCP. We share this code with the server.
380 */
381 DhcpOption *pParsed = NULL;
382 int rc = VINF_SUCCESS;
383 try
384 {
385 pParsed = DhcpOption::parse((uint8_t)aOption, aEncoding, aValue.c_str(), &rc);
386 }
387 catch (std::bad_alloc &)
388 {
389 return E_OUTOFMEMORY;
390 }
391 if (pParsed)
392 {
393 delete pParsed;
394
395 /*
396 * Add/change it.
397 */
398 {
399 AutoWriteLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
400 try
401 {
402 m_OptionMap[aOption] = settings::DhcpOptValue(aValue, aEncoding);
403 }
404 catch (std::bad_alloc &)
405 {
406 return E_OUTOFMEMORY;
407 }
408 }
409 i_doWriteConfig();
410 return S_OK;
411 }
412
413 if (rc == VERR_WRONG_TYPE)
414 return m_pHack->setError(E_INVALIDARG, m_pHack->tr("Unsupported encoding %d (option %d, value %s)"),
415 (int)aEncoding, (int)aOption, aValue.c_str());
416 if (rc == VERR_NOT_SUPPORTED)
417 return m_pHack->setError(E_INVALIDARG, m_pHack->tr("Unsupported option %d (encoding %d, value %s)"),
418 (int)aOption, (int)aEncoding, aValue.c_str());
419 return m_pHack->setError(E_INVALIDARG, m_pHack->tr("Malformed option %d value '%s' (encoding %d, rc=%Rrc)"),
420 (int)aOption, aValue.c_str(), (int)aEncoding, rc);
421}
422
423
424HRESULT DHCPConfig::i_removeOption(DHCPOption_T aOption)
425{
426 {
427 AutoWriteLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
428 settings::DhcpOptionMap::iterator it = m_OptionMap.find(aOption);
429 if (it != m_OptionMap.end())
430 m_OptionMap.erase(it);
431 else
432 return m_pHack->setError(VBOX_E_OBJECT_NOT_FOUND, m_pHack->tr("DHCP option %u was not found"), aOption);
433 }
434 return i_doWriteConfig();
435}
436
437
438HRESULT DHCPConfig::i_removeAllOptions()
439{
440 {
441 AutoWriteLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
442 m_OptionMap.erase(m_OptionMap.begin(), m_OptionMap.end());
443 }
444 return i_doWriteConfig();
445}
446
447
448HRESULT DHCPConfig::i_getOption(DHCPOption_T aOption, DHCPOptionEncoding_T *aEncoding, com::Utf8Str &aValue)
449{
450 AutoReadLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
451 settings::DhcpOptionMap::const_iterator it = m_OptionMap.find(aOption);
452 if (it != m_OptionMap.end())
453 {
454 *aEncoding = it->second.enmEncoding;
455 return aValue.assignEx(it->second.strValue);
456 }
457 return m_pHack->setError(VBOX_E_OBJECT_NOT_FOUND, m_pHack->tr("DHCP option %u was not found"), aOption);
458}
459
460
461HRESULT DHCPConfig::i_getAllOptions(std::vector<DHCPOption_T> &aOptions, std::vector<DHCPOptionEncoding_T> &aEncodings,
462 std::vector<com::Utf8Str> &aValues)
463{
464 AutoReadLock alock(m_pHack COMMA_LOCKVAL_SRC_POS);
465 try
466 {
467 aOptions.resize(m_OptionMap.size());
468 aEncodings.resize(m_OptionMap.size());
469 aValues.resize(m_OptionMap.size());
470 size_t i = 0;
471 for (settings::DhcpOptionMap::iterator it = m_OptionMap.begin(); it != m_OptionMap.end(); ++it, i++)
472 {
473 aOptions[i] = it->first;
474 aEncodings[i] = it->second.enmEncoding;
475 aValues[i] = it->second.strValue;
476 }
477 }
478 catch (std::bad_alloc &)
479 {
480 return E_OUTOFMEMORY;
481 }
482 return S_OK;
483}
484
485
486HRESULT DHCPConfig::i_remove()
487{
488 return m_pParent->i_removeConfig(this, m_enmScope);
489}
490
491
492
493/**
494 * Causes the global VirtualBox configuration file to be written
495 *
496 * @returns COM status code.
497 *
498 * @note Must hold no locks when this is called!
499 * @note Public because DHCPGroupCondition needs to call it too.
500 */
501HRESULT DHCPConfig::i_doWriteConfig()
502{
503 AssertPtrReturn(m_pVirtualBox, E_FAIL);
504
505 AutoWriteLock alock(m_pVirtualBox COMMA_LOCKVAL_SRC_POS);
506 return m_pVirtualBox->i_saveSettings();
507}
508
509
510/**
511 * Produces the Dhcpd configuration.
512 *
513 * The base class only saves DHCP options.
514 *
515 * @param pElmConfig The element where to put the configuration.
516 * @throws std::bad_alloc
517 */
518void DHCPConfig::i_writeDhcpdConfig(xml::ElementNode *pElmConfig)
519{
520 if (m_secMinLeaseTime > 0 )
521 pElmConfig->setAttribute("secMinLeaseTime", (uint32_t)m_secMinLeaseTime);
522 if (m_secDefaultLeaseTime > 0 )
523 pElmConfig->setAttribute("secDefaultLeaseTime", (uint32_t)m_secDefaultLeaseTime);
524 if (m_secMaxLeaseTime > 0 )
525 pElmConfig->setAttribute("secMaxLeaseTime", (uint32_t)m_secMaxLeaseTime);
526
527 for (settings::DhcpOptionMap::const_iterator it = m_OptionMap.begin(); it != m_OptionMap.end(); ++it)
528 {
529 xml::ElementNode *pOption = pElmConfig->createChild("Option");
530 pOption->setAttribute("name", (int)it->first);
531 pOption->setAttribute("encoding", it->second.enmEncoding);
532 pOption->setAttribute("value", it->second.strValue);
533 }
534}
535
536
537
538/*********************************************************************************************************************************
539* DHCPGlobalConfig Implementation *
540*********************************************************************************************************************************/
541#undef LOG_GROUP
542#define LOG_GROUP LOG_GROUP_MAIN_DHCPGLOBALCONFIG
543
544HRESULT DHCPGlobalConfig::initWithDefaults(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent)
545{
546 AutoInitSpan autoInitSpan(this);
547 AssertReturn(autoInitSpan.isOk(), E_FAIL);
548
549 HRESULT hrc = DHCPConfig::i_initWithDefaults(a_pVirtualBox, a_pParent);
550 if (SUCCEEDED(hrc))
551 hrc = i_setOption(DHCPOption_SubnetMask, DHCPOptionEncoding_Normal, "0.0.0.0");
552
553 if (SUCCEEDED(hrc))
554 autoInitSpan.setSucceeded();
555 return hrc;
556}
557
558
559HRESULT DHCPGlobalConfig::initWithSettings(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent, const settings::DHCPConfig &rConfig)
560{
561 AutoInitSpan autoInitSpan(this);
562 AssertReturn(autoInitSpan.isOk(), E_FAIL);
563
564 HRESULT hrc = DHCPConfig::i_initWithSettings(a_pVirtualBox, a_pParent, rConfig);
565 if (SUCCEEDED(hrc))
566 autoInitSpan.setSucceeded();
567 else
568 autoInitSpan.setFailed(hrc);
569 return hrc;
570}
571
572
573void DHCPGlobalConfig::uninit()
574{
575 AutoUninitSpan autoUninitSpan(this);
576 if (!autoUninitSpan.uninitDone())
577 autoUninitSpan.setSucceeded();
578}
579
580
581HRESULT DHCPGlobalConfig::i_saveSettings(settings::DHCPConfig &a_rDst)
582{
583 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
584
585 return DHCPConfig::i_saveSettings(a_rDst);
586}
587
588
589/**
590 * For getting the network mask option value (IDHCPServer::netmask attrib).
591 *
592 * @returns COM status code.
593 * @param a_rDst Where to return it.
594 * @throws nothing
595 */
596HRESULT DHCPGlobalConfig::i_getNetworkMask(com::Utf8Str &a_rDst)
597{
598 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
599 settings::DhcpOptionMap::const_iterator it = m_OptionMap.find(DHCPOption_SubnetMask);
600 if (it != m_OptionMap.end())
601 {
602 if (it->second.enmEncoding == DHCPOptionEncoding_Normal)
603 return a_rDst.assignEx(it->second.strValue);
604 return setError(VBOX_E_OBJECT_NOT_FOUND, tr("DHCP option DhcpOpt_SubnetMask is not in a legacy encoding"));
605 }
606 return setError(VBOX_E_OBJECT_NOT_FOUND, tr("DHCP option DhcpOpt_SubnetMask was not found"));
607}
608
609
610/**
611 * For setting the network mask option value (IDHCPServer::netmask attrib).
612 *
613 * @returns COM status code.
614 * @param a_rSrc The new value.
615 * @throws nothing
616 */
617HRESULT DHCPGlobalConfig::i_setNetworkMask(const com::Utf8Str &a_rSrc)
618{
619 /* Validate it before setting it: */
620 RTNETADDRIPV4 AddrIgnored;
621 int vrc = RTNetStrToIPv4Addr(a_rSrc.c_str(), &AddrIgnored);
622 if (RT_FAILURE(vrc))
623 return setErrorBoth(E_INVALIDARG, vrc, tr("Invalid IPv4 netmask '%s': %Rrc"), a_rSrc.c_str(), vrc);
624
625 return i_setOption(DHCPOption_SubnetMask, DHCPOptionEncoding_Normal, a_rSrc);
626}
627
628
629/**
630 * Overriden to ensure the sanity of the DhcpOpt_SubnetMask option.
631 */
632HRESULT DHCPGlobalConfig::i_setOption(DHCPOption_T aOption, DHCPOptionEncoding_T aEncoding, const com::Utf8Str &aValue)
633{
634 if (aOption != DhcpOpt_SubnetMask || aEncoding == DHCPOptionEncoding_Normal)
635 return DHCPConfig::i_setOption(aOption, aEncoding, aValue);
636 return setError(E_FAIL, tr("DhcpOpt_SubnetMask must use DHCPOptionEncoding_Normal as it is reflected by IDHCPServer::networkMask"));
637}
638
639
640/**
641 * Overriden to ensure the sanity of the DhcpOpt_SubnetMask option.
642 */
643HRESULT DHCPGlobalConfig::i_removeOption(DHCPOption_T aOption)
644{
645 if (aOption != DhcpOpt_SubnetMask)
646 return DHCPConfig::i_removeOption(aOption);
647 return setError(E_FAIL, tr("DhcpOpt_SubnetMask cannot be removed as it reflects IDHCPServer::networkMask"));
648}
649
650
651/**
652 * Overriden to preserve the DhcpOpt_SubnetMask option.
653 */
654HRESULT DHCPGlobalConfig::i_removeAllOptions()
655{
656 {
657 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
658 settings::DhcpOptionMap::iterator it = m_OptionMap.find(DHCPOption_SubnetMask);
659 m_OptionMap.erase(m_OptionMap.begin(), it);
660 if (it != m_OptionMap.end())
661 {
662 ++it;
663 if (it != m_OptionMap.end())
664 m_OptionMap.erase(it, m_OptionMap.end());
665 }
666 }
667
668 return i_doWriteConfig();
669}
670
671
672/**
673 * Overriden to prevent removal.
674 */
675HRESULT DHCPGlobalConfig::i_remove()
676{
677 return setError(E_ACCESSDENIED, tr("Cannot delete the global config"));
678}
679
680
681
682/*********************************************************************************************************************************
683* DHCPGroupCondition Implementation *
684*********************************************************************************************************************************/
685#undef LOG_GROUP
686#define LOG_GROUP LOG_GROUP_MAIN_DHCPGROUPCONDITION
687
688HRESULT DHCPGroupCondition::initWithDefaults(DHCPGroupConfig *a_pParent, bool a_fInclusive, DHCPGroupConditionType_T a_enmType,
689 const com::Utf8Str a_strValue)
690{
691 AutoInitSpan autoInitSpan(this);
692 AssertReturn(autoInitSpan.isOk(), E_FAIL);
693
694 m_pParent = a_pParent;
695 m_fInclusive = a_fInclusive;
696 m_enmType = a_enmType;
697 HRESULT hrc = m_strValue.assignEx(a_strValue);
698
699 if (SUCCEEDED(hrc))
700 autoInitSpan.setSucceeded();
701 else
702 autoInitSpan.setFailed(hrc);
703 return hrc;
704}
705
706
707HRESULT DHCPGroupCondition::initWithSettings(DHCPGroupConfig *a_pParent, const settings::DHCPGroupCondition &a_rSrc)
708{
709 return initWithDefaults(a_pParent, a_rSrc.fInclusive, a_rSrc.enmType, a_rSrc.strValue);
710}
711
712
713void DHCPGroupCondition::uninit()
714{
715 AutoUninitSpan autoUninitSpan(this);
716 if (!autoUninitSpan.uninitDone())
717 autoUninitSpan.setSucceeded();
718}
719
720
721HRESULT DHCPGroupCondition::i_saveSettings(settings::DHCPGroupCondition &a_rDst)
722{
723 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
724
725 a_rDst.fInclusive = m_fInclusive;
726 a_rDst.enmType = m_enmType;
727 return a_rDst.strValue.assignEx(m_strValue);
728}
729
730
731/**
732 * Worker for validating the condition value according to the given type.
733 *
734 * @returns COM status code.
735 * @param enmType The condition type.
736 * @param strValue The condition value.
737 * @param pErrorDst The object to use for reporting errors.
738 */
739/*static*/ HRESULT DHCPGroupCondition::i_validateTypeAndValue(DHCPGroupConditionType_T enmType, com::Utf8Str const &strValue,
740 VirtualBoxBase *pErrorDst)
741{
742 switch (enmType)
743 {
744 case DHCPGroupConditionType_MAC:
745 {
746 RTMAC MACAddress;
747 int vrc = RTNetStrToMacAddr(strValue.c_str(), &MACAddress);
748 if (RT_SUCCESS(vrc))
749 return S_OK;
750 return pErrorDst->setError(E_INVALIDARG, pErrorDst->tr("Not a valid MAC address: %s"), strValue.c_str());
751 }
752
753 case DHCPGroupConditionType_MACWildcard:
754 {
755 /* This must be colon separated double xdigit bytes. Single bytes
756 shorthand or raw hexstrings won't match anything. For reasons of
757 simplicity, '?' can only be used to match xdigits, '*' must match 1+
758 chars. */
759 /** @todo test this properly... */
760 const char *psz = strValue.c_str();
761 size_t off = 0;
762 unsigned cPairsLeft = 6;
763 bool fSeenAsterisk = false;
764 for (;;)
765 {
766 char ch = psz[off++];
767 if (RT_C_IS_XDIGIT(ch) || ch == '?')
768 {
769 ch = psz[off++];
770 if (RT_C_IS_XDIGIT(ch) || ch == '?')
771 {
772 ch = psz[off++];
773 cPairsLeft -= 1;
774 if (cPairsLeft == 0)
775 {
776 if (!ch)
777 return S_OK;
778 return pErrorDst->setError(E_INVALIDARG,
779 pErrorDst->tr("Trailing chars in MAC wildcard address: %s (offset %zu)"),
780 psz, off - 1);
781 }
782 if (ch == ':' || ch == '*')
783 continue;
784 if (ch == '\0' && fSeenAsterisk)
785 return S_OK;
786 return pErrorDst->setError(E_INVALIDARG,
787 pErrorDst->tr("Malformed MAC wildcard address: %s (offset %zu)"),
788 psz, off - 1);
789 }
790
791 if (ch == '*')
792 {
793 fSeenAsterisk = true;
794 do
795 ch = psz[off++];
796 while (ch == '*');
797 if (ch == '\0')
798 return S_OK;
799 cPairsLeft -= 1;
800 if (cPairsLeft == 0)
801 return pErrorDst->setError(E_INVALIDARG,
802 pErrorDst->tr("Trailing chars in MAC wildcard address: %s (offset %zu)"),
803 psz, off - 1);
804 if (ch == ':')
805 continue;
806 }
807 else
808 return pErrorDst->setError(E_INVALIDARG, pErrorDst->tr("Malformed MAC wildcard address: %s (offset %zu)"),
809 psz, off - 1);
810 }
811 else if (ch == '*')
812 {
813 fSeenAsterisk = true;
814 do
815 ch = psz[off++];
816 while (ch == '*');
817 if (ch == '\0')
818 return S_OK;
819 if (ch == ':')
820 {
821 cPairsLeft -= 1;
822 if (cPairsLeft == 0)
823 return pErrorDst->setError(E_INVALIDARG,
824 pErrorDst->tr("Trailing chars in MAC wildcard address: %s (offset %zu)"),
825 psz, off - 1);
826 continue;
827 }
828
829 }
830 else
831 return pErrorDst->setError(E_INVALIDARG, pErrorDst->tr("Malformed MAC wildcard address: %s (offset %zu)"),
832 psz, off - 1);
833
834 /* Pick up after '*' in the two cases above: ch is not ':' or '\0'. */
835 Assert(ch != ':' && ch != '\0');
836 if (RT_C_IS_XDIGIT(ch) || ch == '?')
837 {
838 ch = psz[off++];
839 if (RT_C_IS_XDIGIT(ch) || ch == '?' || ch == '*')
840 {
841 off -= 2;
842 continue;
843 }
844 if (ch == ':')
845 {
846 ch = psz[off++];
847 if (ch == '\0')
848 return S_OK;
849 cPairsLeft -= 1;
850 if (cPairsLeft == 0)
851 return pErrorDst->setError(E_INVALIDARG,
852 pErrorDst->tr("Trailing chars in MAC wildcard address: %s (offset %zu)"),
853 psz, off - 1);
854 continue;
855 }
856 if (ch == '\0')
857 return S_OK;
858 return pErrorDst->setError(E_INVALIDARG,
859 pErrorDst->tr("Trailing chars in MAC wildcard address: %s (offset %zu)"),
860 psz, off - 1);
861 }
862 return pErrorDst->setError(E_INVALIDARG,
863 pErrorDst->tr("Malformed MAC wildcard address: %s (offset %zu)"),
864 psz, off - 1);
865 }
866 break;
867 }
868
869 case DHCPGroupConditionType_vendorClassID:
870 case DHCPGroupConditionType_vendorClassIDWildcard:
871 case DHCPGroupConditionType_userClassID:
872 case DHCPGroupConditionType_userClassIDWildcard:
873 if (strValue.length() == 0)
874 return pErrorDst->setError(E_INVALIDARG, pErrorDst->tr("Value cannot be empty"));
875 if (strValue.length() < 255)
876 return pErrorDst->setError(E_INVALIDARG, pErrorDst->tr("Value is too long: %zu bytes"), strValue.length());
877 break;
878
879 default:
880 return pErrorDst->setError(E_INVALIDARG, pErrorDst->tr("Invalid condition type: %d"), enmType);
881 }
882
883 return S_OK;
884}
885
886
887HRESULT DHCPGroupCondition::getInclusive(BOOL *aInclusive)
888{
889 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
890 *aInclusive = m_fInclusive;
891 return S_OK;
892}
893
894
895HRESULT DHCPGroupCondition::setInclusive(BOOL aInclusive)
896{
897 {
898 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
899 if ((aInclusive != FALSE) == m_fInclusive)
900 return S_OK;
901 m_fInclusive = aInclusive != FALSE;
902 }
903 return m_pParent->i_doWriteConfig();
904}
905
906
907HRESULT DHCPGroupCondition::getType(DHCPGroupConditionType_T *aType)
908{
909 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
910 *aType = m_enmType;
911 return S_OK;
912}
913
914
915HRESULT DHCPGroupCondition::setType(DHCPGroupConditionType_T aType)
916{
917 {
918 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
919 if (aType == m_enmType)
920 return S_OK;
921 HRESULT hrc = i_validateTypeAndValue(aType, m_strValue, this);
922 if (FAILED(hrc))
923 return hrc;
924 m_enmType = aType;
925 }
926 return m_pParent->i_doWriteConfig();
927}
928
929
930HRESULT DHCPGroupCondition::getValue(com::Utf8Str &aValue)
931{
932 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
933 return aValue.assignEx(m_strValue);
934}
935
936
937HRESULT DHCPGroupCondition::setValue(const com::Utf8Str &aValue)
938{
939 {
940 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
941 if (aValue == m_strValue)
942 return S_OK;
943 HRESULT hrc = i_validateTypeAndValue(m_enmType, aValue, this);
944 if (FAILED(hrc))
945 return hrc;
946 hrc = m_strValue.assignEx(aValue);
947 if (FAILED(hrc))
948 return hrc;
949 }
950 return m_pParent->i_doWriteConfig();
951}
952
953
954HRESULT DHCPGroupCondition::remove()
955{
956 return m_pParent->i_removeCondition(this);
957}
958
959
960
961/*********************************************************************************************************************************
962* DHCPGroupConfig Implementation *
963*********************************************************************************************************************************/
964#undef LOG_GROUP
965#define LOG_GROUP LOG_GROUP_MAIN_DHCPGROUPCONFIG
966
967
968HRESULT DHCPGroupConfig::initWithDefaults(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent, const com::Utf8Str &a_rName)
969{
970 AutoInitSpan autoInitSpan(this);
971 AssertReturn(autoInitSpan.isOk(), E_FAIL);
972
973 Assert(m_Conditions.size() == 0);
974 HRESULT hrc = DHCPConfig::i_initWithDefaults(a_pVirtualBox, a_pParent);
975 if (SUCCEEDED(hrc))
976 hrc = m_strName.assignEx(a_rName);
977
978 if (SUCCEEDED(hrc))
979 autoInitSpan.setSucceeded();
980 else
981 autoInitSpan.setFailed(hrc);
982 return hrc;
983}
984
985
986HRESULT DHCPGroupConfig::initWithSettings(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent, const settings::DHCPGroupConfig &a_rSrc)
987{
988 AutoInitSpan autoInitSpan(this);
989 AssertReturn(autoInitSpan.isOk(), E_FAIL);
990
991 Assert(m_Conditions.size() == 0);
992 HRESULT hrc = DHCPConfig::i_initWithSettings(a_pVirtualBox, a_pParent, a_rSrc);
993 if (SUCCEEDED(hrc))
994 hrc = m_strName.assignEx(a_rSrc.strName);
995
996 for (settings::DHCPGroupConditionVec::const_iterator it = a_rSrc.vecConditions.begin();
997 it != a_rSrc.vecConditions.end() && SUCCEEDED(hrc); ++it)
998 {
999 ComObjPtr<DHCPGroupCondition> ptrCondition;
1000 hrc = ptrCondition.createObject();
1001 if (SUCCEEDED(hrc))
1002 {
1003 hrc = ptrCondition->initWithSettings(this, *it);
1004 if (SUCCEEDED(hrc))
1005 {
1006 try
1007 {
1008 m_Conditions.push_back(ptrCondition);
1009 }
1010 catch (std::bad_alloc &)
1011 {
1012 hrc = E_OUTOFMEMORY;
1013 }
1014 }
1015 }
1016 }
1017
1018 if (SUCCEEDED(hrc))
1019 autoInitSpan.setSucceeded();
1020 else
1021 autoInitSpan.setFailed(hrc);
1022 return hrc;
1023}
1024
1025
1026void DHCPGroupConfig::uninit()
1027{
1028 AutoUninitSpan autoUninitSpan(this);
1029 if (!autoUninitSpan.uninitDone())
1030 autoUninitSpan.setSucceeded();
1031}
1032
1033
1034HRESULT DHCPGroupConfig::i_saveSettings(settings::DHCPGroupConfig &a_rDst)
1035{
1036 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1037
1038 HRESULT hrc = DHCPConfig::i_saveSettings(a_rDst);
1039 if (SUCCEEDED(hrc))
1040 hrc = a_rDst.strName.assignEx(m_strName);
1041 if (SUCCEEDED(hrc))
1042 {
1043 size_t const cConditions = m_Conditions.size();
1044 try
1045 {
1046 a_rDst.vecConditions.resize(cConditions);
1047 }
1048 catch (std::bad_alloc &)
1049 {
1050 hrc = E_OUTOFMEMORY;
1051 }
1052
1053 for (size_t i = 0; i < cConditions && SUCCEEDED(hrc); i++)
1054 hrc = m_Conditions[i]->i_saveSettings(a_rDst.vecConditions[i]);
1055 }
1056 return hrc;
1057}
1058
1059
1060HRESULT DHCPGroupConfig::i_removeCondition(DHCPGroupCondition *a_pCondition)
1061{
1062 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1063
1064 for (ConditionsIterator it = m_Conditions.begin(); it != m_Conditions.end();)
1065 {
1066 DHCPGroupCondition *pCurCondition = *it;
1067 if (pCurCondition == a_pCondition)
1068 it = m_Conditions.erase(it);
1069 else
1070 ++it;
1071 }
1072
1073 /* Never mind if already delete, right? */
1074 return S_OK;
1075}
1076
1077
1078/**
1079 * Overridden to add a 'name' attribute and emit condition child elements.
1080 */
1081void DHCPGroupConfig::i_writeDhcpdConfig(xml::ElementNode *a_pElmGroup)
1082{
1083 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1084
1085 /* The name attribute: */
1086 a_pElmGroup->setAttribute("name", m_strName);
1087
1088 /*
1089 * Conditions:
1090 */
1091 for (ConditionsIterator it = m_Conditions.begin(); it != m_Conditions.end(); ++it)
1092 {
1093 xml::ElementNode *pElmCondition;
1094 switch ((*it)->i_getType())
1095 {
1096 case DHCPGroupConditionType_MAC:
1097 pElmCondition = a_pElmGroup->createChild("ConditionMAC");
1098 break;
1099 case DHCPGroupConditionType_MACWildcard:
1100 pElmCondition = a_pElmGroup->createChild("ConditionMACWildcard");
1101 break;
1102 case DHCPGroupConditionType_vendorClassID:
1103 pElmCondition = a_pElmGroup->createChild("ConditionVendorClassID");
1104 break;
1105 case DHCPGroupConditionType_vendorClassIDWildcard:
1106 pElmCondition = a_pElmGroup->createChild("ConditionVendorClassIDWildcard");
1107 break;
1108 case DHCPGroupConditionType_userClassID:
1109 pElmCondition = a_pElmGroup->createChild("ConditionUserClassID");
1110 break;
1111 case DHCPGroupConditionType_userClassIDWildcard:
1112 pElmCondition = a_pElmGroup->createChild("ConditionUserClassIDWildcard");
1113 break;
1114 default:
1115 AssertLogRelMsgFailed(("m_enmType=%d\n", (*it)->i_getType()));
1116 continue;
1117 }
1118 pElmCondition->setAttribute("inclusive", (*it)->i_getInclusive());
1119 pElmCondition->setAttribute("value", (*it)->i_getValue());
1120 }
1121
1122 DHCPConfig::i_writeDhcpdConfig(a_pElmGroup);
1123}
1124
1125
1126HRESULT DHCPGroupConfig::getName(com::Utf8Str &aName)
1127{
1128 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1129 return aName.assignEx(m_strName);
1130}
1131
1132
1133HRESULT DHCPGroupConfig::setName(const com::Utf8Str &aName)
1134{
1135 {
1136 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1137 if (aName == m_strName)
1138 return S_OK;
1139 HRESULT hrc = m_strName.assignEx(aName);
1140 if (FAILED(hrc))
1141 return hrc;
1142 }
1143 return i_doWriteConfig();
1144}
1145
1146
1147HRESULT DHCPGroupConfig::getConditions(std::vector<ComPtr<IDHCPGroupCondition> > &aConditions)
1148{
1149 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1150 size_t const cConditions = m_Conditions.size();
1151 try
1152 {
1153 aConditions.resize(cConditions);
1154 }
1155 catch (std::bad_alloc &)
1156 {
1157 return E_OUTOFMEMORY;
1158 }
1159 HRESULT hrc = S_OK;
1160 for (size_t i = 0; i < cConditions && SUCCEEDED(hrc); i++)
1161 hrc = m_Conditions[i].queryInterfaceTo(aConditions[i].asOutParam());
1162 return hrc;
1163}
1164
1165
1166HRESULT DHCPGroupConfig::addCondition(BOOL aInclusive, DHCPGroupConditionType_T aType, const com::Utf8Str &aValue,
1167 ComPtr<IDHCPGroupCondition> &aCondition)
1168{
1169 /*
1170 * Valdiate it.
1171 */
1172 HRESULT hrc = DHCPGroupCondition::i_validateTypeAndValue(aType, aValue, this);
1173 if (SUCCEEDED(hrc))
1174 {
1175 /*
1176 * Add it.
1177 */
1178 ComObjPtr<DHCPGroupCondition> ptrCondition;
1179 hrc = ptrCondition.createObject();
1180 if (SUCCEEDED(hrc))
1181 hrc = ptrCondition->initWithDefaults(this, aInclusive != FALSE, aType, aValue);
1182 if (SUCCEEDED(hrc))
1183 {
1184 hrc = ptrCondition.queryInterfaceTo(aCondition.asOutParam());
1185 if (SUCCEEDED(hrc))
1186 {
1187 {
1188 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1189 try
1190 {
1191 m_Conditions.push_back(ptrCondition);
1192 }
1193 catch (std::bad_alloc &)
1194 {
1195 aCondition.setNull();
1196 return E_OUTOFMEMORY;
1197 }
1198 }
1199
1200 hrc = i_doWriteConfig();
1201 if (FAILED(hrc))
1202 aCondition.setNull();
1203 }
1204 }
1205 }
1206
1207 return hrc;
1208}
1209
1210
1211HRESULT DHCPGroupConfig::removeAllConditions()
1212{
1213 {
1214 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1215 if (m_Conditions.size() == 0)
1216 return S_OK;
1217
1218 /** @todo sever the weak parent link for each entry... */
1219 m_Conditions.erase(m_Conditions.begin(), m_Conditions.end());
1220 }
1221
1222 return i_doWriteConfig();
1223}
1224
1225
1226
1227/*********************************************************************************************************************************
1228* DHCPIndividualConfig Implementation *
1229*********************************************************************************************************************************/
1230#undef LOG_GROUP
1231#define LOG_GROUP LOG_GROUP_MAIN_DHCPINDIVIDUALCONFIG
1232
1233HRESULT DHCPIndividualConfig::initWithMachineIdAndSlot(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent,
1234 com::Guid const &a_idMachine, ULONG a_uSlot, uint32_t a_uMACAddressVersion)
1235{
1236 AutoInitSpan autoInitSpan(this);
1237 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1238
1239 HRESULT hrc = DHCPConfig::i_initWithDefaults(a_pVirtualBox, a_pParent);
1240 if (SUCCEEDED(hrc))
1241 {
1242 unconst(m_enmScope) = DHCPConfigScope_MachineNIC;
1243 unconst(m_idMachine) = a_idMachine;
1244 unconst(m_uSlot) = a_uSlot;
1245 m_uMACAddressResolvedVersion = a_uMACAddressVersion;
1246
1247 autoInitSpan.setSucceeded();
1248 }
1249 return hrc;
1250}
1251
1252
1253HRESULT DHCPIndividualConfig::initWithMACAddress(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent, PCRTMAC a_pMACAddress)
1254{
1255 AutoInitSpan autoInitSpan(this);
1256 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1257
1258 HRESULT hrc = DHCPConfig::i_initWithDefaults(a_pVirtualBox, a_pParent);
1259 if (SUCCEEDED(hrc))
1260 {
1261 unconst(m_enmScope) = DHCPConfigScope_MAC;
1262 unconst(m_MACAddress) = *a_pMACAddress;
1263
1264 autoInitSpan.setSucceeded();
1265 }
1266 return hrc;
1267}
1268
1269
1270HRESULT DHCPIndividualConfig::initWithSettingsAndMachineIdAndSlot(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent,
1271 settings::DHCPIndividualConfig const &rConfig,
1272 com::Guid const &a_idMachine, ULONG a_uSlot,
1273 uint32_t a_uMACAddressVersion)
1274{
1275 AutoInitSpan autoInitSpan(this);
1276 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1277
1278 HRESULT hrc = DHCPConfig::i_initWithSettings(a_pVirtualBox, a_pParent, rConfig);
1279 if (SUCCEEDED(hrc))
1280 {
1281 unconst(m_enmScope) = DHCPConfigScope_MachineNIC;
1282 unconst(m_idMachine) = a_idMachine;
1283 unconst(m_uSlot) = a_uSlot;
1284 m_uMACAddressResolvedVersion = a_uMACAddressVersion;
1285 m_strFixedAddress = rConfig.strFixedAddress;
1286
1287 autoInitSpan.setSucceeded();
1288 }
1289 return hrc;
1290}
1291
1292
1293HRESULT DHCPIndividualConfig::initWithSettingsAndMACAddress(VirtualBox *a_pVirtualBox, DHCPServer *a_pParent,
1294 settings::DHCPIndividualConfig const &rConfig, PCRTMAC a_pMACAddress)
1295{
1296 AutoInitSpan autoInitSpan(this);
1297 AssertReturn(autoInitSpan.isOk(), E_FAIL);
1298
1299 HRESULT hrc = DHCPConfig::i_initWithSettings(a_pVirtualBox, a_pParent, rConfig);
1300 if (SUCCEEDED(hrc))
1301 {
1302 unconst(m_enmScope) = DHCPConfigScope_MAC;
1303 unconst(m_MACAddress) = *a_pMACAddress;
1304 m_strFixedAddress = rConfig.strFixedAddress;
1305
1306 autoInitSpan.setSucceeded();
1307 }
1308 return hrc;
1309}
1310
1311
1312void DHCPIndividualConfig::uninit()
1313{
1314 AutoUninitSpan autoUninitSpan(this);
1315 if (!autoUninitSpan.uninitDone())
1316 autoUninitSpan.setSucceeded();
1317}
1318
1319
1320HRESULT DHCPIndividualConfig::i_saveSettings(settings::DHCPIndividualConfig &a_rDst)
1321{
1322 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1323
1324 a_rDst.uSlot = m_uSlot;
1325 int vrc = a_rDst.strMACAddress.printfNoThrow("%RTmac", &m_MACAddress);
1326 if (m_idMachine.isValid() && !m_idMachine.isZero() && RT_SUCCESS(vrc))
1327 vrc = a_rDst.strVMName.printfNoThrow("%RTuuid", m_idMachine.raw());
1328 if (RT_SUCCESS(vrc))
1329 vrc = a_rDst.strFixedAddress.assignNoThrow(m_strFixedAddress);
1330 if (RT_SUCCESS(vrc))
1331 return DHCPConfig::i_saveSettings(a_rDst);
1332 return E_OUTOFMEMORY;;
1333}
1334
1335
1336HRESULT DHCPIndividualConfig::getMACAddress(com::Utf8Str &aMACAddress)
1337{
1338 /* No locking needed here (the MAC address, machine UUID and NIC slot number cannot change). */
1339 RTMAC MACAddress;
1340 if (m_enmScope == DHCPConfigScope_MAC)
1341 MACAddress = m_MACAddress;
1342 else
1343 {
1344 HRESULT hrc = i_getMachineMAC(&MACAddress);
1345 if (FAILED(hrc))
1346 return hrc;
1347 }
1348
1349 /* Format the return string: */
1350 int vrc = aMACAddress.printfNoThrow("%RTmac", &MACAddress);
1351 return RT_SUCCESS(vrc) ? S_OK : E_OUTOFMEMORY;
1352}
1353
1354
1355HRESULT DHCPIndividualConfig::getMachineId(com::Guid &aId)
1356{
1357 AutoReadLock(this COMMA_LOCKVAL_SRC_POS);
1358 aId = m_idMachine;
1359 return S_OK;
1360}
1361
1362
1363HRESULT DHCPIndividualConfig::getSlot(ULONG *aSlot)
1364{
1365 AutoReadLock(this COMMA_LOCKVAL_SRC_POS);
1366 *aSlot = m_uSlot;
1367 return S_OK;
1368}
1369
1370HRESULT DHCPIndividualConfig::getFixedAddress(com::Utf8Str &aFixedAddress)
1371{
1372 AutoReadLock(this COMMA_LOCKVAL_SRC_POS);
1373 return aFixedAddress.assignEx(m_strFixedAddress);
1374}
1375
1376
1377HRESULT DHCPIndividualConfig::setFixedAddress(const com::Utf8Str &aFixedAddress)
1378{
1379 if (aFixedAddress.isNotEmpty())
1380 {
1381 RTNETADDRIPV4 AddrIgnored;
1382 int vrc = RTNetStrToIPv4Addr(aFixedAddress.c_str(), &AddrIgnored);
1383 if (RT_FAILURE(vrc))
1384 return setErrorBoth(E_INVALIDARG, vrc, tr("Invalid IPv4 address '%s': %Rrc"), aFixedAddress.c_str(), vrc);
1385 }
1386
1387 {
1388 AutoWriteLock(this COMMA_LOCKVAL_SRC_POS);
1389 m_strFixedAddress = aFixedAddress;
1390 }
1391 return i_doWriteConfig();
1392}
1393
1394
1395/**
1396 * Gets the MAC address of m_idMachine + m_uSlot.
1397 *
1398 * @returns COM status code w/ setError.
1399 * @param pMACAddress Where to return the address.
1400 *
1401 * @note Must be called without holding any DHCP related locks as that would
1402 * be lock order violation. The m_idMachine and m_uSlot values are
1403 * practically const, so we don't need any locks here anyway.
1404 */
1405HRESULT DHCPIndividualConfig::i_getMachineMAC(PRTMAC pMACAddress)
1406{
1407 ComObjPtr<Machine> ptrMachine;
1408 HRESULT hrc = m_pVirtualBox->i_findMachine(m_idMachine, false /*fPermitInaccessible*/, true /*aSetError*/, &ptrMachine);
1409 if (SUCCEEDED(hrc))
1410 {
1411 ComPtr<INetworkAdapter> ptrNetworkAdapter;
1412 hrc = ptrMachine->GetNetworkAdapter(m_uSlot, ptrNetworkAdapter.asOutParam());
1413 if (SUCCEEDED(hrc))
1414 {
1415 com::Bstr bstrMACAddress;
1416 hrc = ptrNetworkAdapter->COMGETTER(MACAddress)(bstrMACAddress.asOutParam());
1417 if (SUCCEEDED(hrc))
1418 {
1419 Utf8Str strMACAddress;
1420 try
1421 {
1422 strMACAddress = bstrMACAddress;
1423 }
1424 catch (std::bad_alloc &)
1425 {
1426 return E_OUTOFMEMORY;
1427 }
1428
1429 int vrc = RTNetStrToMacAddr(strMACAddress.c_str(), pMACAddress);
1430 if (RT_SUCCESS(vrc))
1431 hrc = S_OK;
1432 else
1433 hrc = setErrorBoth(E_FAIL, vrc, tr("INetworkAdapter returned bogus MAC address '%ls': %Rrc"),
1434 bstrMACAddress.raw(), vrc);
1435 }
1436 }
1437 }
1438 return hrc;
1439}
1440
1441
1442HRESULT DHCPIndividualConfig::i_resolveMACAddress(uint32_t uVersion)
1443{
1444 HRESULT hrc;
1445 if (m_enmScope == DHCPConfigScope_MachineNIC)
1446 {
1447 RTMAC MACAddress;
1448 hrc = i_getMachineMAC(&MACAddress);
1449 if (SUCCEEDED(hrc))
1450 {
1451 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1452 if ((int32_t)(uVersion - m_uMACAddressResolvedVersion) >= 0)
1453 {
1454 m_uMACAddressResolvedVersion = uVersion;
1455 m_MACAddress = MACAddress;
1456 }
1457 }
1458 }
1459 else
1460 hrc = S_OK;
1461 return hrc;
1462}
1463
1464
1465/**
1466 * Overridden to write out additional config.
1467 */
1468void DHCPIndividualConfig::i_writeDhcpdConfig(xml::ElementNode *pElmConfig)
1469{
1470 char szTmp[RTUUID_STR_LENGTH + 32];
1471 RTStrPrintf(szTmp, sizeof(szTmp), "%RTmac", &m_MACAddress);
1472 pElmConfig->setAttribute("MACAddress", szTmp);
1473
1474 if (m_enmScope == DHCPConfigScope_MachineNIC)
1475 {
1476 RTStrPrintf(szTmp, sizeof(szTmp), "%RTuuid/%u", m_idMachine.raw(), m_uSlot);
1477 pElmConfig->setAttribute("name", szTmp);
1478 }
1479
1480 pElmConfig->setAttribute("fixedAddress", m_strFixedAddress);
1481
1482 DHCPConfig::i_writeDhcpdConfig(pElmConfig);
1483}
1484
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