Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020 Project CHIP Authors
4 : * Copyright (c) 2019 Google LLC.
5 : * Copyright (c) 2013-2018 Nest Labs, Inc.
6 : *
7 : * Licensed under the Apache License, Version 2.0 (the "License");
8 : * you may not use this file except in compliance with the License.
9 : * You may obtain a copy of the License at
10 : *
11 : * http://www.apache.org/licenses/LICENSE-2.0
12 : *
13 : * Unless required by applicable law or agreed to in writing, software
14 : * distributed under the License is distributed on an "AS IS" BASIS,
15 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 : * See the License for the specific language governing permissions and
17 : * limitations under the License.
18 : */
19 :
20 : /**
21 : * @file
22 : * This file implements the class <tt>Inet::IPAddress</tt> and
23 : * related enumerated constants. The CHIP Inet Layer uses objects
24 : * of this class to represent Internet protocol addresses of both
25 : * IPv4 and IPv6 address families. (IPv4 addresses are stored
26 : * internally as IPv4-Mapped IPv6 addresses.)
27 : *
28 : */
29 :
30 : #ifndef __STDC_LIMIT_MACROS
31 : #define __STDC_LIMIT_MACROS
32 : #endif
33 :
34 : #include <inet/IPAddress.h>
35 :
36 : #include <inet/InetError.h>
37 : #include <lib/core/CHIPEncoding.h>
38 : #include <lib/support/CodeUtils.h>
39 :
40 : #include "arpa-inet-compatibility.h"
41 :
42 : #include <stdint.h>
43 : #include <string.h>
44 :
45 : namespace chip {
46 : namespace Inet {
47 :
48 : IPAddress IPAddress::Any;
49 :
50 12568 : bool IPAddress::operator==(const IPAddress & other) const
51 : {
52 12568 : return Addr[0] == other.Addr[0] && Addr[1] == other.Addr[1] && Addr[2] == other.Addr[2] && Addr[3] == other.Addr[3];
53 : }
54 :
55 3738 : bool IPAddress::operator!=(const IPAddress & other) const
56 : {
57 3738 : return Addr[0] != other.Addr[0] || Addr[1] != other.Addr[1] || Addr[2] != other.Addr[2] || Addr[3] != other.Addr[3];
58 : }
59 :
60 : #if CHIP_SYSTEM_CONFIG_USE_LWIP && !CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
61 :
62 : IPAddress::IPAddress(const ip6_addr_t & ipv6Addr)
63 : {
64 : static_assert(sizeof(ipv6Addr.addr) == sizeof(Addr), "ip6_addr_t size mismatch");
65 : memcpy(Addr, &ipv6Addr.addr, sizeof(ipv6Addr.addr));
66 : }
67 :
68 : #if INET_CONFIG_ENABLE_IPV4 || LWIP_IPV4
69 :
70 : IPAddress::IPAddress(const ip4_addr_t & ipv4Addr)
71 : {
72 : Addr[0] = 0;
73 : Addr[1] = 0;
74 : Addr[2] = htonl(0xFFFF);
75 : Addr[3] = ipv4Addr.addr;
76 : }
77 :
78 : IPAddress::IPAddress(const ip_addr_t & addr)
79 : {
80 : switch (IP_GET_TYPE(&addr))
81 : {
82 : #if INET_CONFIG_ENABLE_IPV4
83 : case IPADDR_TYPE_V4:
84 : *this = IPAddress(*ip_2_ip4(&addr));
85 : break;
86 : #endif // INET_CONFIG_ENABLE_IPV4
87 :
88 : case IPADDR_TYPE_V6:
89 : *this = IPAddress(*ip_2_ip6(&addr));
90 : break;
91 :
92 : default:
93 : *this = Any;
94 : break;
95 : }
96 : }
97 :
98 : #endif // INET_CONFIG_ENABLE_IPV4 || LWIP_IPV4
99 :
100 : #if INET_CONFIG_ENABLE_IPV4
101 :
102 : ip4_addr_t IPAddress::ToIPv4() const
103 : {
104 : ip4_addr_t ipAddr;
105 : memcpy(&ipAddr, &Addr[3], sizeof(ipAddr));
106 : return ipAddr;
107 : }
108 :
109 : #endif // INET_CONFIG_ENABLE_IPV4
110 :
111 : ip_addr_t IPAddress::ToLwIPAddr() const
112 : {
113 : ip_addr_t ret;
114 :
115 : switch (Type())
116 : {
117 : #if INET_CONFIG_ENABLE_IPV4
118 : case IPAddressType::kIPv4:
119 : ip_addr_copy_from_ip4(ret, IPAddress::ToIPv4());
120 : break;
121 : #endif // INET_CONFIG_ENABLE_IPV4
122 :
123 : case IPAddressType::kIPv6:
124 : ip_addr_copy_from_ip6(ret, IPAddress::ToIPv6());
125 : break;
126 :
127 : default:
128 : ret = *IP6_ADDR_ANY;
129 : break;
130 : }
131 :
132 : return ret;
133 : }
134 :
135 : CHIP_ERROR IPAddress::ToLwIPAddr(IPAddressType addressType, ip_addr_t & outAddress) const
136 : {
137 : VerifyOrReturnError(addressType != IPAddressType::kUnknown, CHIP_ERROR_INVALID_ARGUMENT);
138 :
139 : switch (Type())
140 : {
141 : #if INET_CONFIG_ENABLE_IPV4
142 : case IPAddressType::kIPv4:
143 : ip_addr_copy_from_ip4(outAddress, IPAddress::ToIPv4());
144 : return (addressType == IPAddressType::kIPv6) ? INET_ERROR_WRONG_ADDRESS_TYPE : CHIP_NO_ERROR;
145 : #endif // INET_CONFIG_ENABLE_IPV4
146 :
147 : case IPAddressType::kIPv6:
148 : ip_addr_copy_from_ip6(outAddress, IPAddress::ToIPv6());
149 : #if INET_CONFIG_ENABLE_IPV4
150 : return (addressType == IPAddressType::kIPv4) ? INET_ERROR_WRONG_ADDRESS_TYPE : CHIP_NO_ERROR;
151 : #else
152 : return CHIP_NO_ERROR;
153 : #endif // INET_CONFIG_ENABLE_IPV4
154 :
155 : case IPAddressType::kAny:
156 : #if INET_CONFIG_ENABLE_IPV4
157 : if (addressType == IPAddressType::kIPv4)
158 : {
159 : outAddress = *IP4_ADDR_ANY;
160 : return CHIP_NO_ERROR;
161 : }
162 : #endif // INET_CONFIG_ENABLE_IPV4
163 : outAddress = *IP6_ADDR_ANY;
164 : return CHIP_NO_ERROR;
165 :
166 : default:
167 : return INET_ERROR_WRONG_ADDRESS_TYPE;
168 : }
169 : }
170 :
171 : lwip_ip_addr_type IPAddress::ToLwIPAddrType(IPAddressType typ)
172 : {
173 : lwip_ip_addr_type ret;
174 :
175 : switch (typ)
176 : {
177 : #if INET_CONFIG_ENABLE_IPV4
178 : case IPAddressType::kIPv4:
179 : ret = IPADDR_TYPE_V4;
180 : break;
181 : #endif // INET_CONFIG_ENABLE_IPV4
182 :
183 : case IPAddressType::kIPv6:
184 : ret = IPADDR_TYPE_V6;
185 : break;
186 :
187 : default:
188 : ret = IPADDR_TYPE_ANY;
189 : break;
190 : }
191 :
192 : return ret;
193 : }
194 :
195 : ip6_addr_t IPAddress::ToIPv6() const
196 : {
197 : ip6_addr_t ipAddr = {};
198 : static_assert(sizeof(ipAddr.addr) == sizeof(Addr), "ip6_addr_t size mismatch");
199 : memcpy(&ipAddr.addr, Addr, sizeof(ipAddr.addr));
200 : return ipAddr;
201 : }
202 :
203 : #endif // CHIP_SYSTEM_CONFIG_USE_LWIP
204 :
205 : #if CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
206 :
207 : #if INET_CONFIG_ENABLE_IPV4
208 885 : IPAddress::IPAddress(const struct in_addr & ipv4Addr)
209 : {
210 885 : Addr[0] = 0;
211 885 : Addr[1] = 0;
212 885 : Addr[2] = htonl(0xFFFF);
213 885 : Addr[3] = ipv4Addr.s_addr;
214 885 : }
215 : #endif // INET_CONFIG_ENABLE_IPV4
216 :
217 846 : IPAddress::IPAddress(const struct in6_addr & ipv6Addr)
218 : {
219 : static_assert(sizeof(*this) == sizeof(ipv6Addr), "in6_addr size mismatch");
220 846 : memcpy(Addr, &ipv6Addr, sizeof(ipv6Addr));
221 846 : }
222 :
223 : #if INET_CONFIG_ENABLE_IPV4
224 180 : struct in_addr IPAddress::ToIPv4() const
225 : {
226 : struct in_addr ipv4Addr;
227 180 : ipv4Addr.s_addr = Addr[3];
228 180 : return ipv4Addr;
229 : }
230 : #endif // INET_CONFIG_ENABLE_IPV4
231 :
232 167 : struct in6_addr IPAddress::ToIPv6() const
233 : {
234 : in6_addr ipAddr;
235 : static_assert(sizeof(ipAddr) == sizeof(Addr), "in6_addr size mismatch");
236 167 : memcpy(&ipAddr, Addr, sizeof(ipAddr));
237 167 : return ipAddr;
238 : }
239 :
240 947 : CHIP_ERROR IPAddress::GetIPAddressFromSockAddr(const SockAddrWithoutStorage & sockaddr, IPAddress & outIPAddress)
241 : {
242 : #if INET_CONFIG_ENABLE_IPV4
243 947 : if (sockaddr.any.sa_family == AF_INET)
244 : {
245 519 : outIPAddress = FromSockAddr(sockaddr.in);
246 519 : return CHIP_NO_ERROR;
247 : }
248 : #endif // INET_CONFIG_ENABLE_IPV4
249 428 : if (sockaddr.any.sa_family == AF_INET6)
250 : {
251 428 : outIPAddress = FromSockAddr(sockaddr.in6);
252 428 : return CHIP_NO_ERROR;
253 : }
254 0 : return INET_ERROR_WRONG_ADDRESS_TYPE;
255 : }
256 :
257 : #endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS || CHIP_SYSTEM_CONFIG_USE_NETWORK_FRAMEWORK
258 :
259 : #if CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
260 : IPAddress::IPAddress(const otIp6Address & ipv6Addr)
261 : {
262 : static_assert(sizeof(ipv6Addr.mFields.m32) == sizeof(Addr), "otIp6Address size mismatch");
263 : memcpy(Addr, ipv6Addr.mFields.m32, sizeof(Addr));
264 : }
265 : otIp6Address IPAddress::ToIPv6() const
266 : {
267 : otIp6Address otAddr;
268 : static_assert(sizeof(otAddr.mFields.m32) == sizeof(Addr), "otIp6Address size mismatch");
269 : memcpy(otAddr.mFields.m32, Addr, sizeof(otAddr.mFields.m32));
270 : return otAddr;
271 : }
272 :
273 : IPAddress IPAddress::FromOtAddr(const otIp6Address & address)
274 : {
275 : IPAddress addr;
276 : static_assert(sizeof(address.mFields.m32) == sizeof(addr), "otIp6Address size mismatch");
277 : memcpy(addr.Addr, address.mFields.m32, sizeof(addr.Addr));
278 : return addr;
279 : }
280 : #endif // CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_ENDPOINT
281 :
282 : // Is address an IPv4 address encoded in IPv6 format?
283 20650 : bool IPAddress::IsIPv4() const
284 : {
285 20650 : return Addr[0] == 0 && Addr[1] == 0 && Addr[2] == htonl(0xFFFF);
286 : }
287 :
288 : // Is address a IPv4 multicast address?
289 126 : bool IPAddress::IsIPv4Multicast() const
290 : {
291 126 : return (IsIPv4() && ((ntohl(Addr[3]) & 0xF0000000U) == 0xE0000000U));
292 : }
293 :
294 : // Is address the IPv4 broadcast address?
295 55 : bool IPAddress::IsIPv4Broadcast() const
296 : {
297 55 : return (IsIPv4() && (Addr[3] == 0xFFFFFFFFU));
298 : }
299 :
300 : // Is address an IPv4 or IPv6 multicast address?
301 89 : bool IPAddress::IsMulticast() const
302 : {
303 89 : return (IsIPv6Multicast() || IsIPv4Multicast());
304 : }
305 :
306 557 : bool IPAddress::IsIPv6() const
307 : {
308 557 : return *this != Any && !IsIPv4();
309 : }
310 :
311 : // Is address an IPv6 multicast address?
312 146 : bool IPAddress::IsIPv6Multicast() const
313 : {
314 146 : return (ntohl(Addr[0]) & 0xFF000000U) == 0xFF000000U;
315 : }
316 :
317 : // Is address an IPv6 Global Unicast Address?
318 98 : bool IPAddress::IsIPv6GlobalUnicast() const
319 : {
320 98 : return (ntohl(Addr[0]) & 0xE0000000U) == 0x20000000U;
321 : }
322 :
323 : // Is address an IPv6 Unique Local Address?
324 314 : bool IPAddress::IsIPv6ULA() const
325 : {
326 314 : return (ntohl(Addr[0]) & 0xFF000000U) == 0xFD000000U;
327 : }
328 :
329 : // Is address an IPv6 Link-local Address?
330 522 : bool IPAddress::IsIPv6LinkLocal() const
331 : {
332 522 : return (Addr[0] == htonl(0xFE800000U) && Addr[1] == 0);
333 : }
334 :
335 : // Extract the interface id from a IPv6 ULA address. Returns 0 if the address
336 : // is not a ULA.
337 55 : uint64_t IPAddress::InterfaceId() const
338 : {
339 55 : if (IsIPv6ULA())
340 3 : return ((static_cast<uint64_t>(ntohl(Addr[2]))) << 32) | (static_cast<uint64_t>(ntohl(Addr[3])));
341 52 : return 0;
342 : }
343 :
344 : // Extract the subnet id from a IPv6 ULA address. Returns 0 if the address
345 : // is not a ULA.
346 55 : uint16_t IPAddress::Subnet() const
347 : {
348 55 : if (IsIPv6ULA())
349 3 : return static_cast<uint16_t>(ntohl(Addr[1]));
350 52 : return 0;
351 : }
352 :
353 : // Extract the global id from a IPv6 ULA address. Returns 0 if the address
354 : // is not a ULA.
355 55 : uint64_t IPAddress::GlobalId() const
356 : {
357 55 : if (IsIPv6ULA())
358 3 : return ((static_cast<uint64_t>(ntohl(Addr[0]) & 0xFFFFFF)) << 16) |
359 3 : (static_cast<uint64_t>(ntohl(Addr[1])) & 0xFFFF0000) >> 16;
360 52 : return 0;
361 : }
362 :
363 821 : IPAddressType IPAddress::Type() const
364 : {
365 821 : if (Addr[0] == 0 && Addr[1] == 0 && Addr[2] == 0 && Addr[3] == 0)
366 6 : return IPAddressType::kAny;
367 : #if INET_CONFIG_ENABLE_IPV4
368 815 : if (Addr[0] == 0 && Addr[1] == 0 && Addr[2] == htonl(0xFFFF))
369 459 : return IPAddressType::kIPv4;
370 : #endif // INET_CONFIG_ENABLE_IPV4
371 356 : return IPAddressType::kIPv6;
372 : }
373 :
374 : // Encode IPAddress to buffer in network byte order. Buffer must have at least 128 bits of available space.
375 : // Decoder must infer IP address type from context.
376 111 : void IPAddress::WriteAddress(uint8_t *& p) const
377 : {
378 : // Since each of the 32bit values in the Addr array is in network byte order, a simple
379 : // memcpy of the entire array is sufficient while copying the address.
380 :
381 111 : memcpy(p, &Addr[0], NL_INET_IPV6_ADDR_LEN_IN_BYTES);
382 :
383 111 : p += NL_INET_IPV6_ADDR_LEN_IN_BYTES;
384 111 : }
385 :
386 : // Decode IPAddress from buffer in network byte order. Must infer IP address type from context.
387 146 : void IPAddress::ReadAddress(const uint8_t *& p, IPAddress & output)
388 : {
389 : // Since we want to store the address in the output array in network byte order, a simple
390 : // memcpy of the entire array is used to retrieve from the buffer.
391 :
392 146 : memcpy(&output.Addr[0], p, NL_INET_IPV6_ADDR_LEN_IN_BYTES);
393 :
394 146 : p += NL_INET_IPV6_ADDR_LEN_IN_BYTES;
395 146 : }
396 :
397 : // Construct an IPv6 unique local address.
398 55 : IPAddress IPAddress::MakeULA(uint64_t globalId, uint16_t subnet, uint64_t interfaceId)
399 : {
400 : IPAddress addr;
401 :
402 55 : addr.Addr[0] = 0xFD000000 | static_cast<uint32_t>((globalId & 0xFFFFFF0000ULL) >> 16);
403 55 : addr.Addr[0] = htonl(addr.Addr[0]);
404 :
405 55 : addr.Addr[1] = static_cast<uint32_t>((globalId & 0x000000FFFFULL) << 16) | subnet;
406 55 : addr.Addr[1] = htonl(addr.Addr[1]);
407 :
408 55 : addr.Addr[2] = htonl(static_cast<uint32_t>(interfaceId >> 32));
409 55 : addr.Addr[3] = htonl(static_cast<uint32_t>(interfaceId));
410 :
411 55 : return addr;
412 : }
413 :
414 55 : IPAddress IPAddress::MakeLLA(uint64_t interfaceId)
415 : {
416 : IPAddress addr;
417 :
418 55 : addr.Addr[0] = htonl(0xFE800000);
419 55 : addr.Addr[1] = 0;
420 :
421 55 : addr.Addr[2] = htonl(static_cast<uint32_t>(interfaceId >> 32));
422 55 : addr.Addr[3] = htonl(static_cast<uint32_t>(interfaceId));
423 :
424 55 : return addr;
425 : }
426 :
427 59 : IPAddress IPAddress::MakeIPv6Multicast(IPv6MulticastFlags aFlags, uint8_t aScope,
428 : const uint8_t aGroupId[NL_INET_IPV6_MCAST_GROUP_LEN_IN_BYTES])
429 : {
430 : const uint32_t lFlagsAndScope =
431 59 : (((static_cast<uint32_t>(aFlags.Raw()) & 0xF) << 20) | ((static_cast<uint32_t>(aScope) & 0xF) << 16));
432 : IPAddress addr;
433 :
434 59 : addr.Addr[0] = htonl((0xFF000000U | lFlagsAndScope) | (uint32_t(aGroupId[0]) << 8) | (uint32_t(aGroupId[1]) << 0));
435 59 : addr.Addr[1] = htonl((uint32_t(aGroupId[2]) << 24) | (uint32_t(aGroupId[3]) << 16) | (uint32_t(aGroupId[4]) << 8) |
436 59 : (uint32_t(aGroupId[5]) << 0));
437 59 : addr.Addr[2] = htonl((uint32_t(aGroupId[6]) << 24) | (uint32_t(aGroupId[7]) << 16) | (uint32_t(aGroupId[8]) << 8) |
438 59 : (uint32_t(aGroupId[9]) << 0));
439 59 : addr.Addr[3] = htonl((uint32_t(aGroupId[10]) << 24) | (uint32_t(aGroupId[11]) << 16) | (uint32_t(aGroupId[12]) << 8) |
440 59 : (uint32_t(aGroupId[13]) << 0));
441 :
442 59 : return addr;
443 : }
444 :
445 14 : IPAddress IPAddress::MakeIPv6Multicast(IPv6MulticastFlags aFlags, uint8_t aScope, uint32_t aGroupId)
446 : {
447 14 : const uint8_t lGroupId[NL_INET_IPV6_MCAST_GROUP_LEN_IN_BYTES] = { 0,
448 : 0,
449 : 0,
450 : 0,
451 : 0,
452 : 0,
453 : 0,
454 : 0,
455 : 0,
456 : 0,
457 14 : static_cast<uint8_t>((aGroupId & 0xFF000000U) >> 24),
458 14 : static_cast<uint8_t>((aGroupId & 0x00FF0000U) >> 16),
459 14 : static_cast<uint8_t>((aGroupId & 0x0000FF00U) >> 8),
460 14 : static_cast<uint8_t>((aGroupId & 0x000000FFU) >> 0) };
461 :
462 14 : return (MakeIPv6Multicast(aFlags, aScope, lGroupId));
463 : }
464 :
465 14 : IPAddress IPAddress::MakeIPv6WellKnownMulticast(uint8_t aScope, uint32_t aGroupId)
466 : {
467 14 : constexpr IPv6MulticastFlags lFlags;
468 :
469 14 : return (MakeIPv6Multicast(lFlags, aScope, aGroupId));
470 : }
471 :
472 45 : IPAddress IPAddress::MakeIPv6TransientMulticast(IPv6MulticastFlags aFlags, uint8_t aScope,
473 : const uint8_t aGroupId[NL_INET_IPV6_MCAST_GROUP_LEN_IN_BYTES])
474 : {
475 45 : aFlags.Set(IPv6MulticastFlag::kTransient);
476 45 : return (MakeIPv6Multicast(aFlags, aScope, aGroupId));
477 : }
478 :
479 31 : IPAddress IPAddress::MakeIPv6PrefixMulticast(uint8_t aScope, uint8_t aPrefixLength, const uint64_t & aPrefix, uint32_t aGroupId)
480 : {
481 31 : const uint8_t lReserved = 0;
482 31 : const IPv6MulticastFlags lFlags = IPv6MulticastFlag::kPrefix;
483 31 : const uint8_t lGroupId[NL_INET_IPV6_MCAST_GROUP_LEN_IN_BYTES] = { lReserved,
484 : aPrefixLength,
485 31 : static_cast<uint8_t>((aPrefix & 0xFF00000000000000ULL) >> 56),
486 31 : static_cast<uint8_t>((aPrefix & 0x00FF000000000000ULL) >> 48),
487 31 : static_cast<uint8_t>((aPrefix & 0x0000FF0000000000ULL) >> 40),
488 31 : static_cast<uint8_t>((aPrefix & 0x000000FF00000000ULL) >> 32),
489 31 : static_cast<uint8_t>((aPrefix & 0x00000000FF000000ULL) >> 24),
490 31 : static_cast<uint8_t>((aPrefix & 0x0000000000FF0000ULL) >> 16),
491 31 : static_cast<uint8_t>((aPrefix & 0x000000000000FF00ULL) >> 8),
492 31 : static_cast<uint8_t>((aPrefix & 0x00000000000000FFULL) >> 0),
493 31 : static_cast<uint8_t>((aGroupId & 0xFF000000U) >> 24),
494 31 : static_cast<uint8_t>((aGroupId & 0x00FF0000U) >> 16),
495 31 : static_cast<uint8_t>((aGroupId & 0x0000FF00U) >> 8),
496 31 : static_cast<uint8_t>((aGroupId & 0x000000FFU) >> 0) };
497 :
498 31 : return (MakeIPv6TransientMulticast(lFlags, aScope, lGroupId));
499 : }
500 :
501 0 : IPAddress IPAddress::MakeIPv4Broadcast()
502 : {
503 : IPAddress ipAddr;
504 0 : ipAddr.Addr[0] = 0;
505 0 : ipAddr.Addr[1] = 0;
506 0 : ipAddr.Addr[2] = htonl(0xFFFF);
507 0 : ipAddr.Addr[3] = 0xFFFFFFFF;
508 0 : return ipAddr;
509 : }
510 :
511 114 : IPAddress IPAddress::Loopback(IPAddressType type)
512 : {
513 : IPAddress address;
514 : #if INET_CONFIG_ENABLE_IPV4
515 114 : if (type == IPAddressType::kIPv4)
516 : {
517 57 : address.Addr[0] = 0;
518 57 : address.Addr[1] = 0;
519 57 : address.Addr[2] = htonl(0xFFFF);
520 57 : address.Addr[3] = htonl(0x7F000001);
521 : }
522 : else
523 : #endif
524 : {
525 57 : address.Addr[0] = 0;
526 57 : address.Addr[1] = 0;
527 57 : address.Addr[2] = 0;
528 57 : address.Addr[3] = htonl(1);
529 : }
530 :
531 114 : return address;
532 : }
533 :
534 : } // namespace Inet
535 : } // namespace chip
|