VirtualBox

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

Last change on this file since 106901 was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

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