VirtualBox

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

Last change on this file since 47501 was 47501, checked in by vboxsync, 11 years ago

VBoxNetDHCP: removes session handling. binding and lease expiration control was added.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.1 KB
Line 
1/* $Id: Config.h 47501 2013-08-01 06:24:41Z 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 {
200 int iMatch = (m_criteria && m_criteria->check(client)? m_MatchLevel: 0);
201 if (m_children.empty())
202 {
203 if (iMatch > 0)
204 {
205 *cfg = this;
206 return iMatch;
207 }
208 }
209 else
210 {
211 *cfg = this;
212 /* XXX: hack */
213 BaseConfigEntity *matching = this;
214 int matchingLevel = m_MatchLevel;
215
216 for (std::vector<BaseConfigEntity *>::iterator it = m_children.begin();
217 it != m_children.end();
218 ++it)
219 {
220 iMatch = (*it)->match(client, &matching);
221 if (iMatch > matchingLevel)
222 {
223 *cfg = matching;
224 matchingLevel = iMatch;
225 }
226 }
227 return matchingLevel;
228 }
229 return iMatch;
230 }
231 virtual uint32_t expirationPeriod() const = 0;
232 protected:
233 const ClientMatchCriteria *m_criteria;
234 int m_MatchLevel;
235 std::vector<BaseConfigEntity *> m_children;
236};
237
238
239class NullConfigEntity: public BaseConfigEntity
240{
241public:
242 NullConfigEntity(){}
243 virtual ~NullConfigEntity(){}
244 int add(BaseConfigEntity *cfg) const
245 {
246 return 0;
247 }
248 virtual uint32_t expirationPeriod() const {return 0;}
249};
250
251
252class ConfigEntity: public BaseConfigEntity
253{
254 public:
255
256 /* range */
257 /* match conditions */
258 ConfigEntity(std::string& name,
259 const BaseConfigEntity *cfg,
260 const ClientMatchCriteria *criteria,
261 int matchingLevel = 0):
262 BaseConfigEntity(criteria, matchingLevel),
263 m_name(name),
264 m_parentCfg(cfg)
265 {
266 unconst(m_parentCfg)->add(this);
267 }
268
269 std::string m_name;
270 const BaseConfigEntity *m_parentCfg;
271 virtual uint32_t expirationPeriod() const
272 {
273 if (!m_u32ExpirationPeriod)
274 return m_parentCfg->expirationPeriod();
275 else
276 return m_u32ExpirationPeriod;
277 }
278
279 /* XXX: private:*/
280 uint32_t m_u32ExpirationPeriod;
281};
282
283
284/**
285 * Network specific entries
286 */
287class NetworkConfigEntity:public ConfigEntity
288{
289 public:
290 /* Address Pool matching with network declaration */
291 NetworkConfigEntity(std::string name,
292 const BaseConfigEntity *cfg,
293 const ClientMatchCriteria *criteria,
294 int matchlvl,
295 const RTNETADDRIPV4& networkID,
296 const RTNETADDRIPV4& networkMask,
297 const RTNETADDRIPV4& lowerIP,
298 const RTNETADDRIPV4& upperIP):
299 ConfigEntity(name, cfg, criteria, matchlvl),
300 m_NetworkID(networkID),
301 m_NetworkMask(networkMask),
302 m_UpperIP(upperIP),
303 m_LowerIP(lowerIP)
304 {
305 };
306
307 NetworkConfigEntity(std::string name,
308 const BaseConfigEntity *cfg,
309 const ClientMatchCriteria *criteria,
310 const RTNETADDRIPV4& networkID,
311 const RTNETADDRIPV4& networkMask):
312 ConfigEntity(name, cfg, criteria, 5),
313 m_NetworkID(networkID),
314 m_NetworkMask(networkMask)
315 {
316 m_UpperIP.u = m_NetworkID.u | (~m_NetworkMask.u);
317 m_LowerIP.u = m_NetworkID.u;
318 };
319
320 const RTNETADDRIPV4& upperIp() const {return m_UpperIP;}
321 const RTNETADDRIPV4& lowerIp() const {return m_LowerIP;}
322 const RTNETADDRIPV4& networkId() const {return m_NetworkID;}
323 const RTNETADDRIPV4& netmask() const {return m_NetworkMask;}
324
325 private:
326 RTNETADDRIPV4 m_NetworkID;
327 RTNETADDRIPV4 m_NetworkMask;
328 RTNETADDRIPV4 m_UpperIP;
329 RTNETADDRIPV4 m_LowerIP;
330};
331
332
333/**
334 * Host specific entry
335 * Address pool is contains one element
336 */
337class HostConfigEntity: public NetworkConfigEntity
338{
339
340 public:
341 HostConfigEntity(const RTNETADDRIPV4& addr,
342 std::string name,
343 const NetworkConfigEntity *cfg,
344 const ClientMatchCriteria *criteria):
345 NetworkConfigEntity(name,
346 static_cast<const ConfigEntity*>(cfg),
347 criteria,
348 10,
349 cfg->networkId(),
350 cfg->netmask(),
351 addr,
352 addr)
353 {
354 /* upper addr == lower addr */
355 }
356
357 virtual int match(const Client& client) const
358 {
359 return (m_criteria->check(client) ? 10 : 0);
360 }
361
362};
363
364class RootConfigEntity: public NetworkConfigEntity
365{
366 public:
367 RootConfigEntity(std::string name, uint32_t expirationPeriod);
368 virtual ~RootConfigEntity(){};
369};
370
371
372#if 0
373/**
374 * Shared regions e.g. some of configured networks declarations
375 * are cover each other.
376 * XXX: Shared Network is join on Network config entities with possible
377 * overlaps in address pools. for a moment we won't configure and use them them
378 */
379class SharedNetworkConfigEntity: public NetworkEntity
380{
381 public:
382 SharedNetworkConfigEntity(){}
383 int match(const Client& client) const { return m_criteria.match(client)? 3 : 0;}
384
385 SharedNetworkConfigEntity(NetworkEntity& network)
386 {
387 Networks.push_back(network);
388 }
389 virtual ~SharedNetworkConfigEntity(){}
390
391 std::vector<NetworkConfigEntity> Networks;
392
393};
394#endif
395
396class ConfigurationManager
397{
398 public:
399 static ConfigurationManager* getConfigurationManager();
400 static int extractRequestList(PCRTNETBOOTP pDhcpMsg, size_t cbDhcpMsg, RawOption& rawOpt);
401
402 /**
403 *
404 */
405 Client* getClientByDhcpPacket(const RTNETBOOTP *pDhcpMsg, size_t cbDhcpMsg);
406
407 /**
408 * XXX: it's could be done on DHCPOFFER or on DHCPACK (rfc2131 gives freedom here
409 * 3.1.2, what is strict that allocation should do address check before real
410 * allocation)...
411 */
412 Lease* allocateLease4Client(Client *client, PCRTNETBOOTP pDhcpMsg, size_t cbDhcpMsg);
413
414 /**
415 * We call this before DHCPACK sent and after DHCPREQUEST received ...
416 * when requested configuration is acceptable.
417 */
418 int commitLease4Client(Client *client);
419
420 /**
421 * Expires client lease.
422 */
423 int expireLease4Client(Client *client);
424
425 static int findOption(uint8_t uOption, PCRTNETBOOTP pDhcpMsg, size_t cbDhcpMsg, RawOption& opt);
426
427 NetworkConfigEntity *addNetwork(NetworkConfigEntity *pCfg,
428 const RTNETADDRIPV4& networkId,
429 const RTNETADDRIPV4& netmask,
430 RTNETADDRIPV4& UpperAddress,
431 RTNETADDRIPV4& LowerAddress);
432
433 HostConfigEntity *addHost(NetworkConfigEntity*, const RTNETADDRIPV4&, ClientMatchCriteria*);
434
435 int addToAddressList(uint8_t u8OptId, RTNETADDRIPV4& address)
436 {
437 switch(u8OptId)
438 {
439 case RTNET_DHCP_OPT_DNS:
440 m_nameservers.push_back(address);
441 break;
442 case RTNET_DHCP_OPT_ROUTERS:
443 m_routers.push_back(address);
444 break;
445 default:
446 Log(("dhcp-opt: list (%d) unsupported\n", u8OptId));
447 }
448 return VINF_SUCCESS;
449 }
450
451 int flushAddressList(uint8_t u8OptId)
452 {
453 switch(u8OptId)
454 {
455 case RTNET_DHCP_OPT_DNS:
456 m_nameservers.clear();
457 break;
458 case RTNET_DHCP_OPT_ROUTERS:
459 m_routers.clear();
460 break;
461 default:
462 Log(("dhcp-opt: list (%d) unsupported\n", u8OptId));
463 }
464 return VINF_SUCCESS;
465 }
466
467 const Ipv4AddressContainer& getAddressList(uint8_t u8OptId)
468 {
469 switch(u8OptId)
470 {
471 case RTNET_DHCP_OPT_DNS:
472 return m_nameservers;
473
474 case RTNET_DHCP_OPT_ROUTERS:
475 return m_routers;
476
477 }
478 /* XXX: Grrr !!! */
479 return m_empty;
480 }
481
482 private:
483 ConfigurationManager(){}
484 virtual ~ConfigurationManager(){}
485
486 bool isAddressTaken(const RTNETADDRIPV4& addr, Lease** ppLease = NULL);
487 MapLease2Ip4Address m_allocations;
488 /**
489 * Here we can store expired Leases to do not re-allocate them latter.
490 */
491 /* XXX: MapLease2Ip4Address m_freed; */
492 /*
493 *
494 */
495 Ipv4AddressContainer m_nameservers;
496 Ipv4AddressContainer m_routers;
497 Ipv4AddressContainer m_empty;
498 VecClient m_clients;
499
500};
501
502
503class NetworkManager
504{
505 public:
506 static NetworkManager *getNetworkManager();
507
508 int offer4Client(Client* lease, uint32_t u32Xid, uint8_t *pu8ReqList, int cReqList);
509 int ack(Client *lease, uint32_t u32Xid, uint8_t *pu8ReqList, int cReqList);
510 int nak(Client *lease, uint32_t u32Xid);
511
512 const RTNETADDRIPV4& getOurAddress(){ return m_OurAddress;}
513 const RTNETADDRIPV4& getOurNetmask(){ return m_OurNetmask;}
514 const RTMAC& getOurMac() {return m_OurMac;}
515
516 void setOurAddress(const RTNETADDRIPV4& aAddress){ m_OurAddress = aAddress;}
517 void setOurNetmask(const RTNETADDRIPV4& aNetmask){ m_OurNetmask = aNetmask;}
518 void setOurMac(const RTMAC& aMac) {m_OurMac = aMac;}
519
520 /* XXX: artifacts should be hidden or removed from here. */
521 PSUPDRVSESSION m_pSession;
522 INTNETIFHANDLE m_hIf;
523 PINTNETBUF m_pIfBuf;
524
525 private:
526 int prepareReplyPacket4Client(Client *client, uint32_t u32Xid);
527 int doReply(Client *client);
528 int processParameterReqList(Client *client, uint8_t *pu8ReqList, int cReqList);
529
530 union {
531 RTNETBOOTP BootPHeader;
532 uint8_t au8Storage[1024];
533 } BootPReplyMsg;
534 int cbBooPReplyMsg;
535
536 RTNETADDRIPV4 m_OurAddress;
537 RTNETADDRIPV4 m_OurNetmask;
538 RTMAC m_OurMac;
539
540 NetworkManager(){}
541 virtual ~NetworkManager(){}
542};
543
544
545
546class Lease
547{
548public:
549 Lease()
550 {
551 m_address.u = 0;
552 m_client = NULL;
553 fBinding = false;
554 u64TimestampBindingStarted = 0;
555 u64TimestampLeasingStarted = 0;
556 u32LeaseExpirationPeriod = 0;
557 u32BindExpirationPeriod = 0;
558 pCfg = NULL;
559 }
560 virtual ~Lease(){}
561
562 bool isExpired()
563 {
564 if (!fBinding)
565 return (ASMDivU64ByU32RetU32(RTTimeMilliTS() - u64TimestampLeasingStarted, 1000)
566 > u32LeaseExpirationPeriod);
567 else
568 return (ASMDivU64ByU32RetU32(RTTimeMilliTS() - u64TimestampBindingStarted, 1000)
569 > u32BindExpirationPeriod);
570
571 }
572
573 /* XXX private: */
574 RTNETADDRIPV4 m_address;
575
576 /** lease isn't commited */
577 bool fBinding;
578
579 /** Timestamp when lease commited. */
580 uint64_t u64TimestampLeasingStarted;
581 /** Period when lease is expired in secs. */
582 uint32_t u32LeaseExpirationPeriod;
583
584 /** timestamp when lease was bound */
585 uint64_t u64TimestampBindingStarted;
586 /* Period when binding is expired in secs. */
587 uint32_t u32BindExpirationPeriod;
588
589 NetworkConfigEntity *pCfg;
590 Client *m_client;
591};
592
593
594
595
596
597extern const ClientMatchCriteria *g_AnyClient;
598extern RootConfigEntity *g_RootConfig;
599extern const NullConfigEntity *g_NullConfig;
600
601/**
602 * Helper class for stuffing DHCP options into a reply packet.
603 */
604class VBoxNetDhcpWriteCursor
605{
606private:
607 uint8_t *m_pbCur; /**< The current cursor position. */
608 uint8_t *m_pbEnd; /**< The end the current option space. */
609 uint8_t *m_pfOverload; /**< Pointer to the flags of the overload option. */
610 uint8_t m_fUsed; /**< Overload fields that have been used. */
611 PRTNETDHCPOPT m_pOpt; /**< The current option. */
612 PRTNETBOOTP m_pDhcp; /**< The DHCP packet. */
613 bool m_fOverflowed; /**< Set if we've overflowed, otherwise false. */
614
615public:
616 /** Instantiate an option cursor for the specified DHCP message. */
617 VBoxNetDhcpWriteCursor(PRTNETBOOTP pDhcp, size_t cbDhcp) :
618 m_pbCur(&pDhcp->bp_vend.Dhcp.dhcp_opts[0]),
619 m_pbEnd((uint8_t *)pDhcp + cbDhcp),
620 m_pfOverload(NULL),
621 m_fUsed(0),
622 m_pOpt(NULL),
623 m_pDhcp(pDhcp),
624 m_fOverflowed(false)
625 {
626 AssertPtr(pDhcp);
627 Assert(cbDhcp > RT_UOFFSETOF(RTNETBOOTP, bp_vend.Dhcp.dhcp_opts[10]));
628 }
629
630 /** Destructor. */
631 ~VBoxNetDhcpWriteCursor()
632 {
633 m_pbCur = m_pbEnd = m_pfOverload = NULL;
634 m_pOpt = NULL;
635 m_pDhcp = NULL;
636 }
637
638 /**
639 * Try use the bp_file field.
640 * @returns true if not overloaded, false otherwise.
641 */
642 bool useBpFile(void)
643 {
644 if ( m_pfOverload
645 && (*m_pfOverload & 1))
646 return false;
647 m_fUsed |= 1 /* bp_file flag*/;
648 return true;
649 }
650
651
652 /**
653 * Try overload more BOOTP fields
654 */
655 bool overloadMore(void)
656 {
657 /* switch option area. */
658 uint8_t *pbNew;
659 uint8_t *pbNewEnd;
660 uint8_t fField;
661 if (!(m_fUsed & 1))
662 {
663 fField = 1;
664 pbNew = &m_pDhcp->bp_file[0];
665 pbNewEnd = &m_pDhcp->bp_file[sizeof(m_pDhcp->bp_file)];
666 }
667 else if (!(m_fUsed & 2))
668 {
669 fField = 2;
670 pbNew = &m_pDhcp->bp_sname[0];
671 pbNewEnd = &m_pDhcp->bp_sname[sizeof(m_pDhcp->bp_sname)];
672 }
673 else
674 return false;
675
676 if (!m_pfOverload)
677 {
678 /* Add an overload option. */
679 *m_pbCur++ = RTNET_DHCP_OPT_OPTION_OVERLOAD;
680 *m_pbCur++ = fField;
681 m_pfOverload = m_pbCur;
682 *m_pbCur++ = 1; /* bp_file flag */
683 }
684 else
685 *m_pfOverload |= fField;
686
687 /* pad current option field */
688 while (m_pbCur != m_pbEnd)
689 *m_pbCur++ = RTNET_DHCP_OPT_PAD; /** @todo not sure if this stuff is at all correct... */
690
691 /* switch */
692 m_pbCur = pbNew;
693 m_pbEnd = pbNewEnd;
694 return true;
695 }
696
697 /**
698 * Begin an option.
699 *
700 * @returns true on success, false if we're out of space.
701 *
702 * @param uOption The option number.
703 * @param cb The amount of data.
704 */
705 bool begin(uint8_t uOption, size_t cb)
706 {
707 /* Check that the data of the previous option has all been written. */
708 Assert( !m_pOpt
709 || (m_pbCur - m_pOpt->dhcp_len == (uint8_t *)(m_pOpt + 1)));
710 AssertMsg(cb <= 255, ("%#x\n", cb));
711
712 /* Check if we need to overload more stuff. */
713 if ((uintptr_t)(m_pbEnd - m_pbCur) < cb + 2 + (m_pfOverload ? 1 : 3))
714 {
715 m_pOpt = NULL;
716 if (!overloadMore())
717 {
718 m_fOverflowed = true;
719 AssertMsgFailedReturn(("%u %#x\n", uOption, cb), false);
720 }
721 if ((uintptr_t)(m_pbEnd - m_pbCur) < cb + 2 + 1)
722 {
723 m_fOverflowed = true;
724 AssertMsgFailedReturn(("%u %#x\n", uOption, cb), false);
725 }
726 }
727
728 /* Emit the option header. */
729 m_pOpt = (PRTNETDHCPOPT)m_pbCur;
730 m_pOpt->dhcp_opt = uOption;
731 m_pOpt->dhcp_len = (uint8_t)cb;
732 m_pbCur += 2;
733 return true;
734 }
735
736 /**
737 * Puts option data.
738 *
739 * @param pvData The data.
740 * @param cb The amount to put.
741 */
742 void put(void const *pvData, size_t cb)
743 {
744 Assert(m_pOpt || m_fOverflowed);
745 if (RT_LIKELY(m_pOpt))
746 {
747 Assert((uintptr_t)m_pbCur - (uintptr_t)(m_pOpt + 1) + cb <= (size_t)m_pOpt->dhcp_len);
748 memcpy(m_pbCur, pvData, cb);
749 m_pbCur += cb;
750 }
751 }
752
753 /**
754 * Puts an IPv4 Address.
755 *
756 * @param IPv4Addr The address.
757 */
758 void putIPv4Addr(RTNETADDRIPV4 IPv4Addr)
759 {
760 put(&IPv4Addr, 4);
761 }
762
763 /**
764 * Adds an IPv4 address option.
765 *
766 * @returns true/false just like begin().
767 *
768 * @param uOption The option number.
769 * @param IPv4Addr The address.
770 */
771 bool optIPv4Addr(uint8_t uOption, RTNETADDRIPV4 IPv4Addr)
772 {
773 if (!begin(uOption, 4))
774 return false;
775 putIPv4Addr(IPv4Addr);
776 return true;
777 }
778
779 /**
780 * Adds an option taking 1 or more IPv4 address.
781 *
782 * If the vector contains no addresses, the option will not be added.
783 *
784 * @returns true/false just like begin().
785 *
786 * @param uOption The option number.
787 * @param rIPv4Addrs Reference to the address vector.
788 */
789 bool optIPv4Addrs(uint8_t uOption, std::vector<RTNETADDRIPV4> const &rIPv4Addrs)
790 {
791 size_t const c = rIPv4Addrs.size();
792 if (!c)
793 return true;
794
795 if (!begin(uOption, 4*c))
796 return false;
797 for (size_t i = 0; i < c; i++)
798 putIPv4Addr(rIPv4Addrs[i]);
799 return true;
800 }
801
802 /**
803 * Puts an 8-bit integer.
804 *
805 * @param u8 The integer.
806 */
807 void putU8(uint8_t u8)
808 {
809 put(&u8, 1);
810 }
811
812 /**
813 * Adds an 8-bit integer option.
814 *
815 * @returns true/false just like begin().
816 *
817 * @param uOption The option number.
818 * @param u8 The integer
819 */
820 bool optU8(uint8_t uOption, uint8_t u8)
821 {
822 if (!begin(uOption, 1))
823 return false;
824 putU8(u8);
825 return true;
826 }
827
828 /**
829 * Puts an 32-bit integer (network endian).
830 *
831 * @param u32Network The integer.
832 */
833 void putU32(uint32_t u32)
834 {
835 put(&u32, 4);
836 }
837
838 /**
839 * Adds an 32-bit integer (network endian) option.
840 *
841 * @returns true/false just like begin().
842 *
843 * @param uOption The option number.
844 * @param u32Network The integer.
845 */
846 bool optU32(uint8_t uOption, uint32_t u32)
847 {
848 if (!begin(uOption, 4))
849 return false;
850 putU32(u32);
851 return true;
852 }
853
854 /**
855 * Puts a std::string.
856 *
857 * @param rStr Reference to the string.
858 */
859 void putStr(std::string const &rStr)
860 {
861 put(rStr.c_str(), rStr.size());
862 }
863
864 /**
865 * Adds an std::string option if the string isn't empty.
866 *
867 * @returns true/false just like begin().
868 *
869 * @param uOption The option number.
870 * @param rStr Reference to the string.
871 */
872 bool optStr(uint8_t uOption, std::string const &rStr)
873 {
874 const size_t cch = rStr.size();
875 if (!cch)
876 return true;
877
878 if (!begin(uOption, cch))
879 return false;
880 put(rStr.c_str(), cch);
881 return true;
882 }
883
884 /**
885 * Whether we've overflowed.
886 *
887 * @returns true on overflow, false otherwise.
888 */
889 bool hasOverflowed(void) const
890 {
891 return m_fOverflowed;
892 }
893
894 /**
895 * Adds the terminating END option.
896 *
897 * The END will always be added as we're reserving room for it, however, we
898 * might have dropped previous options due to overflows and that is what the
899 * return status indicates.
900 *
901 * @returns true on success, false on a (previous) overflow.
902 */
903 bool optEnd(void)
904 {
905 Assert((uintptr_t)(m_pbEnd - m_pbCur) < 4096);
906 *m_pbCur++ = RTNET_DHCP_OPT_END;
907 return !hasOverflowed();
908 }
909};
910
911#endif
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