VirtualBox

source: vbox/trunk/src/VBox/NetworkServices/DHCP/Config.h@ 48465

Last change on this file since 48465 was 48465, checked in by vboxsync, 12 years ago

DHCP: nukes extra lines.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.4 KB
Line 
1/* $Id: Config.h 48465 2013-09-13 01:36:17Z vboxsync $ */
2/**
3 * This file contains declarations of DHCP config.
4 */
5
6#ifndef _CONFIG_H_
7# define _CONFIG_H_
8
9#include <iprt/asm-math.h>
10#include <iprt/cpp/utils.h>
11
12typedef std::vector<RTMAC> MacAddressContainer;
13typedef MacAddressContainer::iterator MacAddressIterator;
14
15typedef std::vector<RTNETADDRIPV4> Ipv4AddressContainer;
16typedef Ipv4AddressContainer::iterator Ipv4AddressIterator;
17typedef Ipv4AddressContainer::const_iterator Ipv4AddressConstIterator;
18
19static bool operator <(const RTNETADDRIPV4& a, const RTNETADDRIPV4& b)
20{
21 return (RT_N2H_U32(a.u) < RT_N2H_U32(b.u));
22}
23
24static bool operator > (const RTNETADDRIPV4& a, const RTNETADDRIPV4& b)
25{
26 return (b < a);
27}
28
29
30class RawOption
31{
32public:
33 uint8_t u8OptId;
34 uint8_t cbRawOpt;
35 uint8_t au8RawOpt[255];
36};
37
38
39class Client;
40class Lease;
41class BaseConfigEntity;
42
43
44class NetworkConfigEntity;
45class HostConfigEntity;
46class ClientMatchCriteria;
47
48typedef std::map<Lease *, RTNETADDRIPV4> MapLease2Ip4Address;
49typedef MapLease2Ip4Address::iterator MapLease2Ip4AddressIterator;
50typedef MapLease2Ip4Address::value_type MapLease2Ip4AddressPair;
51
52/*
53 * it's a basic representation of
54 * of out undestanding what client is
55 * XXX: Client might sends Option 61 (RFC2132 9.14 "Client-identifier") signalling
56 * that we may identify it in special way
57 *
58 * XXX: Client might send Option 60 (RFC2132 9.13 "Vendor class undentifier")
59 * in response it's expected server sends Option 43 (RFC2132 8.4. "Vendor Specific Information")
60 */
61class Client
62{
63 public:
64
65 /* XXX: Option 60 and 61 */
66 Client(const RTMAC& mac);
67
68 bool operator== (const RTMAC& mac) const
69 {
70 return ( m_mac.au16[0] == mac.au16[0]
71 && m_mac.au16[1] == mac.au16[1]
72 && m_mac.au16[2] == mac.au16[2]);
73 }
74 /** Dumps client query */
75 void dump();
76
77 /* XXX! private: */
78
79 RTMAC m_mac;
80 Lease *m_lease;
81
82 /* XXX: should be in lease */
83 std::vector<RawOption> rawOptions;
84};
85
86
87typedef std::vector<Client*> VecClient;
88typedef VecClient::iterator VecClientIterator;
89typedef VecClient::const_iterator VecClientConstIterator;
90
91
92/**
93 *
94 */
95class ClientMatchCriteria
96{
97 public:
98 virtual bool check(const Client& client) const {return false;};
99};
100
101
102class ORClientMatchCriteria: ClientMatchCriteria
103{
104 ClientMatchCriteria* m_left;
105 ClientMatchCriteria* m_right;
106 ORClientMatchCriteria(ClientMatchCriteria *left, ClientMatchCriteria *right)
107 {
108 m_left = left;
109 m_right = right;
110 }
111
112 virtual bool check(const Client& client) const
113 {
114 return (m_left->check(client) || m_right->check(client));
115 }
116};
117
118
119class ANDClientMatchCriteria: ClientMatchCriteria
120{
121 ClientMatchCriteria* m_left;
122 ClientMatchCriteria* m_right;
123 ANDClientMatchCriteria(ClientMatchCriteria *left, ClientMatchCriteria *right)
124 {
125 m_left = left;
126 m_right = right;
127 }
128
129 virtual bool check(const Client& client) const
130 {
131 return (m_left->check(client) && m_right->check(client));
132 }
133};
134
135
136class AnyClientMatchCriteria: public ClientMatchCriteria
137{
138 virtual bool check(const Client& client) const
139 {
140 return true;
141 }
142};
143
144
145class MACClientMatchCriteria: public ClientMatchCriteria
146{
147
148 public:
149 MACClientMatchCriteria(const RTMAC& mac):m_mac(mac){}
150
151 virtual bool check(const Client& client) const
152 {
153 return (client == m_mac);
154 }
155 private:
156 RTMAC m_mac;
157};
158
159
160#if 0
161/* XXX: Later */
162class VmSlotClientMatchCriteria: public ClientMatchCriteria
163{
164 str::string VmName;
165 uint8_t u8Slot;
166 virtual bool check(const Client& client)
167 {
168 return ( client.VmName == VmName
169 && ( u8Slot == (uint8_t)~0 /* any */
170 || client.u8Slot == u8Slot));
171 }
172};
173#endif
174
175
176/* Option 60 */
177class ClassClientMatchCriteria: ClientMatchCriteria{};
178/* Option 61 */
179class ClientIdentifierMatchCriteria: ClientMatchCriteria{};
180
181
182class BaseConfigEntity
183{
184public:
185 BaseConfigEntity(const ClientMatchCriteria *criteria = NULL,
186 int matchingLevel = 0)
187 : m_criteria(criteria),
188 m_MatchLevel(matchingLevel){};
189 virtual ~BaseConfigEntity(){};
190 /* XXX */
191 int add(BaseConfigEntity *cfg)
192 {
193 m_children.push_back(cfg);
194 return 0;
195 }
196
197 /* Should return how strong matching */
198 virtual int match(Client& client, BaseConfigEntity **cfg);
199 virtual uint32_t expirationPeriod() const = 0;
200 protected:
201 const ClientMatchCriteria *m_criteria;
202 int m_MatchLevel;
203 std::vector<BaseConfigEntity *> m_children;
204};
205
206
207class NullConfigEntity: public BaseConfigEntity
208{
209public:
210 NullConfigEntity(){}
211 virtual ~NullConfigEntity(){}
212 int add(BaseConfigEntity *cfg) const
213 {
214 return 0;
215 }
216 virtual uint32_t expirationPeriod() const {return 0;}
217};
218
219
220class ConfigEntity: public BaseConfigEntity
221{
222 public:
223
224 /* range */
225 /* match conditions */
226 ConfigEntity(std::string& name,
227 const BaseConfigEntity *cfg,
228 const ClientMatchCriteria *criteria,
229 int matchingLevel = 0):
230 BaseConfigEntity(criteria, matchingLevel),
231 m_name(name),
232 m_parentCfg(cfg),
233 m_u32ExpirationPeriod(0)
234 {
235 unconst(m_parentCfg)->add(this);
236 }
237
238 std::string m_name;
239 const BaseConfigEntity *m_parentCfg;
240 virtual uint32_t expirationPeriod() const
241 {
242 if (!m_u32ExpirationPeriod)
243 return m_parentCfg->expirationPeriod();
244 else
245 return m_u32ExpirationPeriod;
246 }
247
248 /* XXX: private:*/
249 uint32_t m_u32ExpirationPeriod;
250};
251
252
253/**
254 * Network specific entries
255 */
256class NetworkConfigEntity:public ConfigEntity
257{
258 public:
259 /* Address Pool matching with network declaration */
260 NetworkConfigEntity(std::string name,
261 const BaseConfigEntity *cfg,
262 const ClientMatchCriteria *criteria,
263 int matchlvl,
264 const RTNETADDRIPV4& networkID,
265 const RTNETADDRIPV4& networkMask,
266 const RTNETADDRIPV4& lowerIP,
267 const RTNETADDRIPV4& upperIP):
268 ConfigEntity(name, cfg, criteria, matchlvl),
269 m_NetworkID(networkID),
270 m_NetworkMask(networkMask),
271 m_UpperIP(upperIP),
272 m_LowerIP(lowerIP)
273 {
274 };
275
276 NetworkConfigEntity(std::string name,
277 const BaseConfigEntity *cfg,
278 const ClientMatchCriteria *criteria,
279 const RTNETADDRIPV4& networkID,
280 const RTNETADDRIPV4& networkMask):
281 ConfigEntity(name, cfg, criteria, 5),
282 m_NetworkID(networkID),
283 m_NetworkMask(networkMask)
284 {
285 m_UpperIP.u = m_NetworkID.u | (~m_NetworkMask.u);
286 m_LowerIP.u = m_NetworkID.u;
287 };
288
289 const RTNETADDRIPV4& upperIp() const {return m_UpperIP;}
290 const RTNETADDRIPV4& lowerIp() const {return m_LowerIP;}
291 const RTNETADDRIPV4& networkId() const {return m_NetworkID;}
292 const RTNETADDRIPV4& netmask() const {return m_NetworkMask;}
293
294 private:
295 RTNETADDRIPV4 m_NetworkID;
296 RTNETADDRIPV4 m_NetworkMask;
297 RTNETADDRIPV4 m_UpperIP;
298 RTNETADDRIPV4 m_LowerIP;
299};
300
301
302/**
303 * Host specific entry
304 * Address pool is contains one element
305 */
306class HostConfigEntity: public NetworkConfigEntity
307{
308
309 public:
310 HostConfigEntity(const RTNETADDRIPV4& addr,
311 std::string name,
312 const NetworkConfigEntity *cfg,
313 const ClientMatchCriteria *criteria):
314 NetworkConfigEntity(name,
315 static_cast<const ConfigEntity*>(cfg), criteria, 10,
316 cfg->networkId(), cfg->netmask(), addr, addr)
317 {
318 /* upper addr == lower addr */
319 }
320
321 virtual int match(const Client& client) const
322 {
323 return (m_criteria->check(client) ? 10 : 0);
324 }
325
326};
327
328class RootConfigEntity: public NetworkConfigEntity
329{
330 public:
331 RootConfigEntity(std::string name, uint32_t expirationPeriod);
332 virtual ~RootConfigEntity(){};
333};
334
335
336#if 0
337/**
338 * Shared regions e.g. some of configured networks declarations
339 * are cover each other.
340 * XXX: Shared Network is join on Network config entities with possible
341 * overlaps in address pools. for a moment we won't configure and use them them
342 */
343class SharedNetworkConfigEntity: public NetworkEntity
344{
345 public:
346 SharedNetworkConfigEntity(){}
347 int match(const Client& client) const { return m_criteria.match(client)? 3 : 0;}
348
349 SharedNetworkConfigEntity(NetworkEntity& network)
350 {
351 Networks.push_back(network);
352 }
353 virtual ~SharedNetworkConfigEntity(){}
354
355 std::vector<NetworkConfigEntity> Networks;
356
357};
358#endif
359
360class ConfigurationManager
361{
362 public:
363 static ConfigurationManager* getConfigurationManager();
364 static int extractRequestList(PCRTNETBOOTP pDhcpMsg, size_t cbDhcpMsg, RawOption& rawOpt);
365
366 /**
367 *
368 */
369 Client* getClientByDhcpPacket(const RTNETBOOTP *pDhcpMsg, size_t cbDhcpMsg);
370
371 /**
372 * XXX: it's could be done on DHCPOFFER or on DHCPACK (rfc2131 gives freedom here
373 * 3.1.2, what is strict that allocation should do address check before real
374 * allocation)...
375 */
376 Lease* allocateLease4Client(Client *client, PCRTNETBOOTP pDhcpMsg, size_t cbDhcpMsg);
377
378 /**
379 * We call this before DHCPACK sent and after DHCPREQUEST received ...
380 * when requested configuration is acceptable.
381 */
382 int commitLease4Client(Client *client);
383
384 /**
385 * Expires client lease.
386 */
387 int expireLease4Client(Client *client);
388
389 static int findOption(uint8_t uOption, PCRTNETBOOTP pDhcpMsg, size_t cbDhcpMsg, RawOption& opt);
390
391 NetworkConfigEntity *addNetwork(NetworkConfigEntity *pCfg,
392 const RTNETADDRIPV4& networkId,
393 const RTNETADDRIPV4& netmask,
394 RTNETADDRIPV4& UpperAddress,
395 RTNETADDRIPV4& LowerAddress);
396
397 HostConfigEntity *addHost(NetworkConfigEntity*, const RTNETADDRIPV4&, ClientMatchCriteria*);
398 int addToAddressList(uint8_t u8OptId, RTNETADDRIPV4& address);
399 int flushAddressList(uint8_t u8OptId);
400 int setString(uint8_t u8OptId, const std::string& str);
401 const std::string& getString(uint8_t u8OptId);
402 const Ipv4AddressContainer& getAddressList(uint8_t u8OptId);
403
404private:
405 ConfigurationManager(){}
406 virtual ~ConfigurationManager(){}
407 bool isAddressTaken(const RTNETADDRIPV4& addr, Lease** ppLease = NULL);
408
409public:
410 /* nulls */
411 const Ipv4AddressContainer m_empty;
412 const std::string m_noString;
413
414private:
415 MapLease2Ip4Address m_allocations;
416 /**
417 * Here we can store expired Leases to do not re-allocate them latter.
418 */
419
420 /* XXX: MapLease2Ip4Address m_freed; */
421 /* XXX: more universal storages are required. */
422 Ipv4AddressContainer m_nameservers;
423 Ipv4AddressContainer m_routers;
424
425 std::string m_domainName;
426 VecClient m_clients;
427};
428
429
430class NetworkManager
431{
432 public:
433 static NetworkManager *getNetworkManager();
434
435 int offer4Client(Client* lease, uint32_t u32Xid, uint8_t *pu8ReqList, int cReqList);
436 int ack(Client *lease, uint32_t u32Xid, uint8_t *pu8ReqList, int cReqList);
437 int nak(Client *lease, uint32_t u32Xid);
438
439 const RTNETADDRIPV4& getOurAddress(){ return m_OurAddress;}
440 const RTNETADDRIPV4& getOurNetmask(){ return m_OurNetmask;}
441 const RTMAC& getOurMac() {return m_OurMac;}
442
443 void setOurAddress(const RTNETADDRIPV4& aAddress){ m_OurAddress = aAddress;}
444 void setOurNetmask(const RTNETADDRIPV4& aNetmask){ m_OurNetmask = aNetmask;}
445 void setOurMac(const RTMAC& aMac) {m_OurMac = aMac;}
446
447 /* XXX: artifacts should be hidden or removed from here. */
448 PSUPDRVSESSION m_pSession;
449 INTNETIFHANDLE m_hIf;
450 PINTNETBUF m_pIfBuf;
451
452 private:
453 int prepareReplyPacket4Client(Client *client, uint32_t u32Xid);
454 int doReply(Client *client);
455 int processParameterReqList(Client *client, uint8_t *pu8ReqList, int cReqList);
456
457 union {
458 RTNETBOOTP BootPHeader;
459 uint8_t au8Storage[1024];
460 } BootPReplyMsg;
461 int cbBooPReplyMsg;
462
463 RTNETADDRIPV4 m_OurAddress;
464 RTNETADDRIPV4 m_OurNetmask;
465 RTMAC m_OurMac;
466
467 NetworkManager(){}
468 virtual ~NetworkManager(){}
469};
470
471
472
473class Lease
474{
475public:
476 Lease()
477 {
478 m_address.u = 0;
479 m_client = NULL;
480 fBinding = false;
481 u64TimestampBindingStarted = 0;
482 u64TimestampLeasingStarted = 0;
483 u32LeaseExpirationPeriod = 0;
484 u32BindExpirationPeriod = 0;
485 pCfg = NULL;
486 }
487 virtual ~Lease(){}
488
489 bool isExpired()
490 {
491 if (!fBinding)
492 return (ASMDivU64ByU32RetU32(RTTimeMilliTS() - u64TimestampLeasingStarted, 1000)
493 > u32LeaseExpirationPeriod);
494 else
495 return (ASMDivU64ByU32RetU32(RTTimeMilliTS() - u64TimestampBindingStarted, 1000)
496 > u32BindExpirationPeriod);
497
498 }
499
500 /* XXX private: */
501 RTNETADDRIPV4 m_address;
502
503 /** lease isn't commited */
504 bool fBinding;
505
506 /** Timestamp when lease commited. */
507 uint64_t u64TimestampLeasingStarted;
508 /** Period when lease is expired in secs. */
509 uint32_t u32LeaseExpirationPeriod;
510
511 /** timestamp when lease was bound */
512 uint64_t u64TimestampBindingStarted;
513 /* Period when binding is expired in secs. */
514 uint32_t u32BindExpirationPeriod;
515
516 NetworkConfigEntity *pCfg;
517 Client *m_client;
518};
519
520
521
522
523
524extern const ClientMatchCriteria *g_AnyClient;
525extern RootConfigEntity *g_RootConfig;
526extern const NullConfigEntity *g_NullConfig;
527
528/**
529 * Helper class for stuffing DHCP options into a reply packet.
530 */
531class VBoxNetDhcpWriteCursor
532{
533private:
534 uint8_t *m_pbCur; /**< The current cursor position. */
535 uint8_t *m_pbEnd; /**< The end the current option space. */
536 uint8_t *m_pfOverload; /**< Pointer to the flags of the overload option. */
537 uint8_t m_fUsed; /**< Overload fields that have been used. */
538 PRTNETDHCPOPT m_pOpt; /**< The current option. */
539 PRTNETBOOTP m_pDhcp; /**< The DHCP packet. */
540 bool m_fOverflowed; /**< Set if we've overflowed, otherwise false. */
541
542public:
543 /** Instantiate an option cursor for the specified DHCP message. */
544 VBoxNetDhcpWriteCursor(PRTNETBOOTP pDhcp, size_t cbDhcp) :
545 m_pbCur(&pDhcp->bp_vend.Dhcp.dhcp_opts[0]),
546 m_pbEnd((uint8_t *)pDhcp + cbDhcp),
547 m_pfOverload(NULL),
548 m_fUsed(0),
549 m_pOpt(NULL),
550 m_pDhcp(pDhcp),
551 m_fOverflowed(false)
552 {
553 AssertPtr(pDhcp);
554 Assert(cbDhcp > RT_UOFFSETOF(RTNETBOOTP, bp_vend.Dhcp.dhcp_opts[10]));
555 }
556
557 /** Destructor. */
558 ~VBoxNetDhcpWriteCursor()
559 {
560 m_pbCur = m_pbEnd = m_pfOverload = NULL;
561 m_pOpt = NULL;
562 m_pDhcp = NULL;
563 }
564
565 /**
566 * Try use the bp_file field.
567 * @returns true if not overloaded, false otherwise.
568 */
569 bool useBpFile(void)
570 {
571 if ( m_pfOverload
572 && (*m_pfOverload & 1))
573 return false;
574 m_fUsed |= 1 /* bp_file flag*/;
575 return true;
576 }
577
578
579 /**
580 * Try overload more BOOTP fields
581 */
582 bool overloadMore(void)
583 {
584 /* switch option area. */
585 uint8_t *pbNew;
586 uint8_t *pbNewEnd;
587 uint8_t fField;
588 if (!(m_fUsed & 1))
589 {
590 fField = 1;
591 pbNew = &m_pDhcp->bp_file[0];
592 pbNewEnd = &m_pDhcp->bp_file[sizeof(m_pDhcp->bp_file)];
593 }
594 else if (!(m_fUsed & 2))
595 {
596 fField = 2;
597 pbNew = &m_pDhcp->bp_sname[0];
598 pbNewEnd = &m_pDhcp->bp_sname[sizeof(m_pDhcp->bp_sname)];
599 }
600 else
601 return false;
602
603 if (!m_pfOverload)
604 {
605 /* Add an overload option. */
606 *m_pbCur++ = RTNET_DHCP_OPT_OPTION_OVERLOAD;
607 *m_pbCur++ = fField;
608 m_pfOverload = m_pbCur;
609 *m_pbCur++ = 1; /* bp_file flag */
610 }
611 else
612 *m_pfOverload |= fField;
613
614 /* pad current option field */
615 while (m_pbCur != m_pbEnd)
616 *m_pbCur++ = RTNET_DHCP_OPT_PAD; /** @todo not sure if this stuff is at all correct... */
617
618 /* switch */
619 m_pbCur = pbNew;
620 m_pbEnd = pbNewEnd;
621 return true;
622 }
623
624 /**
625 * Begin an option.
626 *
627 * @returns true on success, false if we're out of space.
628 *
629 * @param uOption The option number.
630 * @param cb The amount of data.
631 */
632 bool begin(uint8_t uOption, size_t cb)
633 {
634 /* Check that the data of the previous option has all been written. */
635 Assert( !m_pOpt
636 || (m_pbCur - m_pOpt->dhcp_len == (uint8_t *)(m_pOpt + 1)));
637 AssertMsg(cb <= 255, ("%#x\n", cb));
638
639 /* Check if we need to overload more stuff. */
640 if ((uintptr_t)(m_pbEnd - m_pbCur) < cb + 2 + (m_pfOverload ? 1 : 3))
641 {
642 m_pOpt = NULL;
643 if (!overloadMore())
644 {
645 m_fOverflowed = true;
646 AssertMsgFailedReturn(("%u %#x\n", uOption, cb), false);
647 }
648 if ((uintptr_t)(m_pbEnd - m_pbCur) < cb + 2 + 1)
649 {
650 m_fOverflowed = true;
651 AssertMsgFailedReturn(("%u %#x\n", uOption, cb), false);
652 }
653 }
654
655 /* Emit the option header. */
656 m_pOpt = (PRTNETDHCPOPT)m_pbCur;
657 m_pOpt->dhcp_opt = uOption;
658 m_pOpt->dhcp_len = (uint8_t)cb;
659 m_pbCur += 2;
660 return true;
661 }
662
663 /**
664 * Puts option data.
665 *
666 * @param pvData The data.
667 * @param cb The amount to put.
668 */
669 void put(void const *pvData, size_t cb)
670 {
671 Assert(m_pOpt || m_fOverflowed);
672 if (RT_LIKELY(m_pOpt))
673 {
674 Assert((uintptr_t)m_pbCur - (uintptr_t)(m_pOpt + 1) + cb <= (size_t)m_pOpt->dhcp_len);
675 memcpy(m_pbCur, pvData, cb);
676 m_pbCur += cb;
677 }
678 }
679
680 /**
681 * Puts an IPv4 Address.
682 *
683 * @param IPv4Addr The address.
684 */
685 void putIPv4Addr(RTNETADDRIPV4 IPv4Addr)
686 {
687 put(&IPv4Addr, 4);
688 }
689
690 /**
691 * Adds an IPv4 address option.
692 *
693 * @returns true/false just like begin().
694 *
695 * @param uOption The option number.
696 * @param IPv4Addr The address.
697 */
698 bool optIPv4Addr(uint8_t uOption, RTNETADDRIPV4 IPv4Addr)
699 {
700 if (!begin(uOption, 4))
701 return false;
702 putIPv4Addr(IPv4Addr);
703 return true;
704 }
705
706 /**
707 * Adds an option taking 1 or more IPv4 address.
708 *
709 * If the vector contains no addresses, the option will not be added.
710 *
711 * @returns true/false just like begin().
712 *
713 * @param uOption The option number.
714 * @param rIPv4Addrs Reference to the address vector.
715 */
716 bool optIPv4Addrs(uint8_t uOption, std::vector<RTNETADDRIPV4> const &rIPv4Addrs)
717 {
718 size_t const c = rIPv4Addrs.size();
719 if (!c)
720 return true;
721
722 if (!begin(uOption, 4*c))
723 return false;
724 for (size_t i = 0; i < c; i++)
725 putIPv4Addr(rIPv4Addrs[i]);
726 return true;
727 }
728
729 /**
730 * Puts an 8-bit integer.
731 *
732 * @param u8 The integer.
733 */
734 void putU8(uint8_t u8)
735 {
736 put(&u8, 1);
737 }
738
739 /**
740 * Adds an 8-bit integer option.
741 *
742 * @returns true/false just like begin().
743 *
744 * @param uOption The option number.
745 * @param u8 The integer
746 */
747 bool optU8(uint8_t uOption, uint8_t u8)
748 {
749 if (!begin(uOption, 1))
750 return false;
751 putU8(u8);
752 return true;
753 }
754
755 /**
756 * Puts an 32-bit integer (network endian).
757 *
758 * @param u32Network The integer.
759 */
760 void putU32(uint32_t u32)
761 {
762 put(&u32, 4);
763 }
764
765 /**
766 * Adds an 32-bit integer (network endian) option.
767 *
768 * @returns true/false just like begin().
769 *
770 * @param uOption The option number.
771 * @param u32Network The integer.
772 */
773 bool optU32(uint8_t uOption, uint32_t u32)
774 {
775 if (!begin(uOption, 4))
776 return false;
777 putU32(u32);
778 return true;
779 }
780
781 /**
782 * Puts a std::string.
783 *
784 * @param rStr Reference to the string.
785 */
786 void putStr(std::string const &rStr)
787 {
788 put(rStr.c_str(), rStr.size());
789 }
790
791 /**
792 * Adds an std::string option if the string isn't empty.
793 *
794 * @returns true/false just like begin().
795 *
796 * @param uOption The option number.
797 * @param rStr Reference to the string.
798 */
799 bool optStr(uint8_t uOption, std::string const &rStr)
800 {
801 const size_t cch = rStr.size();
802 if (!cch)
803 return true;
804
805 if (!begin(uOption, cch))
806 return false;
807 put(rStr.c_str(), cch);
808 return true;
809 }
810
811 /**
812 * Whether we've overflowed.
813 *
814 * @returns true on overflow, false otherwise.
815 */
816 bool hasOverflowed(void) const
817 {
818 return m_fOverflowed;
819 }
820
821 /**
822 * Adds the terminating END option.
823 *
824 * The END will always be added as we're reserving room for it, however, we
825 * might have dropped previous options due to overflows and that is what the
826 * return status indicates.
827 *
828 * @returns true on success, false on a (previous) overflow.
829 */
830 bool optEnd(void)
831 {
832 Assert((uintptr_t)(m_pbEnd - m_pbCur) < 4096);
833 *m_pbCur++ = RTNET_DHCP_OPT_END;
834 return !hasOverflowed();
835 }
836};
837
838#endif
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