VirtualBox

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

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

previous r87050, was re-commit of r86970

DHCP becomes Main client, internals changed to let more flexible managment and describing more complex networks (current state, so it should not brake a lot things, but something could stop working).
more stuff moved to BaseNetworkService class.

and r87051 nukes trailing whitespaces.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.0 KB
Line 
1/* $Id: Config.h 47020 2013-07-06 17:42:33Z vboxsync $ */
2/**
3 * This file contains declarations of DHCP config.
4 */
5
6#ifndef _CONFIG_H_
7# define _CONFIG_H_
8
9#include <iprt/cpp/utils.h>
10
11typedef std::vector<RTMAC> MacAddressContainer;
12typedef MacAddressContainer::iterator MacAddressIterator;
13
14typedef std::vector<RTNETADDRIPV4> Ipv4AddressContainer;
15typedef Ipv4AddressContainer::iterator Ipv4AddressIterator;
16typedef Ipv4AddressContainer::const_iterator Ipv4AddressConstIterator;
17
18static bool operator <(const RTNETADDRIPV4& a, const RTNETADDRIPV4& b)
19{
20 return (RT_N2H_U32(a.u) < RT_N2H_U32(b.u));
21}
22
23static bool operator > (const RTNETADDRIPV4& a, const RTNETADDRIPV4& b)
24{
25 return (b < a);
26}
27
28
29typedef enum CLIENTSESSIONSTATE
30{
31 /**
32 * defult state, session isn't operable, not initialized an so on.
33 */
34 DHCPNONSENSE,
35 /** We've received dhcp discover =>
36 * we're starting new client and/or session.
37 * Using XID (we record session)
38 * and response with DHCPOFFER
39 */
40 DHCPDISCOVERRECEIEVED,
41 /**
42 * We're ready to send DHCPOFFER
43 */
44 DHCPOFFERPREPARED,
45 /**
46 * This more, session state, we responsed, to
47 * client with DHCPOFFER using session's XID
48 */
49 DHCPOFFERSENT,
50 /**
51 * this is session's state, client's done DHCPREQUEST with (XID)
52 */
53 DHCPREQUESTRECEIVED,
54 /**
55 * We're ready to send DHCPACK or DHCPNAK
56 */
57 DHCPACKNAKPREPARED,
58 /**
59 * We've been able to furfill client's request for (XID) session, erased others Client
60 * 's sessions ... and send DHCPACK (should be Lease bind at this point?)
61 */
62 DHCPACKSENT,
63 /**
64 * We couldn't furfill client's request -> destroy session.
65 */
66 DHCPNACKSENT,
67 /**
68 * real client, don't want our DHCPOFFER, we're delating our client representation,
69 * and sessions objects.
70 */
71 DHCPDECLINERECEIVED,
72 /**
73 * nice to have, but not mandatory.
74 */
75 DHCPINFORMRECEIVED
76} CLIENTSESSIONSTATE;
77
78
79class RawOption
80{
81public:
82 uint8_t u8OptId;
83 uint8_t cbRawOpt;
84 uint8_t au8RawOpt[255];
85};
86
87
88class Client;
89class BaseConfigEntity;
90
91/**
92 * This class joins client and the lease ...
93 * at the begining client might request several address assignments...
94 *
95 * So session here is descriptor joining client to each of it's requests.
96 * When client finalizes its selection ... only single assignment is chosen,
97 * others are released.
98 */
99class Session
100{
101public:
102 Session(const Client *client = NULL,
103 uint32_t xid = 0,
104 CLIENTSESSIONSTATE enmState = DHCPNONSENSE):
105 m_pClient(client),
106 m_state(enmState),
107 m_u32Xid(xid),
108 m_pCfg(NULL)
109 {
110 /* XXX: state ? Which is acceptable on initialization ?! */
111 addressHint.u = 0;
112 RT_ZERO(reqParamList);
113 }
114
115 bool operator < (const Session& s) const;
116
117 int switchTo(CLIENTSESSIONSTATE);
118 /* XXX private: */
119
120 /**/
121 const Client* m_pClient;
122 /* We don't store the state in the client, because client might initiate several
123 * sessions.
124 */
125 CLIENTSESSIONSTATE m_state;
126 /**
127 * uniq identificator of session
128 */
129 uint32_t m_u32Xid;
130
131 /* dhcp-opts: request address */
132 RTNETADDRIPV4 addressHint;
133
134 /* dhcp-opts: request parameter list */
135 RawOption reqParamList;
136 /* Config for this session */
137 const BaseConfigEntity *m_pCfg;
138
139 /**
140 * times used for evaluating wherther Session/Lease could be expired.
141 */
142
143 RTTIMESPEC creation;
144 RTTIMESPEC expiration;
145};
146
147typedef std::map<uint32_t, Session> Map2ClientSession;
148typedef Map2ClientSession::value_type Map2ClientSessionType;
149typedef Map2ClientSession::iterator Map2ClientSessionIterator;
150
151class Lease
152{
153public:
154 Lease(const Session& session):m_pClient(session.m_pClient){}
155 virtual ~Lease(){}
156private:
157 const Client *m_pClient;
158
159 bool operator == (const Session& session) const
160 {
161 /* XXX: pointer comparison, perhaps not we really need */
162 return (session.m_pClient == m_pClient);
163 }
164};
165
166typedef std::map<Lease, RTNETADDRIPV4> MapLease2Ip4Address;
167typedef MapLease2Ip4Address::value_type MapLease2Ip4AddressPair;
168typedef MapLease2Ip4Address::iterator MapLease2Ip4AddressIterator;
169
170/*
171 * it's a basic representation of
172 * of out undestanding what client is
173 * XXX: Client might sends Option 61 (RFC2132 9.14 "Client-identifier") signalling
174 * that we may identify it in special way
175 *
176 * XXX: Client might send Option 60 (RFC2132 9.13 "Vendor class undentifier")
177 * in response it's expected server sends Option 43 (RFC2132 8.4. "Vendor Specific Information")
178 */
179class Client
180{
181 public:
182
183 /* XXX: Option 60 and 61 */
184 Client(const RTMAC& mac, uint32_t xid = 0);
185
186 bool operator== (const RTMAC& mac) const
187 {
188 return ( m_mac.au16[0] == mac.au16[0]
189 && m_mac.au16[1] == mac.au16[1]
190 && m_mac.au16[2] == mac.au16[2]);
191 }
192 /** Dumps client query */
193 void dump();
194
195 /* XXX! private: */
196
197 RTMAC m_mac;
198 Map2ClientSession m_sessions;
199 /* XXX: it's logically per session object, but some client broke XIDness */
200 /* XXX: we're using it as stack */
201 std::vector<RawOption> rawOptions;
202};
203
204
205typedef std::vector<Client> VecClient;
206typedef VecClient::iterator VecClientIterator;
207typedef VecClient::const_iterator VecClientConstIterator;
208
209
210class SessionManager
211{
212 public:
213
214 static SessionManager* getSessionManager();
215
216 /**
217 * This method we call on every DHCP packet we've received.
218 * 1. it finds/creates Client/and Session Object.
219 */
220 Session& getClientSessionByDhcpPacket(const RTNETBOOTP* pDhcpMsg, size_t cbPacket);
221
222 /* XXX: DHCPDECLINE */
223 void releaseClientSession(Session& session);
224 /* XXX: DHCPRELEASE */
225 void releaseClient(Client& client);
226
227 private:
228
229 VecClient m_clients;
230
231 SessionManager(){}
232 virtual ~SessionManager(){}
233};
234
235
236typedef std::map<Session, RTNETADDRIPV4> MapSession2Ip4Address;
237typedef MapSession2Ip4Address::iterator MapSession2Ip4AddressIterator;
238typedef MapSession2Ip4Address::value_type MapSession2Ip4AddressPair;
239
240class NetworkConfigEntity;
241class HostConfigEntity;
242class ClientMatchCriteria;
243
244class ConfigurationManager
245{
246 public:
247 static ConfigurationManager* getConfigurationManager();
248
249 /**
250 * We call this on DHCPDISCOVER
251 */
252 int findConfiguration4Session(Session& session);
253
254 /**
255 * XXX: it's could be done on DHCPOFFER or on DHCPACK (rfc2131 gives freedom here
256 * 3.1.2, what is strict that allocation should do address check before real
257 * allocation)...
258 */
259 int allocateConfiguration4Session(Session& session);
260
261 /*
262 * We call this before DHCPACK sent and after DHCPREQUEST received ...
263 * when requested configuration is acceptable.
264 */
265 int commitConfiguration4ClientSession(Session& sesion);
266
267 static int findOption(uint8_t uOption, PCRTNETBOOTP pDhcpMsg, size_t cbDhcpMsg, RawOption& opt);
268
269 NetworkConfigEntity *addNetwork(NetworkConfigEntity *pCfg,
270 const RTNETADDRIPV4& networkId,
271 const RTNETADDRIPV4& netmask,
272 RTNETADDRIPV4& UpperAddress,
273 RTNETADDRIPV4& LowerAddress);
274
275 HostConfigEntity *addHost(NetworkConfigEntity*, const RTNETADDRIPV4&, ClientMatchCriteria*);
276
277 RTNETADDRIPV4 getSessionAddress(const Session& session);
278
279 /* XXX: from config */
280 uint32_t getLeaseTime() {return 600;}
281
282 int addToAddressList(uint8_t u8OptId, RTNETADDRIPV4& address)
283 {
284 switch(u8OptId)
285 {
286 case RTNET_DHCP_OPT_DNS:
287 m_nameservers.push_back(address);
288 break;
289 case RTNET_DHCP_OPT_ROUTERS:
290 m_routers.push_back(address);
291 break;
292 default:
293 Log(("dhcp-opt: list (%d) unsupported\n", u8OptId));
294 }
295 return VINF_SUCCESS;
296 }
297
298 int flushAddressList(uint8_t u8OptId)
299 {
300 switch(u8OptId)
301 {
302 case RTNET_DHCP_OPT_DNS:
303 m_nameservers.clear();
304 break;
305 case RTNET_DHCP_OPT_ROUTERS:
306 m_routers.clear();
307 break;
308 default:
309 Log(("dhcp-opt: list (%d) unsupported\n", u8OptId));
310 }
311 return VINF_SUCCESS;
312 }
313
314 const Ipv4AddressContainer& getAddressList(uint8_t u8OptId)
315 {
316 switch(u8OptId)
317 {
318 case RTNET_DHCP_OPT_DNS:
319 return m_nameservers;
320
321 case RTNET_DHCP_OPT_ROUTERS:
322 return m_routers;
323
324 }
325 /* XXX: Grrr !!! */
326 return m_empty;
327 }
328
329 private:
330 ConfigurationManager(){}
331 virtual ~ConfigurationManager(){}
332 MapSession2Ip4Address m_allocations;
333 /*
334 *
335 */
336 Ipv4AddressContainer m_nameservers;
337 Ipv4AddressContainer m_routers;
338 Ipv4AddressContainer m_empty;
339
340};
341
342
343class NetworkManager
344{
345 public:
346 static NetworkManager *getNetworkManager();
347
348 int offer4Session(Session& ses);
349 int ack(Session& ses);
350 int nak(Session& ses);
351
352 const RTNETADDRIPV4& getOurAddress(){ return m_OurAddress;}
353 const RTNETADDRIPV4& getOurNetmask(){ return m_OurNetmask;}
354 const RTMAC& getOurMac() {return m_OurMac;}
355
356 void setOurAddress(const RTNETADDRIPV4& aAddress){ m_OurAddress = aAddress;}
357 void setOurNetmask(const RTNETADDRIPV4& aNetmask){ m_OurNetmask = aNetmask;}
358 void setOurMac(const RTMAC& aMac) {m_OurMac = aMac;}
359
360 /* XXX: artifacts should be hidden or removed from here. */
361 PSUPDRVSESSION m_pSession;
362 INTNETIFHANDLE m_hIf;
363 PINTNETBUF m_pIfBuf;
364
365 private:
366 int prepareReplyPacket4Session(const Session& session);
367 int doReply(const Session& session);
368 int processParameterReqList(Session& session);
369
370 union {
371 RTNETBOOTP BootPHeader;
372 uint8_t au8Storage[1024];
373 } BootPReplyMsg;
374 int cbBooPReplyMsg;
375
376 RTNETADDRIPV4 m_OurAddress;
377 RTNETADDRIPV4 m_OurNetmask;
378 RTMAC m_OurMac;
379
380 NetworkManager(){}
381 virtual ~NetworkManager(){}
382};
383
384/**
385 *
386 */
387class ClientMatchCriteria
388{
389 public:
390 virtual bool check(const Client& client) const {return false;};
391};
392
393
394class ORClientMatchCriteria: ClientMatchCriteria
395{
396 ClientMatchCriteria* m_left;
397 ClientMatchCriteria* m_right;
398 ORClientMatchCriteria(ClientMatchCriteria *left, ClientMatchCriteria *right)
399 {
400 m_left = left;
401 m_right = right;
402 }
403
404 virtual bool check(const Client& client) const
405 {
406 return (m_left->check(client) || m_right->check(client));
407 }
408};
409
410
411class ANDClientMatchCriteria: ClientMatchCriteria
412{
413 ClientMatchCriteria* m_left;
414 ClientMatchCriteria* m_right;
415 ANDClientMatchCriteria(ClientMatchCriteria *left, ClientMatchCriteria *right)
416 {
417 m_left = left;
418 m_right = right;
419 }
420
421 virtual bool check(const Client& client) const
422 {
423 return (m_left->check(client) && m_right->check(client));
424 }
425};
426
427
428class AnyClientMatchCriteria: public ClientMatchCriteria
429{
430 virtual bool check(const Client& client) const
431 {
432 return true;
433 }
434};
435
436
437class MACClientMatchCriteria: public ClientMatchCriteria
438{
439
440 public:
441 MACClientMatchCriteria(const RTMAC& mac):m_mac(mac){}
442
443 virtual bool check(const Client& client) const
444 {
445 return (client == m_mac);
446 }
447 private:
448 RTMAC m_mac;
449};
450
451
452#if 0
453/* XXX: Later */
454class VmSlotClientMatchCriteria: public ClientMatchCriteria
455{
456 str::string VmName;
457 uint8_t u8Slot;
458 virtual bool check(const Client& client)
459 {
460 return ( client.VmName == VmName
461 && ( u8Slot == (uint8_t)~0 /* any */
462 || client.u8Slot == u8Slot));
463 }
464};
465#endif
466
467
468/* Option 60 */
469class ClassClientMatchCriteria: ClientMatchCriteria{};
470/* Option 61 */
471class ClientIdentifierMatchCriteria: ClientMatchCriteria{};
472
473
474class BaseConfigEntity
475{
476public:
477 BaseConfigEntity(const ClientMatchCriteria *criteria = NULL,
478 int matchingLevel = 0)
479 : m_criteria(criteria),
480 m_MatchLevel(matchingLevel){};
481 virtual ~BaseConfigEntity(){};
482 /* XXX */
483 int add(BaseConfigEntity *cfg)
484 {
485 m_children.push_back(cfg);
486 return 0;
487 }
488
489 /* Should return how strong matching */
490 virtual int match(const Client& client, const BaseConfigEntity **cfg) const
491 {
492 int iMatch = (m_criteria && m_criteria->check(client)? m_MatchLevel: 0);
493 if (m_children.empty())
494 {
495 if (iMatch > 0)
496 {
497 *cfg = this;
498 return iMatch;
499 }
500 }
501 else
502 {
503 *cfg = this;
504 /* XXX: hack */
505 BaseConfigEntity const *matching = this;
506 int matchingLevel = m_MatchLevel;
507
508 for (std::vector<const BaseConfigEntity *>::const_iterator it = m_children.begin();
509 it != m_children.end();
510 ++it)
511 {
512 iMatch = (*it)->match(client, &matching);
513 if (iMatch > matchingLevel)
514 {
515 *cfg = matching;
516 matchingLevel = iMatch;
517 }
518 }
519 return matchingLevel;
520 }
521 return iMatch;
522 }
523
524 protected:
525 const ClientMatchCriteria *m_criteria;
526 int m_MatchLevel;
527 std::vector<const BaseConfigEntity *> m_children;
528};
529
530
531class NullConfigEntity: public BaseConfigEntity
532{
533public:
534 NullConfigEntity(){}
535 virtual ~NullConfigEntity(){}
536 int add(BaseConfigEntity *cfg) const
537 {
538 return 0;
539 }
540};
541
542
543class ConfigEntity: public BaseConfigEntity
544{
545 public:
546
547 /* range */
548 /* match conditions */
549 ConfigEntity(std::string& name,
550 const BaseConfigEntity *cfg,
551 const ClientMatchCriteria *criteria,
552 int matchingLevel = 0):
553 BaseConfigEntity(criteria, matchingLevel),
554 m_name(name),
555 m_parentCfg(cfg)
556 {
557 unconst(m_parentCfg)->add(this);
558 }
559
560 std::string m_name;
561 const BaseConfigEntity *m_parentCfg;
562};
563
564
565/**
566 * Network specific entries
567 */
568class NetworkConfigEntity:public ConfigEntity
569{
570 public:
571 /* Address Pool matching with network declaration */
572 NetworkConfigEntity(std::string name,
573 const BaseConfigEntity *cfg,
574 const ClientMatchCriteria *criteria,
575 int matchlvl,
576 const RTNETADDRIPV4& networkID,
577 const RTNETADDRIPV4& networkMask,
578 const RTNETADDRIPV4& lowerIP,
579 const RTNETADDRIPV4& upperIP):
580 ConfigEntity(name, cfg, criteria, matchlvl),
581 m_NetworkID(networkID),
582 m_NetworkMask(networkMask),
583 m_UpperIP(upperIP),
584 m_LowerIP(lowerIP)
585 {
586 };
587
588 NetworkConfigEntity(std::string name,
589 const BaseConfigEntity *cfg,
590 const ClientMatchCriteria *criteria,
591 const RTNETADDRIPV4& networkID,
592 const RTNETADDRIPV4& networkMask):
593 ConfigEntity(name, cfg, criteria, 5),
594 m_NetworkID(networkID),
595 m_NetworkMask(networkMask)
596 {
597 m_UpperIP.u = m_NetworkID.u | (~m_NetworkMask.u);
598 m_LowerIP.u = m_NetworkID.u;
599 };
600
601 const RTNETADDRIPV4& upperIp() const {return m_UpperIP;}
602 const RTNETADDRIPV4& lowerIp() const {return m_LowerIP;}
603 const RTNETADDRIPV4& networkId() const {return m_NetworkID;}
604 const RTNETADDRIPV4& netmask() const {return m_NetworkMask;}
605
606 private:
607 RTNETADDRIPV4 m_NetworkID;
608 RTNETADDRIPV4 m_NetworkMask;
609 RTNETADDRIPV4 m_UpperIP;
610 RTNETADDRIPV4 m_LowerIP;
611};
612
613
614/**
615 * Host specific entry
616 * Address pool is contains one element
617 */
618class HostConfigEntity: public NetworkConfigEntity
619{
620
621 public:
622 HostConfigEntity(const RTNETADDRIPV4& addr,
623 std::string name,
624 const NetworkConfigEntity *cfg,
625 const ClientMatchCriteria *criteria):
626 NetworkConfigEntity(name,
627 static_cast<const ConfigEntity*>(cfg),
628 criteria,
629 10,
630 cfg->networkId(),
631 cfg->netmask(),
632 addr,
633 addr)
634 {
635 /* upper addr == lower addr */
636 }
637
638 virtual int match(const Client& client) const
639 {
640 return (m_criteria->check(client) ? 10 : 0);
641 }
642
643};
644
645class RootConfigEntity: public NetworkConfigEntity
646{
647 public:
648 RootConfigEntity(std::string name);
649 virtual ~RootConfigEntity(){};
650};
651
652
653#if 0
654/**
655 * Shared regions e.g. some of configured networks declarations
656 * are cover each other.
657 * XXX: Shared Network is join on Network config entities with possible
658 * overlaps in address pools. for a moment we won't configure and use them them
659 */
660class SharedNetworkConfigEntity: public NetworkEntity
661{
662 public:
663 SharedNetworkConfigEntity(){}
664 int match(const Client& client) const { return m_criteria.match(client)? 3 : 0;}
665
666 SharedNetworkConfigEntity(NetworkEntity& network)
667 {
668 Networks.push_back(network);
669 }
670 virtual ~SharedNetworkConfigEntity(){}
671
672 std::vector<NetworkConfigEntity> Networks;
673
674};
675#endif
676
677
678extern const ClientMatchCriteria *g_AnyClient;
679extern const RootConfigEntity *g_RootConfig;
680extern const NullConfigEntity *g_NullConfig;
681
682/**
683 * Helper class for stuffing DHCP options into a reply packet.
684 */
685class VBoxNetDhcpWriteCursor
686{
687private:
688 uint8_t *m_pbCur; /**< The current cursor position. */
689 uint8_t *m_pbEnd; /**< The end the current option space. */
690 uint8_t *m_pfOverload; /**< Pointer to the flags of the overload option. */
691 uint8_t m_fUsed; /**< Overload fields that have been used. */
692 PRTNETDHCPOPT m_pOpt; /**< The current option. */
693 PRTNETBOOTP m_pDhcp; /**< The DHCP packet. */
694 bool m_fOverflowed; /**< Set if we've overflowed, otherwise false. */
695
696public:
697 /** Instantiate an option cursor for the specified DHCP message. */
698 VBoxNetDhcpWriteCursor(PRTNETBOOTP pDhcp, size_t cbDhcp) :
699 m_pbCur(&pDhcp->bp_vend.Dhcp.dhcp_opts[0]),
700 m_pbEnd((uint8_t *)pDhcp + cbDhcp),
701 m_pfOverload(NULL),
702 m_fUsed(0),
703 m_pOpt(NULL),
704 m_pDhcp(pDhcp),
705 m_fOverflowed(false)
706 {
707 AssertPtr(pDhcp);
708 Assert(cbDhcp > RT_UOFFSETOF(RTNETBOOTP, bp_vend.Dhcp.dhcp_opts[10]));
709 }
710
711 /** Destructor. */
712 ~VBoxNetDhcpWriteCursor()
713 {
714 m_pbCur = m_pbEnd = m_pfOverload = NULL;
715 m_pOpt = NULL;
716 m_pDhcp = NULL;
717 }
718
719 /**
720 * Try use the bp_file field.
721 * @returns true if not overloaded, false otherwise.
722 */
723 bool useBpFile(void)
724 {
725 if ( m_pfOverload
726 && (*m_pfOverload & 1))
727 return false;
728 m_fUsed |= 1 /* bp_file flag*/;
729 return true;
730 }
731
732
733 /**
734 * Try overload more BOOTP fields
735 */
736 bool overloadMore(void)
737 {
738 /* switch option area. */
739 uint8_t *pbNew;
740 uint8_t *pbNewEnd;
741 uint8_t fField;
742 if (!(m_fUsed & 1))
743 {
744 fField = 1;
745 pbNew = &m_pDhcp->bp_file[0];
746 pbNewEnd = &m_pDhcp->bp_file[sizeof(m_pDhcp->bp_file)];
747 }
748 else if (!(m_fUsed & 2))
749 {
750 fField = 2;
751 pbNew = &m_pDhcp->bp_sname[0];
752 pbNewEnd = &m_pDhcp->bp_sname[sizeof(m_pDhcp->bp_sname)];
753 }
754 else
755 return false;
756
757 if (!m_pfOverload)
758 {
759 /* Add an overload option. */
760 *m_pbCur++ = RTNET_DHCP_OPT_OPTION_OVERLOAD;
761 *m_pbCur++ = fField;
762 m_pfOverload = m_pbCur;
763 *m_pbCur++ = 1; /* bp_file flag */
764 }
765 else
766 *m_pfOverload |= fField;
767
768 /* pad current option field */
769 while (m_pbCur != m_pbEnd)
770 *m_pbCur++ = RTNET_DHCP_OPT_PAD; /** @todo not sure if this stuff is at all correct... */
771
772 /* switch */
773 m_pbCur = pbNew;
774 m_pbEnd = pbNewEnd;
775 return true;
776 }
777
778 /**
779 * Begin an option.
780 *
781 * @returns true on success, false if we're out of space.
782 *
783 * @param uOption The option number.
784 * @param cb The amount of data.
785 */
786 bool begin(uint8_t uOption, size_t cb)
787 {
788 /* Check that the data of the previous option has all been written. */
789 Assert( !m_pOpt
790 || (m_pbCur - m_pOpt->dhcp_len == (uint8_t *)(m_pOpt + 1)));
791 AssertMsg(cb <= 255, ("%#x\n", cb));
792
793 /* Check if we need to overload more stuff. */
794 if ((uintptr_t)(m_pbEnd - m_pbCur) < cb + 2 + (m_pfOverload ? 1 : 3))
795 {
796 m_pOpt = NULL;
797 if (!overloadMore())
798 {
799 m_fOverflowed = true;
800 AssertMsgFailedReturn(("%u %#x\n", uOption, cb), false);
801 }
802 if ((uintptr_t)(m_pbEnd - m_pbCur) < cb + 2 + 1)
803 {
804 m_fOverflowed = true;
805 AssertMsgFailedReturn(("%u %#x\n", uOption, cb), false);
806 }
807 }
808
809 /* Emit the option header. */
810 m_pOpt = (PRTNETDHCPOPT)m_pbCur;
811 m_pOpt->dhcp_opt = uOption;
812 m_pOpt->dhcp_len = (uint8_t)cb;
813 m_pbCur += 2;
814 return true;
815 }
816
817 /**
818 * Puts option data.
819 *
820 * @param pvData The data.
821 * @param cb The amount to put.
822 */
823 void put(void const *pvData, size_t cb)
824 {
825 Assert(m_pOpt || m_fOverflowed);
826 if (RT_LIKELY(m_pOpt))
827 {
828 Assert((uintptr_t)m_pbCur - (uintptr_t)(m_pOpt + 1) + cb <= (size_t)m_pOpt->dhcp_len);
829 memcpy(m_pbCur, pvData, cb);
830 m_pbCur += cb;
831 }
832 }
833
834 /**
835 * Puts an IPv4 Address.
836 *
837 * @param IPv4Addr The address.
838 */
839 void putIPv4Addr(RTNETADDRIPV4 IPv4Addr)
840 {
841 put(&IPv4Addr, 4);
842 }
843
844 /**
845 * Adds an IPv4 address option.
846 *
847 * @returns true/false just like begin().
848 *
849 * @param uOption The option number.
850 * @param IPv4Addr The address.
851 */
852 bool optIPv4Addr(uint8_t uOption, RTNETADDRIPV4 IPv4Addr)
853 {
854 if (!begin(uOption, 4))
855 return false;
856 putIPv4Addr(IPv4Addr);
857 return true;
858 }
859
860 /**
861 * Adds an option taking 1 or more IPv4 address.
862 *
863 * If the vector contains no addresses, the option will not be added.
864 *
865 * @returns true/false just like begin().
866 *
867 * @param uOption The option number.
868 * @param rIPv4Addrs Reference to the address vector.
869 */
870 bool optIPv4Addrs(uint8_t uOption, std::vector<RTNETADDRIPV4> const &rIPv4Addrs)
871 {
872 size_t const c = rIPv4Addrs.size();
873 if (!c)
874 return true;
875
876 if (!begin(uOption, 4*c))
877 return false;
878 for (size_t i = 0; i < c; i++)
879 putIPv4Addr(rIPv4Addrs[i]);
880 return true;
881 }
882
883 /**
884 * Puts an 8-bit integer.
885 *
886 * @param u8 The integer.
887 */
888 void putU8(uint8_t u8)
889 {
890 put(&u8, 1);
891 }
892
893 /**
894 * Adds an 8-bit integer option.
895 *
896 * @returns true/false just like begin().
897 *
898 * @param uOption The option number.
899 * @param u8 The integer
900 */
901 bool optU8(uint8_t uOption, uint8_t u8)
902 {
903 if (!begin(uOption, 1))
904 return false;
905 putU8(u8);
906 return true;
907 }
908
909 /**
910 * Puts an 32-bit integer (network endian).
911 *
912 * @param u32Network The integer.
913 */
914 void putU32(uint32_t u32)
915 {
916 put(&u32, 4);
917 }
918
919 /**
920 * Adds an 32-bit integer (network endian) option.
921 *
922 * @returns true/false just like begin().
923 *
924 * @param uOption The option number.
925 * @param u32Network The integer.
926 */
927 bool optU32(uint8_t uOption, uint32_t u32)
928 {
929 if (!begin(uOption, 4))
930 return false;
931 putU32(u32);
932 return true;
933 }
934
935 /**
936 * Puts a std::string.
937 *
938 * @param rStr Reference to the string.
939 */
940 void putStr(std::string const &rStr)
941 {
942 put(rStr.c_str(), rStr.size());
943 }
944
945 /**
946 * Adds an std::string option if the string isn't empty.
947 *
948 * @returns true/false just like begin().
949 *
950 * @param uOption The option number.
951 * @param rStr Reference to the string.
952 */
953 bool optStr(uint8_t uOption, std::string const &rStr)
954 {
955 const size_t cch = rStr.size();
956 if (!cch)
957 return true;
958
959 if (!begin(uOption, cch))
960 return false;
961 put(rStr.c_str(), cch);
962 return true;
963 }
964
965 /**
966 * Whether we've overflowed.
967 *
968 * @returns true on overflow, false otherwise.
969 */
970 bool hasOverflowed(void) const
971 {
972 return m_fOverflowed;
973 }
974
975 /**
976 * Adds the terminating END option.
977 *
978 * The END will always be added as we're reserving room for it, however, we
979 * might have dropped previous options due to overflows and that is what the
980 * return status indicates.
981 *
982 * @returns true on success, false on a (previous) overflow.
983 */
984 bool optEnd(void)
985 {
986 Assert((uintptr_t)(m_pbEnd - m_pbCur) < 4096);
987 *m_pbCur++ = RTNET_DHCP_OPT_END;
988 return !hasOverflowed();
989 }
990};
991
992#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