• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2016, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file implements DHCPv6 Server.
32  */
33 
34 #include "dhcp6_server.hpp"
35 
36 #if OPENTHREAD_CONFIG_DHCP6_SERVER_ENABLE
37 
38 #include "common/array.hpp"
39 #include "common/as_core_type.hpp"
40 #include "common/code_utils.hpp"
41 #include "common/encoding.hpp"
42 #include "common/instance.hpp"
43 #include "common/locator_getters.hpp"
44 #include "common/log.hpp"
45 #include "thread/mle.hpp"
46 #include "thread/thread_netif.hpp"
47 
48 namespace ot {
49 namespace Dhcp6 {
50 
51 RegisterLogModule("Dhcp6Server");
52 
Server(Instance & aInstance)53 Server::Server(Instance &aInstance)
54     : InstanceLocator(aInstance)
55     , mSocket(aInstance)
56     , mPrefixAgentsCount(0)
57     , mPrefixAgentsMask(0)
58 {
59     memset(mPrefixAgents, 0, sizeof(mPrefixAgents));
60 }
61 
UpdateService(void)62 Error Server::UpdateService(void)
63 {
64     Error                           error  = kErrorNone;
65     uint16_t                        rloc16 = Get<Mle::MleRouter>().GetRloc16();
66     NetworkData::Iterator           iterator;
67     NetworkData::OnMeshPrefixConfig config;
68     Lowpan::Context                 lowpanContext;
69 
70     // remove dhcp agent aloc and prefix delegation
71     for (PrefixAgent &prefixAgent : mPrefixAgents)
72     {
73         bool found = false;
74 
75         if (!prefixAgent.IsValid())
76         {
77             continue;
78         }
79 
80         iterator = NetworkData::kIteratorInit;
81 
82         while (Get<NetworkData::Leader>().GetNextOnMeshPrefix(iterator, rloc16, config) == kErrorNone)
83         {
84             if (!(config.mDhcp || config.mConfigure))
85             {
86                 continue;
87             }
88 
89             error = Get<NetworkData::Leader>().GetContext(prefixAgent.GetPrefixAsAddress(), lowpanContext);
90 
91             if ((error == kErrorNone) && (prefixAgent.GetContextId() == lowpanContext.mContextId))
92             {
93                 // still in network data
94                 found = true;
95                 break;
96             }
97         }
98 
99         if (!found)
100         {
101             Get<ThreadNetif>().RemoveUnicastAddress(prefixAgent.GetAloc());
102             prefixAgent.Clear();
103             mPrefixAgentsCount--;
104         }
105     }
106 
107     // add dhcp agent aloc and prefix delegation
108     iterator = NetworkData::kIteratorInit;
109 
110     while (Get<NetworkData::Leader>().GetNextOnMeshPrefix(iterator, rloc16, config) == kErrorNone)
111     {
112         if (!(config.mDhcp || config.mConfigure))
113         {
114             continue;
115         }
116 
117         error = Get<NetworkData::Leader>().GetContext(AsCoreType(&config.mPrefix.mPrefix), lowpanContext);
118 
119         if (error == kErrorNone)
120         {
121             AddPrefixAgent(config.GetPrefix(), lowpanContext);
122         }
123     }
124 
125     if (mPrefixAgentsCount > 0)
126     {
127         Start();
128     }
129     else
130     {
131         Stop();
132     }
133 
134     return error;
135 }
136 
Start(void)137 void Server::Start(void)
138 {
139     VerifyOrExit(!mSocket.IsOpen());
140 
141     IgnoreError(mSocket.Open(&Server::HandleUdpReceive, this));
142     IgnoreError(mSocket.Bind(kDhcpServerPort));
143 
144 exit:
145     return;
146 }
147 
Stop(void)148 void Server::Stop(void)
149 {
150     IgnoreError(mSocket.Close());
151 }
152 
AddPrefixAgent(const Ip6::Prefix & aIp6Prefix,const Lowpan::Context & aContext)153 void Server::AddPrefixAgent(const Ip6::Prefix &aIp6Prefix, const Lowpan::Context &aContext)
154 {
155     Error        error    = kErrorNone;
156     PrefixAgent *newEntry = nullptr;
157 
158     for (PrefixAgent &prefixAgent : mPrefixAgents)
159     {
160         if (!prefixAgent.IsValid())
161         {
162             newEntry = &prefixAgent;
163         }
164         else if (prefixAgent.GetPrefix() == aIp6Prefix)
165         {
166             // already added
167             ExitNow();
168         }
169     }
170 
171     VerifyOrExit(newEntry != nullptr, error = kErrorNoBufs);
172 
173     newEntry->Set(aIp6Prefix, Get<Mle::MleRouter>().GetMeshLocalPrefix(), aContext.mContextId);
174     Get<ThreadNetif>().AddUnicastAddress(newEntry->GetAloc());
175     mPrefixAgentsCount++;
176 
177 exit:
178 
179     if (error != kErrorNone)
180     {
181         LogNote("Failed to add DHCPv6 prefix agent: %s", ErrorToString(error));
182     }
183 }
184 
HandleUdpReceive(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)185 void Server::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
186 {
187     static_cast<Server *>(aContext)->HandleUdpReceive(AsCoreType(aMessage), AsCoreType(aMessageInfo));
188 }
189 
HandleUdpReceive(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)190 void Server::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
191 {
192     Header header;
193 
194     SuccessOrExit(aMessage.Read(aMessage.GetOffset(), header));
195     aMessage.MoveOffset(sizeof(header));
196 
197     // discard if not solicit type
198     VerifyOrExit((header.GetType() == kTypeSolicit));
199 
200     ProcessSolicit(aMessage, aMessageInfo.GetPeerAddr(), header.GetTransactionId());
201 
202 exit:
203     return;
204 }
205 
ProcessSolicit(Message & aMessage,const Ip6::Address & aDst,const TransactionId & aTransactionId)206 void Server::ProcessSolicit(Message &aMessage, const Ip6::Address &aDst, const TransactionId &aTransactionId)
207 {
208     IaNa             iana;
209     ClientIdentifier clientIdentifier;
210     uint16_t         optionOffset;
211     uint16_t         offset = aMessage.GetOffset();
212     uint16_t         length = aMessage.GetLength() - aMessage.GetOffset();
213 
214     // Client Identifier (discard if not present)
215     VerifyOrExit((optionOffset = FindOption(aMessage, offset, length, kOptionClientIdentifier)) > 0);
216     SuccessOrExit(ProcessClientIdentifier(aMessage, optionOffset, clientIdentifier));
217 
218     // Server Identifier (assuming Rapid Commit, discard if present)
219     VerifyOrExit(FindOption(aMessage, offset, length, kOptionServerIdentifier) == 0);
220 
221     // Rapid Commit (assuming Rapid Commit, discard if not present)
222     VerifyOrExit(FindOption(aMessage, offset, length, kOptionRapidCommit) > 0);
223 
224     // Elapsed Time if present
225     if ((optionOffset = FindOption(aMessage, offset, length, kOptionElapsedTime)) > 0)
226     {
227         SuccessOrExit(ProcessElapsedTime(aMessage, optionOffset));
228     }
229 
230     // IA_NA (discard if not present)
231     VerifyOrExit((optionOffset = FindOption(aMessage, offset, length, kOptionIaNa)) > 0);
232     SuccessOrExit(ProcessIaNa(aMessage, optionOffset, iana));
233 
234     SuccessOrExit(SendReply(aDst, aTransactionId, clientIdentifier, iana));
235 
236 exit:
237     return;
238 }
239 
FindOption(Message & aMessage,uint16_t aOffset,uint16_t aLength,Code aCode)240 uint16_t Server::FindOption(Message &aMessage, uint16_t aOffset, uint16_t aLength, Code aCode)
241 {
242     uint16_t end  = aOffset + aLength;
243     uint16_t rval = 0;
244 
245     while (aOffset <= end)
246     {
247         Option option;
248 
249         SuccessOrExit(aMessage.Read(aOffset, option));
250 
251         if (option.GetCode() == aCode)
252         {
253             ExitNow(rval = aOffset);
254         }
255 
256         aOffset += sizeof(option) + option.GetLength();
257     }
258 
259 exit:
260     return rval;
261 }
ProcessClientIdentifier(Message & aMessage,uint16_t aOffset,ClientIdentifier & aClientId)262 Error Server::ProcessClientIdentifier(Message &aMessage, uint16_t aOffset, ClientIdentifier &aClientId)
263 {
264     Error error = kErrorNone;
265 
266     SuccessOrExit(error = aMessage.Read(aOffset, aClientId));
267     VerifyOrExit((aClientId.GetLength() == sizeof(aClientId) - sizeof(Option)) &&
268                      (aClientId.GetDuidType() == kDuidLinkLayerAddress) &&
269                      (aClientId.GetDuidHardwareType() == kHardwareTypeEui64),
270                  error = kErrorParse);
271 exit:
272     return error;
273 }
274 
ProcessElapsedTime(Message & aMessage,uint16_t aOffset)275 Error Server::ProcessElapsedTime(Message &aMessage, uint16_t aOffset)
276 {
277     Error       error = kErrorNone;
278     ElapsedTime option;
279 
280     SuccessOrExit(error = aMessage.Read(aOffset, option));
281     VerifyOrExit(option.GetLength() == sizeof(option) - sizeof(Option), error = kErrorParse);
282 exit:
283     return error;
284 }
285 
ProcessIaNa(Message & aMessage,uint16_t aOffset,IaNa & aIaNa)286 Error Server::ProcessIaNa(Message &aMessage, uint16_t aOffset, IaNa &aIaNa)
287 {
288     Error    error = kErrorNone;
289     uint16_t optionOffset;
290     uint16_t length;
291 
292     SuccessOrExit(error = aMessage.Read(aOffset, aIaNa));
293 
294     aOffset += sizeof(aIaNa);
295     length = aIaNa.GetLength() + sizeof(Option) - sizeof(IaNa);
296 
297     VerifyOrExit(length <= aMessage.GetLength() - aOffset, error = kErrorParse);
298 
299     mPrefixAgentsMask = 0;
300 
301     while (length > 0)
302     {
303         VerifyOrExit((optionOffset = FindOption(aMessage, aOffset, length, kOptionIaAddress)) > 0);
304         SuccessOrExit(error = ProcessIaAddress(aMessage, optionOffset));
305 
306         length -= ((optionOffset - aOffset) + sizeof(IaAddress));
307         aOffset = optionOffset + sizeof(IaAddress);
308     }
309 
310 exit:
311     return error;
312 }
313 
ProcessIaAddress(Message & aMessage,uint16_t aOffset)314 Error Server::ProcessIaAddress(Message &aMessage, uint16_t aOffset)
315 {
316     Error     error = kErrorNone;
317     IaAddress option;
318 
319     SuccessOrExit(error = aMessage.Read(aOffset, option));
320     VerifyOrExit(option.GetLength() == sizeof(option) - sizeof(Option), error = kErrorParse);
321 
322     // mask matching prefix
323     for (uint16_t i = 0; i < GetArrayLength(mPrefixAgents); i++)
324     {
325         if (mPrefixAgents[i].IsValid() && mPrefixAgents[i].IsPrefixMatch(option.GetAddress()))
326         {
327             mPrefixAgentsMask |= (1 << i);
328             break;
329         }
330     }
331 
332 exit:
333     return error;
334 }
335 
SendReply(const Ip6::Address & aDst,const TransactionId & aTransactionId,ClientIdentifier & aClientId,IaNa & aIaNa)336 Error Server::SendReply(const Ip6::Address & aDst,
337                         const TransactionId &aTransactionId,
338                         ClientIdentifier &   aClientId,
339                         IaNa &               aIaNa)
340 {
341     Error            error = kErrorNone;
342     Ip6::MessageInfo messageInfo;
343     Message *        message;
344 
345     VerifyOrExit((message = mSocket.NewMessage(0)) != nullptr, error = kErrorNoBufs);
346     SuccessOrExit(error = AppendHeader(*message, aTransactionId));
347     SuccessOrExit(error = AppendServerIdentifier(*message));
348     SuccessOrExit(error = AppendClientIdentifier(*message, aClientId));
349     SuccessOrExit(error = AppendIaNa(*message, aIaNa));
350     SuccessOrExit(error = AppendStatusCode(*message, kStatusSuccess));
351     SuccessOrExit(error = AppendIaAddress(*message, aClientId));
352     SuccessOrExit(error = AppendRapidCommit(*message));
353 
354     messageInfo.SetPeerAddr(aDst);
355     messageInfo.SetPeerPort(kDhcpClientPort);
356     SuccessOrExit(error = mSocket.SendTo(*message, messageInfo));
357 
358 exit:
359     FreeMessageOnError(message, error);
360     return error;
361 }
362 
AppendHeader(Message & aMessage,const TransactionId & aTransactionId)363 Error Server::AppendHeader(Message &aMessage, const TransactionId &aTransactionId)
364 {
365     Header header;
366 
367     header.Clear();
368     header.SetType(kTypeReply);
369     header.SetTransactionId(aTransactionId);
370     return aMessage.Append(header);
371 }
372 
AppendClientIdentifier(Message & aMessage,ClientIdentifier & aClientId)373 Error Server::AppendClientIdentifier(Message &aMessage, ClientIdentifier &aClientId)
374 {
375     return aMessage.Append(aClientId);
376 }
377 
AppendServerIdentifier(Message & aMessage)378 Error Server::AppendServerIdentifier(Message &aMessage)
379 {
380     Error            error = kErrorNone;
381     ServerIdentifier option;
382     Mac::ExtAddress  eui64;
383 
384     Get<Radio>().GetIeeeEui64(eui64);
385 
386     option.Init();
387     option.SetDuidType(kDuidLinkLayerAddress);
388     option.SetDuidHardwareType(kHardwareTypeEui64);
389     option.SetDuidLinkLayerAddress(eui64);
390     SuccessOrExit(error = aMessage.Append(option));
391 
392 exit:
393     return error;
394 }
395 
AppendIaNa(Message & aMessage,IaNa & aIaNa)396 Error Server::AppendIaNa(Message &aMessage, IaNa &aIaNa)
397 {
398     Error    error  = kErrorNone;
399     uint16_t length = 0;
400 
401     if (mPrefixAgentsMask)
402     {
403         for (uint16_t i = 0; i < GetArrayLength(mPrefixAgents); i++)
404         {
405             if (mPrefixAgentsMask & (1 << i))
406             {
407                 length += sizeof(IaAddress);
408             }
409         }
410     }
411     else
412     {
413         length += sizeof(IaAddress) * mPrefixAgentsCount;
414     }
415 
416     length += sizeof(IaNa) + sizeof(StatusCode) - sizeof(Option);
417 
418     aIaNa.SetLength(length);
419     aIaNa.SetT1(IaNa::kDefaultT1);
420     aIaNa.SetT2(IaNa::kDefaultT2);
421     SuccessOrExit(error = aMessage.Append(aIaNa));
422 
423 exit:
424     return error;
425 }
426 
AppendStatusCode(Message & aMessage,Status aStatusCode)427 Error Server::AppendStatusCode(Message &aMessage, Status aStatusCode)
428 {
429     StatusCode option;
430 
431     option.Init();
432     option.SetStatusCode(aStatusCode);
433     return aMessage.Append(option);
434 }
435 
AppendIaAddress(Message & aMessage,ClientIdentifier & aClientId)436 Error Server::AppendIaAddress(Message &aMessage, ClientIdentifier &aClientId)
437 {
438     Error error = kErrorNone;
439 
440     if (mPrefixAgentsMask)
441     {
442         // if specified, only apply specified prefixes
443         for (uint16_t i = 0; i < GetArrayLength(mPrefixAgents); i++)
444         {
445             if (mPrefixAgentsMask & (1 << i))
446             {
447                 SuccessOrExit(error = AddIaAddress(aMessage, mPrefixAgents[i].GetPrefixAsAddress(), aClientId));
448             }
449         }
450     }
451     else
452     {
453         // if not specified, apply all configured prefixes
454         for (const PrefixAgent &prefixAgent : mPrefixAgents)
455         {
456             if (prefixAgent.IsValid())
457             {
458                 SuccessOrExit(error = AddIaAddress(aMessage, prefixAgent.GetPrefixAsAddress(), aClientId));
459             }
460         }
461     }
462 
463 exit:
464     return error;
465 }
466 
AddIaAddress(Message & aMessage,const Ip6::Address & aPrefix,ClientIdentifier & aClientId)467 Error Server::AddIaAddress(Message &aMessage, const Ip6::Address &aPrefix, ClientIdentifier &aClientId)
468 {
469     Error     error = kErrorNone;
470     IaAddress option;
471 
472     option.Init();
473     option.GetAddress().SetPrefix(aPrefix.mFields.m8, OT_IP6_PREFIX_BITSIZE);
474     option.GetAddress().GetIid().SetFromExtAddress(aClientId.GetDuidLinkLayerAddress());
475     option.SetPreferredLifetime(IaAddress::kDefaultPreferredLifetime);
476     option.SetValidLifetime(IaAddress::kDefaultValidLiftetime);
477     SuccessOrExit(error = aMessage.Append(option));
478 
479 exit:
480     return error;
481 }
482 
AppendRapidCommit(Message & aMessage)483 Error Server::AppendRapidCommit(Message &aMessage)
484 {
485     RapidCommit option;
486 
487     option.Init();
488     return aMessage.Append(option);
489 }
490 
ApplyMeshLocalPrefix(void)491 void Server::ApplyMeshLocalPrefix(void)
492 {
493     for (PrefixAgent &prefixAgent : mPrefixAgents)
494     {
495         if (prefixAgent.IsValid())
496         {
497             PrefixAgent *entry = &prefixAgent;
498 
499             Get<ThreadNetif>().RemoveUnicastAddress(entry->GetAloc());
500             entry->GetAloc().GetAddress().SetPrefix(Get<Mle::MleRouter>().GetMeshLocalPrefix());
501             Get<ThreadNetif>().AddUnicastAddress(entry->GetAloc());
502         }
503     }
504 }
505 
506 } // namespace Dhcp6
507 } // namespace ot
508 
509 #endif //  OPENTHREAD_CONFIG_DHCP6_SERVER_ENABLE
510