INET Framework for OMNeT++/OMNEST
inet::DhcpServer Class Reference

Implements a DHCP server. More...

#include <DhcpServer.h>

Inheritance diagram for inet::DhcpServer:
inet::ApplicationBase inet::UdpSocket::ICallback inet::OperationalBase inet::OperationalMixin< cSimpleModule > inet::ILifecycle

Public Member Functions

 DhcpServer ()
 
virtual ~DhcpServer ()
 
- Public Member Functions inherited from inet::ApplicationBase
 ApplicationBase ()
 
- Public Member Functions inherited from inet::OperationalMixin< cSimpleModule >
virtual ~OperationalMixin ()
 }@ More...
 
- Public Member Functions inherited from inet::ILifecycle
virtual ~ILifecycle ()
 
- Public Member Functions inherited from inet::UdpSocket::ICallback
virtual ~ICallback ()
 

Protected Types

enum  TimerType { START_DHCP }
 
typedef std::map< Ipv4Address, DhcpLeaseDhcpLeased
 
- Protected Types inherited from inet::OperationalMixin< cSimpleModule >
enum  State
 

Protected Member Functions

virtual int numInitStages () const override
 
virtual void initialize (int stage) override
 
virtual void handleMessageWhenUp (cMessage *msg) override
 
virtual void openSocket ()
 
virtual DhcpLeasegetLeaseByMac (MacAddress mac)
 
virtual DhcpLeasegetAvailableLease (Ipv4Address requestedAddress, const MacAddress &clientMAC)
 
virtual void processDhcpMessage (Packet *packet)
 
virtual void sendOffer (DhcpLease *lease, const Ptr< const DhcpMessage > &dhcpMsg)
 
virtual void sendAck (DhcpLease *lease, const Ptr< const DhcpMessage > &dhcpMsg)
 
virtual void sendNak (const Ptr< const DhcpMessage > &dhcpMsg)
 
virtual void handleSelfMessages (cMessage *msg)
 
virtual NetworkInterfacechooseInterface ()
 
virtual void sendToUDP (Packet *msg, int srcPort, const L3Address &destAddr, int destPort)
 
virtual void socketDataArrived (UdpSocket *socket, Packet *packet) override
 Notifies about data arrival, packet ownership is transferred to the callee. More...
 
virtual void socketErrorArrived (UdpSocket *socket, Indication *indication) override
 Notifies about error indication arrival, indication ownership is transferred to the callee. More...
 
virtual void socketClosed (UdpSocket *socket) override
 Notifies about socket closed, indication ownership is transferred to the callee. More...
 
virtual void receiveSignal (cComponent *source, simsignal_t signalID, cObject *obj, cObject *details) override
 
virtual void handleStartOperation (LifecycleOperation *operation) override
 
virtual void handleStopOperation (LifecycleOperation *operation) override
 
virtual void handleCrashOperation (LifecycleOperation *operation) override
 
- Protected Member Functions inherited from inet::ApplicationBase
virtual bool isInitializeStage (int stage) const override
 
virtual bool isModuleStartStage (int stage) const override
 
virtual bool isModuleStopStage (int stage) const override
 
- Protected Member Functions inherited from inet::OperationalMixin< cSimpleModule >
virtual int numInitStages () const override
 
virtual void refreshDisplay () const override
 
virtual void handleMessage (cMessage *msg) override
 
virtual void handleMessageWhenDown (cMessage *msg)
 
virtual bool handleOperationStage (LifecycleOperation *operation, IDoneCallback *doneCallback) override
 Perform one stage of a lifecycle operation. More...
 
virtual State getInitialOperationalState () const
 Returns initial operational state: OPERATING or NOT_OPERATING. More...
 
virtual void handleActiveOperationTimeout (cMessage *message)
 
virtual bool isUp () const
 utility functions More...
 
virtual bool isDown () const
 
virtual void setOperationalState (State newState)
 
virtual void scheduleOperationTimeout (simtime_t timeout)
 
virtual void setupActiveOperation (LifecycleOperation *operation, IDoneCallback *doneCallback, State)
 
virtual void delayActiveOperationFinish (simtime_t timeout)
 
virtual void startActiveOperationExtraTime (simtime_t delay=SIMTIME_ZERO)
 
virtual void startActiveOperationExtraTimeOrFinish (simtime_t extraTime)
 
virtual void finishActiveOperation ()
 

Protected Attributes

DhcpLeased leased
 
int numSent = 0
 
int numReceived = 0
 
int serverPort = -1
 
int clientPort = -1
 
unsigned int maxNumOfClients = 0
 
unsigned int leaseTime = 0
 
Ipv4Address subnetMask
 
Ipv4Address gateway
 
Ipv4Address ipAddressStart
 
NetworkInterfaceie = nullptr
 
UdpSocket socket
 
simtime_t startTime
 
cMessage * startTimer = nullptr
 
- Protected Attributes inherited from inet::OperationalMixin< cSimpleModule >
State operationalState
 
simtime_t lastChange
 
Operation activeOperation
 
cMessage * activeOperationTimeout
 
cMessage * activeOperationExtraTimer
 

Detailed Description

Implements a DHCP server.

See NED file for more details.

Member Typedef Documentation

◆ DhcpLeased

typedef std::map<Ipv4Address, DhcpLease> inet::DhcpServer::DhcpLeased
protected

Member Enumeration Documentation

◆ TimerType

Enumerator
START_DHCP 
30  {
32  };

Constructor & Destructor Documentation

◆ DhcpServer()

inet::DhcpServer::DhcpServer ( )
26 {
27  ie = nullptr;
28  startTimer = nullptr;
29 }

◆ ~DhcpServer()

inet::DhcpServer::~DhcpServer ( )
virtual
32 {
33  cancelAndDelete(startTimer);
34 }

Member Function Documentation

◆ chooseInterface()

NetworkInterface * inet::DhcpServer::chooseInterface ( )
protectedvirtual
86 {
87  IInterfaceTable *ift = getModuleFromPar<IInterfaceTable>(par("interfaceTableModule"), this);
88  const char *interfaceName = par("interface");
89  NetworkInterface *ie = nullptr;
90 
91  if (strlen(interfaceName) > 0) {
92  ie = ift->findInterfaceByName(interfaceName);
93  if (ie == nullptr)
94  throw cRuntimeError("Interface \"%s\" does not exist", interfaceName);
95  }
96  else {
97  // there should be exactly one non-loopback interface that we want to serve DHCP requests on
98  for (int i = 0; i < ift->getNumInterfaces(); i++) {
99  NetworkInterface *current = ift->getInterface(i);
100  if (!current->isLoopback()) {
101  if (ie)
102  throw cRuntimeError("Multiple non-loopback interfaces found, please select explicitly which one you want to serve DHCP requests on");
103  ie = current;
104  }
105  }
106  if (!ie)
107  throw cRuntimeError("No non-loopback interface found to be configured via DHCP");
108  }
109 
110  return ie;
111 }

Referenced by handleStartOperation().

◆ getAvailableLease()

DhcpLease * inet::DhcpServer::getAvailableLease ( Ipv4Address  requestedAddress,
const MacAddress clientMAC 
)
protectedvirtual
498 {
499  int beginAddr = ipAddressStart.getInt(); // the first address that we might use
500 
501  // try to allocate the requested address if that address is valid and not already allocated
502  if (!requestedAddress.isUnspecified()) { // valid
503  if (containsKey(leased, requestedAddress) && !leased[requestedAddress].leased) // not already leased (allocated)
504  return &leased[requestedAddress];
505 
506  // lease does not exist, create it
507  leased[requestedAddress] = DhcpLease();
508  leased[requestedAddress].ip = requestedAddress;
509  leased[requestedAddress].gateway = gateway;
510  leased[requestedAddress].subnetMask = subnetMask;
511 
512  return &leased[requestedAddress];
513  }
514 
515  // allocate new address from server's pool of available addresses
516  for (unsigned int i = 0; i < maxNumOfClients; i++) {
517  Ipv4Address ip(beginAddr + i);
518  if (containsKey(leased, ip)) {
519  // lease exists but not allocated (e.g. expired or released)
520  if (!leased[ip].leased)
521  return &(leased[ip]);
522  }
523  else {
524  // there is no expired lease so we create a new one
525  leased[ip] = DhcpLease();
526  leased[ip].ip = ip;
527  leased[ip].gateway = gateway;
528  leased[ip].subnetMask = subnetMask;
529  return &(leased[ip]);
530  }
531  }
532  // no lease available
533  return nullptr;
534 }

Referenced by processDhcpMessage().

◆ getLeaseByMac()

DhcpLease * inet::DhcpServer::getLeaseByMac ( MacAddress  mac)
protectedvirtual
483 {
484  for (auto& elem : leased) {
485  // lease exist
486  if (elem.second.mac == mac) {
487  EV_DETAIL << "Found lease for MAC " << mac << "." << endl;
488  return &(elem.second);
489  }
490  }
491  EV_DETAIL << "Lease not found for MAC " << mac << "." << endl;
492 
493  // lease does not exist
494  return nullptr;
495 }

Referenced by processDhcpMessage().

◆ handleCrashOperation()

void inet::DhcpServer::handleCrashOperation ( LifecycleOperation operation)
overrideprotectedvirtual

Implements inet::OperationalMixin< cSimpleModule >.

575 {
576  leased.clear();
577  ie = nullptr;
578  cancelEvent(startTimer);
579  if (operation->getRootModule() != getContainingNode(this)) // closes socket when the application crashed only
580  socket.destroy(); // TODO in real operating systems, program crash detected by OS and OS closes sockets of crashed programs.
581 }

◆ handleMessageWhenUp()

void inet::DhcpServer::handleMessageWhenUp ( cMessage *  msg)
overrideprotectedvirtual

Implements inet::OperationalMixin< cSimpleModule >.

114 {
115  if (msg->isSelfMessage()) {
116  handleSelfMessages(msg);
117  }
118  else if (msg->arrivedOn("socketIn")) {
119  socket.processMessage(msg);
120  }
121  else
122  throw cRuntimeError("Unknown incoming gate: '%s'", msg->getArrivalGate()->getFullName());
123 }

◆ handleSelfMessages()

void inet::DhcpServer::handleSelfMessages ( cMessage *  msg)
protectedvirtual
144 {
145  if (msg->getKind() == START_DHCP) {
146  openSocket();
147  }
148  else
149  throw cRuntimeError("Unknown selfmessage type!");
150 }

Referenced by handleMessageWhenUp().

◆ handleStartOperation()

void inet::DhcpServer::handleStartOperation ( LifecycleOperation operation)
overrideprotectedvirtual

Implements inet::OperationalMixin< cSimpleModule >.

545 {
546  maxNumOfClients = par("maxNumClients");
547  leaseTime = par("leaseTime");
548 
549  simtime_t start = std::max(startTime, simTime());
550  ie = chooseInterface();
551  auto ipv4data = ie->getProtocolData<Ipv4InterfaceData>();
552  const char *gatewayStr = par("gateway");
553  gateway = *gatewayStr ? L3AddressResolver().resolve(gatewayStr, L3AddressResolver::ADDR_IPv4).toIpv4() : ipv4data->getIPAddress();
554  subnetMask = ipv4data->getNetmask();
555  long numReservedAddresses = par("numReservedAddresses");
556  uint32_t networkStartAddress = ipv4data->getIPAddress().getInt() & ipv4data->getNetmask().getInt();
557  ipAddressStart = Ipv4Address(networkStartAddress + numReservedAddresses);
558  if (!Ipv4Address::maskedAddrAreEqual(ipv4data->getIPAddress(), ipAddressStart, subnetMask))
559  throw cRuntimeError("The numReservedAddresses parameter larger than address range");
560  if (!Ipv4Address::maskedAddrAreEqual(ipv4data->getIPAddress(), Ipv4Address(ipAddressStart.getInt() + maxNumOfClients - 1), subnetMask))
561  throw cRuntimeError("Not enough IP addresses in subnet for %d clients", maxNumOfClients);
562  scheduleAt(start, startTimer);
563 }

◆ handleStopOperation()

void inet::DhcpServer::handleStopOperation ( LifecycleOperation operation)
overrideprotectedvirtual

Implements inet::OperationalMixin< cSimpleModule >.

566 {
567  leased.clear();
568  ie = nullptr;
569  cancelEvent(startTimer);
570  socket.close();
571  delayActiveOperationFinish(par("stopOperationTimeout"));
572 }

◆ initialize()

void inet::DhcpServer::initialize ( int  stage)
overrideprotectedvirtual

Reimplemented from inet::OperationalMixin< cSimpleModule >.

37 {
39 
40  if (stage == INITSTAGE_LOCAL) {
41  startTimer = new cMessage("Start DHCP server", START_DHCP);
42  startTime = par("startTime");
43  numSent = 0;
44  numReceived = 0;
45  WATCH(numSent);
46  WATCH(numReceived);
47  WATCH_MAP(leased);
48 
49  // DHCP UDP ports
50  clientPort = 68; // client
51  serverPort = 67; // server
52  }
53  else if (stage == INITSTAGE_APPLICATION_LAYER) {
54  cModule *host = getContainingNode(this);
55  host->subscribe(interfaceDeletedSignal, this);
56  socket.setOutputGate(gate("socketOut"));
57  socket.setCallback(this);
58  }
59 }

◆ numInitStages()

virtual int inet::DhcpServer::numInitStages ( ) const
inlineoverrideprotectedvirtual
53 { return NUM_INIT_STAGES; }

◆ openSocket()

void inet::DhcpServer::openSocket ( )
protectedvirtual
62 {
63  if (!ie)
64  throw cRuntimeError("Interface to listen does not exist. aborting");
66  socket.setBroadcast(true);
67  EV_INFO << "DHCP server bound to port " << serverPort << endl;
68 }

Referenced by handleSelfMessages().

◆ processDhcpMessage()

void inet::DhcpServer::processDhcpMessage ( Packet packet)
protectedvirtual
153 {
154  ASSERT(isUp() && ie != nullptr);
155 
156  const auto& dhcpMsg = packet->peekAtFront<DhcpMessage>();
157 
158  // check that the packet arrived on the interface we are supposed to serve
159  int inputInterfaceId = packet->getTag<InterfaceInd>()->getInterfaceId();
160  if (inputInterfaceId != ie->getInterfaceId()) {
161  EV_WARN << "DHCP message arrived on a different interface, dropping\n";
162  delete packet;
163  return;
164  }
165 
166  // check the OP code
167  if (dhcpMsg->getOp() == BOOTREQUEST) {
168  int messageType = dhcpMsg->getOptions().getMessageType();
169 
170  if (messageType == DHCPDISCOVER) { // RFC 2131, 4.3.1
171  EV_INFO << "DHCPDISCOVER arrived. Handling it." << endl;
172 
173  DhcpLease *lease = getLeaseByMac(dhcpMsg->getChaddr());
174  if (!lease) {
175  // MAC not registered, create offering a new lease to the client
176  lease = getAvailableLease(dhcpMsg->getOptions().getRequestedIp(), dhcpMsg->getChaddr());
177  if (lease != nullptr) {
178 // std::cout << "MAC: " << packet->getChaddr() << " ----> IP: " << lease->ip << endl;
179  lease->mac = dhcpMsg->getChaddr();
180  lease->xid = dhcpMsg->getXid();
181 // lease->parameterRequestList = packet->getOptions().get(PARAM_LIST); TODO !!
182  lease->leased = true; // TODO
183  sendOffer(lease, dhcpMsg);
184  }
185  else
186  EV_ERROR << "No lease available. Ignoring discover." << endl;
187  }
188  else {
189  // MAC already exist, offering the same lease
190  lease->xid = dhcpMsg->getXid();
191 // lease->parameterRequestList = packet->getOptions().get(PARAM_LIST); // TODO !!
192  sendOffer(lease, dhcpMsg);
193  }
194  }
195  else if (messageType == DHCPREQUEST) { // RFC 2131, 4.3.2
196  EV_INFO << "DHCPREQUEST arrived. Handling it." << endl;
197 
198  // check if the request was in response of an offering
199  if (dhcpMsg->getOptions().getServerIdentifier() == ie->getProtocolData<Ipv4InterfaceData>()->getIPAddress()) {
200  // the REQUEST is in response to an offering (because SERVER_ID is filled)
201  // otherwise the msg is a request to extend an existing lease (e. g. INIT-REBOOT)
202 
203  DhcpLease *lease = getLeaseByMac(dhcpMsg->getChaddr());
204  if (lease != nullptr) {
205  if (lease->ip != dhcpMsg->getOptions().getRequestedIp()) {
206  EV_ERROR << "The 'requested IP address' must be filled in with the 'yiaddr' value from the chosen DHCPOFFER." << endl;
207  sendNak(dhcpMsg);
208  }
209  else {
210  EV_INFO << "From now " << lease->ip << " is leased to " << lease->mac << "." << endl;
211  lease->xid = dhcpMsg->getXid();
212  lease->leaseTime = leaseTime;
213  lease->leased = true;
214 
215  // TODO final check before ACK (it is not necessary but recommended)
216  sendAck(lease, dhcpMsg);
217 
218  // TODO update the display string to inform how many clients are assigned
219  }
220  }
221  else {
222  EV_ERROR << "There is no available lease for " << dhcpMsg->getChaddr() << ". Probably, the client missed to send DHCPDISCOVER before DHCPREQUEST." << endl;
223  sendNak(dhcpMsg);
224  }
225  }
226  else {
227  if (dhcpMsg->getCiaddr().isUnspecified()) { // init-reboot
228 // std::cout << "init-reboot" << endl;
229  Ipv4Address requestedAddress = dhcpMsg->getOptions().getRequestedIp();
230  auto it = leased.find(requestedAddress);
231  if (it == leased.end()) {
232  // if DHCP server has no record of the requested IP, then it must remain silent
233  // and may output a warning to the network admin
234  EV_WARN << "DHCP server has no record of IP " << requestedAddress << "." << endl;
235  }
236  else if (Ipv4Address::maskedAddrAreEqual(requestedAddress, it->second.ip, subnetMask)) { // on the same network
237  DhcpLease *lease = &it->second;
238  EV_INFO << "Initialization with known IP address (INIT-REBOOT) " << lease->ip << " on " << lease->mac << " was successful." << endl;
239  lease->xid = dhcpMsg->getXid();
240  lease->leaseTime = leaseTime;
241  lease->leased = true;
242 
243  // TODO final check before ACK (it is not necessary but recommended)
244  sendAck(lease, dhcpMsg);
245  }
246  else {
247  EV_ERROR << "The requested IP address is incorrect, or is on the wrong network." << endl;
248  sendNak(dhcpMsg);
249  }
250  }
251  else { // renewing or rebinding: in this case ciaddr must be filled in with client's IP address
252  auto it = leased.find(dhcpMsg->getCiaddr());
253  if (it != leased.end()) {
254  DhcpLease *lease = &it->second;
255  EV_INFO << "Request for renewal/rebinding IP " << lease->ip << " to " << lease->mac << "." << endl;
256  lease->xid = dhcpMsg->getXid();
257  lease->leaseTime = leaseTime;
258  lease->leased = true;
259 
260  // unicast ACK to ciaddr
261  sendAck(lease, dhcpMsg);
262  }
263  else {
264  EV_ERROR << "Renewal/rebinding process failed: requested IP address " << dhcpMsg->getCiaddr() << " not found in the server's database!" << endl;
265  sendNak(dhcpMsg);
266  }
267  }
268  }
269  }
270  else
271  EV_WARN << "BOOTREQUEST arrived, but DHCP message type is unknown. Dropping it." << endl;
272  }
273  else {
274  EV_WARN << "Message opcode is unknown. This DHCP server only handles BOOTREQUEST messages. Dropping it." << endl;
275  }
276 
277  EV_DEBUG << "Deleting " << packet << "." << endl;
278  delete packet;
279 
280  numReceived++;
281 }

Referenced by socketDataArrived().

◆ receiveSignal()

void inet::DhcpServer::receiveSignal ( cComponent *  source,
simsignal_t  signalID,
cObject *  obj,
cObject *  details 
)
overrideprotectedvirtual
71 {
72  Enter_Method("%s", cComponent::getSignalName(signalID));
73 
74  if (signalID == interfaceDeletedSignal) {
75  if (isUp()) {
76  NetworkInterface *nie = check_and_cast<NetworkInterface *>(obj);
77  if (ie == nie)
78  throw cRuntimeError("Reacting to interface deletions is not implemented in this module");
79  }
80  }
81  else
82  throw cRuntimeError("Unexpected signal: %s", getSignalName(signalID));
83 }

◆ sendAck()

void inet::DhcpServer::sendAck ( DhcpLease lease,
const Ptr< const DhcpMessage > &  dhcpMsg 
)
protectedvirtual
321 {
322  EV_INFO << "Sending the ACK to " << lease->mac << "." << endl;
323 
324  Packet *pk = new Packet("DHCPACK");
325  const auto& ack = makeShared<DhcpMessage>();
326  ack->setOp(BOOTREPLY);
327  uint16_t length = 236; // packet size without the options field
328  ack->setHtype(1); // ethernet
329  ack->setHlen(6); // hardware address length (6 octets)
330  ack->setHops(0);
331  ack->setXid(lease->xid); // transaction id;
332  ack->setSecs(0); // 0 seconds from transaction started
333  ack->setBroadcast(false);
334  ack->setCiaddr(lease->ip); // client IP addr.
335  ack->setYiaddr(lease->ip); // client IP addr.
336 
337  ack->setChaddr(lease->mac); // client MAC address
338  ack->setSname(""); // no server name given
339  ack->setFile(""); // no file given
340  ack->getOptionsForUpdate().setMessageType(DHCPACK);
341  length += 3;
342 
343  // add the lease options
344  ack->getOptionsForUpdate().setSubnetMask(lease->subnetMask);
345  length += 6;
346  ack->getOptionsForUpdate().setRenewalTime(SimTime(leaseTime * 0.5).trunc(SIMTIME_S)); // RFC 4.4.5
347  length += 6;
348  ack->getOptionsForUpdate().setRebindingTime(SimTime(leaseTime * 0.875).trunc(SIMTIME_S));
349  length += 6;
350  ack->getOptionsForUpdate().setLeaseTime(SimTime(leaseTime).trunc(SIMTIME_S));
351  length += 6;
352  ack->getOptionsForUpdate().setRouterArraySize(1);
353  ack->getOptionsForUpdate().setRouter(0, lease->gateway);
354  length += (2 + 1 * sizeof(uint32_t));
355  ack->getOptionsForUpdate().setDnsArraySize(1);
356  ack->getOptionsForUpdate().setDns(0, lease->dns);
357  length += (2 + 1 * sizeof(uint32_t));
358 
359  // add the server ID as the RFC says
360  ack->getOptionsForUpdate().setServerIdentifier(ie->getProtocolData<Ipv4InterfaceData>()->getIPAddress());
361  length += 6;
362 
363  // magic cookie and the end field
364  length += 5;
365 
366  ack->setChunkLength(B(length));
367 
368  pk->insertAtBack(ack);
369 
370  // register the lease time
371  lease->leaseTime = simTime();
372 
373  /* RFC 2131, 4.1
374  * If the 'giaddr' field in a DHCP message from a client is non-zero,
375  * the server sends any return messages to the 'DHCP server' port on the
376  * BOOTP relay agent whose address appears in 'giaddr'. If the 'giaddr'
377  * field is zero and the 'ciaddr' field is nonzero, then the server
378  * unicasts DHCPOFFER and DHCPACK messages to the address in 'ciaddr'.
379  * If 'giaddr' is zero and 'ciaddr' is zero, and the broadcast bit is
380  * set, then the server broadcasts DHCPOFFER and DHCPACK messages to
381  * 0xffffffff. If the broadcast bit is not set and 'giaddr' is zero and
382  * 'ciaddr' is zero, then the server unicasts DHCPOFFER and DHCPACK
383  * messages to the client's hardware address and 'yiaddr' address.
384  */
385  Ipv4Address destAddr;
386  if (!packet->getGiaddr().isUnspecified())
387  destAddr = packet->getGiaddr();
388  else if (!packet->getCiaddr().isUnspecified())
389  destAddr = packet->getCiaddr();
390  else if (packet->getBroadcast())
391  destAddr = Ipv4Address::ALLONES_ADDRESS;
392  else {
393  // TODO should send it to client's hardware address and yiaddr address, but the application can not set the destination MacAddress.
394 // destAddr = lease->ip;
395  destAddr = Ipv4Address::ALLONES_ADDRESS;
396  }
397 
398  sendToUDP(pk, serverPort, destAddr, clientPort);
399 }

Referenced by processDhcpMessage().

◆ sendNak()

void inet::DhcpServer::sendNak ( const Ptr< const DhcpMessage > &  dhcpMsg)
protectedvirtual
284 {
285 // EV_INFO << "Sending NAK to " << lease->mac << "." << endl;
286  Packet *pk = new Packet("DHCPNAK");
287  const auto& nak = makeShared<DhcpMessage>();
288  nak->setOp(BOOTREPLY);
289  uint16_t length = 236; // packet size without the options field
290  nak->setHtype(1); // ethernet
291  nak->setHlen(6); // hardware address length (6 octets)
292  nak->setHops(0);
293  nak->setXid(msg->getXid()); // transaction id from client
294  nak->setSecs(0); // 0 seconds from transaction started.
295  nak->setBroadcast(msg->getBroadcast());
296  nak->setGiaddr(msg->getGiaddr()); // next server IP
297  nak->setChaddr(msg->getChaddr());
298  nak->getOptionsForUpdate().setServerIdentifier(ie->getProtocolData<Ipv4InterfaceData>()->getIPAddress());
299  length += 6;
300  nak->getOptionsForUpdate().setMessageType(DHCPNAK);
301  length += 3;
302 
303  // magic cookie and the end field
304  length += 5;
305 
306  nak->setChunkLength(B(length));
307 
308  pk->insertAtBack(nak);
309  /* RFC 2131, 4.1
310  *
311  * In all cases, when 'giaddr' is zero, the server broadcasts any DHCPNAK
312  * messages to 0xffffffff.
313  */
314  Ipv4Address destAddr = Ipv4Address::ALLONES_ADDRESS;
315  if (!msg->getGiaddr().isUnspecified())
316  destAddr = msg->getGiaddr();
317  sendToUDP(pk, serverPort, destAddr, clientPort);
318 }

Referenced by processDhcpMessage().

◆ sendOffer()

void inet::DhcpServer::sendOffer ( DhcpLease lease,
const Ptr< const DhcpMessage > &  dhcpMsg 
)
protectedvirtual
402 {
403  EV_INFO << "Offering " << *lease << endl;
404 
405  Packet *pk = new Packet("DHCPOFFER");
406  const auto& offer = makeShared<DhcpMessage>();
407  offer->setOp(BOOTREPLY);
408  uint16_t length = 236; // packet size without the options field
409  offer->setHtype(1); // ethernet
410  offer->setHlen(6); // hardware address lenght (6 octets)
411  offer->setHops(0);
412  offer->setXid(lease->xid); // transaction id
413  offer->setSecs(0); // 0 seconds from transaction started
414  offer->setBroadcast(false); // unicast
415 
416  offer->setYiaddr(lease->ip); // ip offered.
417  offer->setGiaddr(lease->gateway); // next server ip
418 
419  offer->setChaddr(lease->mac); // client mac address
420  offer->setSname(""); // no server name given
421  offer->setFile(""); // no file given
422  offer->getOptionsForUpdate().setMessageType(DHCPOFFER);
423  length += 3;
424 
425  // add the offer options
426  offer->getOptionsForUpdate().setSubnetMask(lease->subnetMask);
427  length += 6;
428  offer->getOptionsForUpdate().setRenewalTime(SimTime(leaseTime * 0.5).trunc(SIMTIME_S)); // RFC 4.4.5
429  length += 6;
430  offer->getOptionsForUpdate().setRebindingTime(SimTime(leaseTime * 0.875).trunc(SIMTIME_S));
431  length += 6;
432  offer->getOptionsForUpdate().setLeaseTime(SimTime(leaseTime).trunc(SIMTIME_S));
433  length += 6;
434  offer->getOptionsForUpdate().setRouterArraySize(1);
435  offer->getOptionsForUpdate().setRouter(0, lease->gateway);
436  length += (2 + 1 * sizeof(uint32_t));
437  offer->getOptionsForUpdate().setDnsArraySize(1);
438  offer->getOptionsForUpdate().setDns(0, lease->dns);
439  length += (2 + 1 * sizeof(uint32_t));
440 
441  // add the server_id as the RFC says
442  offer->getOptionsForUpdate().setServerIdentifier(ie->getProtocolData<Ipv4InterfaceData>()->getIPAddress());
443  length += 6;
444 
445  // magic cookie and the end field
446  length += 5;
447 
448  offer->setChunkLength(B(length));
449 
450  // register the offering time // todo: ?
451  lease->leaseTime = simTime();
452  pk->insertAtBack(offer);
453 
454  /* RFC 2131, 4.1
455  * If the 'giaddr' field in a DHCP message from a client is non-zero,
456  * the server sends any return messages to the 'DHCP server' port on the
457  * BOOTP relay agent whose address appears in 'giaddr'. If the 'giaddr'
458  * field is zero and the 'ciaddr' field is nonzero, then the server
459  * unicasts DHCPOFFER and DHCPACK messages to the address in 'ciaddr'.
460  * If 'giaddr' is zero and 'ciaddr' is zero, and the broadcast bit is
461  * set, then the server broadcasts DHCPOFFER and DHCPACK messages to
462  * 0xffffffff. If the broadcast bit is not set and 'giaddr' is zero and
463  * 'ciaddr' is zero, then the server unicasts DHCPOFFER and DHCPACK
464  * messages to the client's hardware address and 'yiaddr' address.
465  */
466  Ipv4Address destAddr;
467  if (!packet->getGiaddr().isUnspecified())
468  destAddr = packet->getGiaddr();
469  else if (!packet->getCiaddr().isUnspecified())
470  destAddr = packet->getCiaddr();
471  else if (packet->getBroadcast())
472  destAddr = Ipv4Address::ALLONES_ADDRESS;
473  else {
474  // TODO should send it to client's hardware address and yiaddr address, but the application can not set the destination MacAddress.
475 // destAddr = lease->ip;
476  destAddr = Ipv4Address::ALLONES_ADDRESS;
477  }
478 
479  sendToUDP(pk, serverPort, destAddr, clientPort);
480 }

Referenced by processDhcpMessage().

◆ sendToUDP()

void inet::DhcpServer::sendToUDP ( Packet msg,
int  srcPort,
const L3Address destAddr,
int  destPort 
)
protectedvirtual
537 {
538  EV_INFO << "Sending packet: " << msg << "." << endl;
539  numSent++;
540  msg->addTagIfAbsent<InterfaceReq>()->setInterfaceId(ie->getInterfaceId());
541  socket.sendTo(msg, destAddr, destPort);
542 }

Referenced by sendAck(), sendNak(), and sendOffer().

◆ socketClosed()

void inet::DhcpServer::socketClosed ( UdpSocket socket)
overrideprotectedvirtual

Notifies about socket closed, indication ownership is transferred to the callee.

Implements inet::UdpSocket::ICallback.

138 {
139  if (operationalState == State::STOPPING_OPERATION && !socket.isOpen())
140  startActiveOperationExtraTimeOrFinish(par("stopOperationExtraTime"));
141 }

◆ socketDataArrived()

void inet::DhcpServer::socketDataArrived ( UdpSocket socket,
Packet packet 
)
overrideprotectedvirtual

Notifies about data arrival, packet ownership is transferred to the callee.

Implements inet::UdpSocket::ICallback.

126 {
127  // process incoming packet
128  processDhcpMessage(packet);
129 }

◆ socketErrorArrived()

void inet::DhcpServer::socketErrorArrived ( UdpSocket socket,
Indication indication 
)
overrideprotectedvirtual

Notifies about error indication arrival, indication ownership is transferred to the callee.

Implements inet::UdpSocket::ICallback.

132 {
133  EV_WARN << "Unknown message '" << indication->getName() << "', kind = " << indication->getKind() << ", discarding it." << endl;
134  delete indication;
135 }

Member Data Documentation

◆ clientPort

int inet::DhcpServer::clientPort = -1
protected

◆ gateway

Ipv4Address inet::DhcpServer::gateway
protected

◆ ie

◆ ipAddressStart

Ipv4Address inet::DhcpServer::ipAddressStart
protected

◆ leased

◆ leaseTime

unsigned int inet::DhcpServer::leaseTime = 0
protected

◆ maxNumOfClients

unsigned int inet::DhcpServer::maxNumOfClients = 0
protected

◆ numReceived

int inet::DhcpServer::numReceived = 0
protected

Referenced by initialize(), and processDhcpMessage().

◆ numSent

int inet::DhcpServer::numSent = 0
protected

Referenced by initialize(), and sendToUDP().

◆ serverPort

int inet::DhcpServer::serverPort = -1
protected

◆ socket

◆ startTime

simtime_t inet::DhcpServer::startTime
protected

Referenced by handleStartOperation(), and initialize().

◆ startTimer

cMessage* inet::DhcpServer::startTimer = nullptr
protected

◆ subnetMask

Ipv4Address inet::DhcpServer::subnetMask
protected

The documentation for this class was generated from the following files:
inet::UdpSocket::setOutputGate
void setOutputGate(cGate *toUdp)
Sets the gate on which to send to UDP.
Definition: UdpSocket.h:117
inet::DhcpServer::sendToUDP
virtual void sendToUDP(Packet *msg, int srcPort, const L3Address &destAddr, int destPort)
Definition: DhcpServer.cc:536
inet::Ipv4Address::getInt
uint32_t getInt() const
Returns the address as an uint32_t in host byte order (e.g.
Definition: Ipv4Address.h:186
inet::OperationalMixin< cSimpleModule >::operationalState
State operationalState
Definition: OperationalMixin.h:23
inet::OperationalMixin< cSimpleModule >::isUp
virtual bool isUp() const
utility functions
Definition: OperationalMixin.h:66
inet::DhcpServer::START_DHCP
@ START_DHCP
Definition: DhcpServer.h:31
inet::UdpSocket::bind
void bind(int localPort)
Bind the socket to a local port number.
Definition: UdpSocket.cc:34
inet::UdpSocket::sendTo
void sendTo(Packet *msg, L3Address destAddr, int destPort)
Sends a data packet to the given address and port.
Definition: UdpSocket.cc:69
inet::DHCPACK
@ DHCPACK
Definition: DhcpMessage_m.h:88
inet::DhcpServer::sendAck
virtual void sendAck(DhcpLease *lease, const Ptr< const DhcpMessage > &dhcpMsg)
Definition: DhcpServer.cc:320
inet::DhcpServer::sendOffer
virtual void sendOffer(DhcpLease *lease, const Ptr< const DhcpMessage > &dhcpMsg)
Definition: DhcpServer.cc:401
inet::getContainingNode
cModule * getContainingNode(const cModule *from)
Find the node containing the given module.
Definition: ModuleAccess.cc:40
inet::OperationalMixin< cSimpleModule >::initialize
virtual void initialize(int stage) override
Definition: OperationalMixinImpl.h:26
inet::DhcpServer::maxNumOfClients
unsigned int maxNumOfClients
Definition: DhcpServer.h:41
InterfaceReq
removed InterfaceReq
Definition: IUdp-gates.txt:11
inet::UdpSocket::destroy
virtual void destroy() override
Notify the protocol that the owner of ISocket has destroyed the socket.
Definition: UdpSocket.cc:98
inet::NetworkInterface::getProtocolData
const InterfaceProtocolData * getProtocolData(int index) const
Returns the protocol data at the given index.
Definition: NetworkInterface.h:287
inet::DHCPDISCOVER
@ DHCPDISCOVER
Definition: DhcpMessage_m.h:84
inet::DhcpServer::startTime
simtime_t startTime
Definition: DhcpServer.h:49
inet::DhcpServer::serverPort
int serverPort
Definition: DhcpServer.h:37
inet::UdpSocket::setCallback
void setCallback(ICallback *cb)
Sets a callback object, to be used with processMessage().
Definition: UdpSocket.cc:338
inet::DHCPOFFER
@ DHCPOFFER
Definition: DhcpMessage_m.h:85
inet::DhcpServer::getLeaseByMac
virtual DhcpLease * getLeaseByMac(MacAddress mac)
Definition: DhcpServer.cc:482
inet::Ipv4Address::ALLONES_ADDRESS
static const Ipv4Address ALLONES_ADDRESS
255.255.255.255
Definition: Ipv4Address.h:94
inet::interfaceDeletedSignal
simsignal_t interfaceDeletedSignal
Definition: Simsignals.cc:31
inet::units::units::B
intscale< b, 1, 8 > B
Definition: Units.h:1168
inet::NetworkInterface::getInterfaceId
int getInterfaceId() const
Definition: NetworkInterface.h:232
inet::DhcpServer::numSent
int numSent
Definition: DhcpServer.h:35
inet::UdpSocket::processMessage
virtual void processMessage(cMessage *msg) override
Examines the message, takes ownership, and updates socket state.
Definition: UdpSocket.cc:343
inet::Ipv4Address::maskedAddrAreEqual
static bool maskedAddrAreEqual(const Ipv4Address &addr1, const Ipv4Address &addr2, const Ipv4Address &netmask)
Test if the masked addresses (ie the mask is applied to addr1 and addr2) are equal.
Definition: Ipv4Address.cc:249
inet::DhcpServer::ipAddressStart
Ipv4Address ipAddressStart
Definition: DhcpServer.h:45
inet::DhcpServer::ie
NetworkInterface * ie
Definition: DhcpServer.h:47
inet::DHCPNAK
@ DHCPNAK
Definition: DhcpMessage_m.h:89
inet::INITSTAGE_LOCAL
INET_API InitStage INITSTAGE_LOCAL
Initialization of local state that don't use or affect other modules includes:
inet::UdpSocket::close
virtual void close() override
Unbinds the socket.
Definition: UdpSocket.cc:87
NUM_INIT_STAGES
#define NUM_INIT_STAGES
Definition: InitStageRegistry.h:73
inet::DhcpServer::getAvailableLease
virtual DhcpLease * getAvailableLease(Ipv4Address requestedAddress, const MacAddress &clientMAC)
Definition: DhcpServer.cc:497
inet::sctp::max
double max(const double a, const double b)
Returns the maximum of a and b.
Definition: SctpAssociation.h:266
inet::DhcpServer::socket
UdpSocket socket
Definition: DhcpServer.h:48
inet::DhcpServer::leased
DhcpLeased leased
Definition: DhcpServer.h:33
inet::UdpSocket::isOpen
virtual bool isOpen() const override
Definition: UdpSocket.h:293
inet::UdpSocket::setBroadcast
void setBroadcast(bool broadcast)
Set the Broadcast option on the UDP socket.
Definition: UdpSocket.cc:139
inet::DhcpServer::gateway
Ipv4Address gateway
Definition: DhcpServer.h:44
inet::INITSTAGE_APPLICATION_LAYER
INET_API InitStage INITSTAGE_APPLICATION_LAYER
Initialization of applications.
inet::OperationalMixin< cSimpleModule >::delayActiveOperationFinish
virtual void delayActiveOperationFinish(simtime_t timeout)
Definition: OperationalMixinImpl.h:161
inet::DhcpServer::subnetMask
Ipv4Address subnetMask
Definition: DhcpServer.h:43
inet::DhcpServer::openSocket
virtual void openSocket()
Definition: DhcpServer.cc:61
inet::OperationalMixin< cSimpleModule >::startActiveOperationExtraTimeOrFinish
virtual void startActiveOperationExtraTimeOrFinish(simtime_t extraTime)
Definition: OperationalMixinImpl.h:179
inet::DhcpServer::chooseInterface
virtual NetworkInterface * chooseInterface()
Definition: DhcpServer.cc:85
Enter_Method
#define Enter_Method(...)
Definition: SelfDoc.h:71
inet::DHCPREQUEST
@ DHCPREQUEST
Definition: DhcpMessage_m.h:86
inet::DhcpServer::sendNak
virtual void sendNak(const Ptr< const DhcpMessage > &dhcpMsg)
Definition: DhcpServer.cc:283
inet::BOOTREQUEST
@ BOOTREQUEST
Definition: DhcpMessage_m.h:60
inet::DhcpServer::numReceived
int numReceived
Definition: DhcpServer.h:36
inet::L3AddressResolver::ADDR_IPv4
@ ADDR_IPv4
Definition: L3AddressResolver.h:70
inet::BOOTREPLY
@ BOOTREPLY
Definition: DhcpMessage_m.h:61
inet::DhcpServer::processDhcpMessage
virtual void processDhcpMessage(Packet *packet)
Definition: DhcpServer.cc:152
inet::containsKey
bool containsKey(const std::map< K, V, _C > &m, const Tk &a)
Definition: stlutils.h:80
inet::DhcpServer::startTimer
cMessage * startTimer
Definition: DhcpServer.h:50
inet::DhcpServer::leaseTime
unsigned int leaseTime
Definition: DhcpServer.h:42
inet::DhcpServer::handleSelfMessages
virtual void handleSelfMessages(cMessage *msg)
Definition: DhcpServer.cc:143
inet::DhcpServer::clientPort
int clientPort
Definition: DhcpServer.h:38