/src/openweave-core/src/inet/RawEndPoint.cpp
Line | Count | Source |
1 | | /* |
2 | | * |
3 | | * Copyright (c) 2018 Google LLC. |
4 | | * Copyright (c) 2013-2018 Nest Labs, Inc. |
5 | | * All rights reserved. |
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 <tt>nl::Inet::RawEndPoint</tt> class, |
23 | | * where the Nest Inet Layer encapsulates methods for interacting |
24 | | * interacting with IP network endpoints (SOCK_RAW sockets |
25 | | * on Linux and BSD-derived systems) or LwIP raw protocol |
26 | | * control blocks, as the system is configured accordingly. |
27 | | * |
28 | | */ |
29 | | |
30 | | #define __APPLE_USE_RFC_3542 |
31 | | |
32 | | #include <string.h> |
33 | | |
34 | | #include <InetLayer/RawEndPoint.h> |
35 | | #include <InetLayer/InetLayer.h> |
36 | | #include <InetLayer/InetFaultInjection.h> |
37 | | #include <SystemLayer/SystemFaultInjection.h> |
38 | | |
39 | | #include <Weave/Support/CodeUtils.h> |
40 | | #include <Weave/Support/logging/WeaveLogging.h> |
41 | | |
42 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
43 | | #include <lwip/raw.h> |
44 | | #include <lwip/tcpip.h> |
45 | | #include <lwip/ip.h> |
46 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
47 | | |
48 | | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
49 | | #include <poll.h> |
50 | | #if HAVE_SYS_SOCKET_H |
51 | | #include <sys/socket.h> |
52 | | #endif // HAVE_SYS_SOCKET_H |
53 | | #include <errno.h> |
54 | | #include <unistd.h> |
55 | | #include <net/if.h> |
56 | | #include <sys/ioctl.h> |
57 | | #if HAVE_NETINET_ICMP6_H |
58 | | #include <netinet/icmp6.h> |
59 | | #endif // HAVE_NETINET_ICMP6_H |
60 | | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
61 | | |
62 | | // SOCK_CLOEXEC not defined on all platforms, e.g. iOS/MacOS: |
63 | | #ifdef SOCK_CLOEXEC |
64 | 0 | #define SOCK_FLAGS SOCK_CLOEXEC |
65 | | #else |
66 | | #define SOCK_FLAGS 0 |
67 | | #endif |
68 | | |
69 | | namespace nl { |
70 | | namespace Inet { |
71 | | |
72 | | using Weave::System::PacketBuffer; |
73 | | |
74 | | Weave::System::ObjectPool<RawEndPoint, INET_CONFIG_NUM_RAW_ENDPOINTS> RawEndPoint::sPool; |
75 | | |
76 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
77 | | /* |
78 | | * Note that for LwIP InterfaceId is already defined to be 'struct |
79 | | * netif'; consequently, some of the checking performed here could |
80 | | * conceivably be optimized out and the HAVE_LWIP_UDP_BIND_NETIF case |
81 | | * could simply be: |
82 | | * |
83 | | * udp_bind_netif(aUDP, intfId); |
84 | | * |
85 | | */ |
86 | | static INET_ERROR LwIPBindInterface(struct raw_pcb *aRaw, InterfaceId intfId) |
87 | | { |
88 | | INET_ERROR res = INET_NO_ERROR; |
89 | | |
90 | | #if HAVE_LWIP_RAW_BIND_NETIF |
91 | | if (!IsInterfaceIdPresent(intfId)) |
92 | | raw_bind_netif(aRaw, NULL); |
93 | | else |
94 | | { |
95 | | struct netif *netifp = IPEndPointBasis::FindNetifFromInterfaceId(intfId); |
96 | | |
97 | | if (netifp == NULL) |
98 | | res = INET_ERROR_UNKNOWN_INTERFACE; |
99 | | else |
100 | | raw_bind_netif(aRaw, netifp); |
101 | | } |
102 | | #else |
103 | | if (!IsInterfaceIdPresent(intfId)) |
104 | | aRaw->intf_filter = NULL; |
105 | | else |
106 | | { |
107 | | struct netif *netifp = IPEndPointBasis::FindNetifFromInterfaceId(intfId); |
108 | | |
109 | | if (netifp == NULL) |
110 | | res = INET_ERROR_UNKNOWN_INTERFACE; |
111 | | else |
112 | | aRaw->intf_filter = netifp; |
113 | | } |
114 | | #endif // HAVE_LWIP_RAW_BIND_NETIF |
115 | | |
116 | | return res; |
117 | | } |
118 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
119 | | |
120 | | /** |
121 | | * @brief Bind the endpoint to an interface IP address. |
122 | | * |
123 | | * @param[in] addrType the protocol version of the IP address |
124 | | * @param[in] addr the IP address (must be an interface address) |
125 | | * @param[in] intfId an optional network interface indicator |
126 | | * |
127 | | * @retval INET_NO_ERROR success: endpoint bound to address |
128 | | * @retval INET_ERROR_INCORRECT_STATE endpoint has been bound previously |
129 | | * @retval INET_NO_MEMORY insufficient memory for endpoint |
130 | | * |
131 | | * @retval INET_ERROR_UNKNOWN_INTERFACE |
132 | | * On some platforms, the optionally specified interface is not |
133 | | * present. |
134 | | * |
135 | | * @retval INET_ERROR_WRONG_PROTOCOL_TYPE |
136 | | * \c addrType does not match \c IPVer. |
137 | | * |
138 | | * @retval INET_ERROR_WRONG_ADDRESS_TYPE |
139 | | * \c addrType is \c kIPAddressType_Any, or the type of \c addr is not |
140 | | * equal to \c addrType. |
141 | | * |
142 | | * @retval other another system or platform error |
143 | | * |
144 | | * @details |
145 | | * Binds the endpoint to the specified network interface IP address. |
146 | | * |
147 | | * On LwIP, this method must not be called with the LwIP stack lock |
148 | | * already acquired. |
149 | | */ |
150 | | INET_ERROR RawEndPoint::Bind(IPAddressType addrType, IPAddress addr, InterfaceId intfId) |
151 | 0 | { |
152 | 0 | INET_ERROR res = INET_NO_ERROR; |
153 | |
|
154 | 0 | if (mState != kState_Ready && mState != kState_Bound) |
155 | 0 | { |
156 | 0 | res = INET_ERROR_INCORRECT_STATE; |
157 | 0 | goto exit; |
158 | 0 | } |
159 | | |
160 | 0 | if ((addr != IPAddress::Any) && (addr.Type() != kIPAddressType_Any) && (addr.Type() != addrType)) |
161 | 0 | { |
162 | 0 | res = INET_ERROR_WRONG_ADDRESS_TYPE; |
163 | 0 | goto exit; |
164 | 0 | } |
165 | | |
166 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
167 | | |
168 | | // Lock LwIP stack |
169 | | LOCK_TCPIP_CORE(); |
170 | | |
171 | | // Make sure we have the appropriate type of PCB. |
172 | | res = GetPCB(addrType); |
173 | | |
174 | | // Bind the PCB to the specified address. |
175 | | if (res == INET_NO_ERROR) |
176 | | { |
177 | | #if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5 |
178 | | ip_addr_t ipAddr = addr.ToLwIPAddr(); |
179 | | #if INET_CONFIG_ENABLE_IPV4 |
180 | | lwip_ip_addr_type lType = IPAddress::ToLwIPAddrType(addrType); |
181 | | IP_SET_TYPE_VAL(ipAddr, lType); |
182 | | #endif // INET_CONFIG_ENABLE_IPV4 |
183 | | res = Weave::System::MapErrorLwIP(raw_bind(mRaw, &ipAddr)); |
184 | | #else // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5 |
185 | | if (addrType == kIPAddressType_IPv6) |
186 | | { |
187 | | ip6_addr_t ipv6Addr = addr.ToIPv6(); |
188 | | res = Weave::System::MapErrorLwIP(raw_bind_ip6(mRaw, &ipv6Addr)); |
189 | | } |
190 | | #if INET_CONFIG_ENABLE_IPV4 |
191 | | else if (addrType == kIPAddressType_IPv4) |
192 | | { |
193 | | ip4_addr_t ipv4Addr = addr.ToIPv4(); |
194 | | res = Weave::System::MapErrorLwIP(raw_bind(mRaw, &ipv4Addr)); |
195 | | } |
196 | | #endif // INET_CONFIG_ENABLE_IPV4 |
197 | | else |
198 | | res = INET_ERROR_WRONG_ADDRESS_TYPE; |
199 | | #endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5 |
200 | | } |
201 | | |
202 | | if (res == INET_NO_ERROR) |
203 | | { |
204 | | res = LwIPBindInterface(mRaw, intfId); |
205 | | } |
206 | | |
207 | | // Unlock LwIP stack |
208 | | UNLOCK_TCPIP_CORE(); |
209 | | |
210 | | SuccessOrExit(res); |
211 | | |
212 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
213 | | |
214 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
215 | | // Make sure we have the appropriate type of socket. |
216 | 0 | res = GetSocket(addrType); |
217 | 0 | SuccessOrExit(res); |
218 | | |
219 | 0 | res = IPEndPointBasis::Bind(addrType, addr, 0, intfId); |
220 | 0 | SuccessOrExit(res); |
221 | | |
222 | 0 | mBoundIntfId = intfId; |
223 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
224 | |
|
225 | 0 | if (res == INET_NO_ERROR) |
226 | 0 | { |
227 | 0 | mState = kState_Bound; |
228 | 0 | } |
229 | |
|
230 | 0 | exit: |
231 | 0 | return res; |
232 | 0 | } |
233 | | |
234 | | /** |
235 | | * Bind the raw endpoint to an IPv6 link-local scope address at the specified |
236 | | * interface index. Also sets various IPv6 socket options appropriate for |
237 | | * transmitting packets to and from on-link destinations. |
238 | | * |
239 | | * @param[in] intf An InterfaceId to identify the scope of the address. |
240 | | * |
241 | | * @param[in] addr An IPv6 link-local scope IPAddress object. |
242 | | * |
243 | | * @return INET_NO_ERROR on success, or a mapped OS error on failure. An invalid |
244 | | * parameter list can result in INET_ERROR_WRONG_ADDRESS_TYPE. If the raw endpoint |
245 | | * is already bound or is listening, then returns INET_ERROR_INCORRECT_STATE. |
246 | | */ |
247 | | /** |
248 | | * @brief Bind the endpoint to an interface IPv6 link-local address. |
249 | | * |
250 | | * @param[in] intf the indicator of the network interface |
251 | | * @param[in] addr the IP address (must be an interface address) |
252 | | * |
253 | | * @retval INET_NO_ERROR success: endpoint bound to address |
254 | | * @retval INET_ERROR_INCORRECT_STATE endpoint has been bound previously |
255 | | * @retval INET_NO_MEMORY insufficient memory for endpoint |
256 | | * |
257 | | * @retval INET_ERROR_WRONG_PROTOCOL_TYPE |
258 | | * \c addrType does not match \c IPVer. |
259 | | * |
260 | | * @retval INET_ERROR_WRONG_ADDRESS_TYPE |
261 | | * \c addr is not an IPv6 link-local address or \c intf is |
262 | | * \c INET_NULL_INTERFACEID. |
263 | | * |
264 | | * @retval other another system or platform error |
265 | | * |
266 | | * @details |
267 | | * Binds the endpoint to the IPv6 link-local address \c addr on the |
268 | | * network interface indicated by \c intf. |
269 | | * |
270 | | * On LwIP, this method must not be called with the LwIP stack lock |
271 | | * already acquired. |
272 | | */ |
273 | | INET_ERROR RawEndPoint::BindIPv6LinkLocal(InterfaceId intf, IPAddress addr) |
274 | 0 | { |
275 | 0 | INET_ERROR res = INET_NO_ERROR; |
276 | |
|
277 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
278 | 0 | const int lIfIndex = static_cast<int>(intf); |
279 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
280 | |
|
281 | 0 | if (mState != kState_Ready && mState != kState_Bound) |
282 | 0 | { |
283 | 0 | res = INET_ERROR_INCORRECT_STATE; |
284 | 0 | goto ret; |
285 | 0 | } |
286 | | |
287 | 0 | if (!addr.IsIPv6LinkLocal()) |
288 | 0 | { |
289 | 0 | res = INET_ERROR_WRONG_ADDRESS_TYPE; |
290 | 0 | goto ret; |
291 | 0 | } |
292 | | |
293 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
294 | | |
295 | | // Lock LwIP stack |
296 | | LOCK_TCPIP_CORE(); |
297 | | |
298 | | // Make sure we have the appropriate type of PCB. |
299 | | res = GetPCB(addr.Type()); |
300 | | |
301 | | // Bind the PCB to the specified address. |
302 | | if (res == INET_NO_ERROR) |
303 | | { |
304 | | #if LWIP_VERSION_MAJOR > 1 |
305 | | ip_addr_t ipAddr = addr.ToLwIPAddr(); |
306 | | res = Weave::System::MapErrorLwIP(raw_bind(mRaw, &ipAddr)); |
307 | | #else // LWIP_VERSION_MAJOR <= 1 |
308 | | ip6_addr_t ipv6Addr = addr.ToIPv6(); |
309 | | res = Weave::System::MapErrorLwIP(raw_bind_ip6(mRaw, &ipv6Addr)); |
310 | | #endif // LWIP_VERSION_MAJOR <= 1 |
311 | | |
312 | | if (res != INET_NO_ERROR) |
313 | | { |
314 | | raw_remove(mRaw); |
315 | | mRaw = NULL; |
316 | | mLwIPEndPointType = kLwIPEndPointType_Unknown; |
317 | | } |
318 | | } |
319 | | |
320 | | // Unlock LwIP stack |
321 | | UNLOCK_TCPIP_CORE(); |
322 | | |
323 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
324 | | |
325 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
326 | | |
327 | 0 | static const int sInt255 = 255; |
328 | | |
329 | | // Make sure we have the appropriate type of socket. |
330 | 0 | res = GetSocket(kIPAddressType_IPv6); |
331 | 0 | if (res != INET_NO_ERROR) |
332 | 0 | { |
333 | 0 | goto ret; |
334 | 0 | } |
335 | | |
336 | 0 | if (::setsockopt(mSocket, IPPROTO_IPV6, IPV6_MULTICAST_IF, &lIfIndex, sizeof(lIfIndex)) != 0) |
337 | 0 | { |
338 | 0 | goto optfail; |
339 | 0 | } |
340 | | |
341 | 0 | if (::setsockopt(mSocket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &sInt255, sizeof(sInt255)) != 0) |
342 | 0 | { |
343 | 0 | goto optfail; |
344 | 0 | } |
345 | | |
346 | 0 | if (::setsockopt(mSocket, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &sInt255, sizeof(sInt255)) != 0) |
347 | 0 | { |
348 | 0 | goto optfail; |
349 | 0 | } |
350 | | |
351 | 0 | mAddrType = kIPAddressType_IPv6; |
352 | 0 | goto ret; |
353 | | |
354 | 0 | optfail: |
355 | 0 | res = Weave::System::MapErrorPOSIX(errno); |
356 | 0 | ::close(mSocket); |
357 | 0 | mSocket = INET_INVALID_SOCKET_FD; |
358 | 0 | mAddrType = kIPAddressType_Unknown; |
359 | |
|
360 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
361 | |
|
362 | 0 | ret: |
363 | 0 | if (res == INET_NO_ERROR) |
364 | 0 | { |
365 | 0 | mState = kState_Bound; |
366 | 0 | } |
367 | |
|
368 | 0 | return res; |
369 | 0 | } |
370 | | |
371 | | /** |
372 | | * @brief Prepare the endpoint to receive ICMP messages. |
373 | | * |
374 | | * @retval INET_NO_ERROR always returned. |
375 | | * |
376 | | * @details |
377 | | * If \c mState is already \c kState_Listening, then no operation is |
378 | | * performed, otherwise the \c mState is set to \c kState_Listening and |
379 | | * the endpoint is prepared to received ICMPv6 messages, according to the |
380 | | * semantics of the platform. |
381 | | * |
382 | | * On LwIP, this method must not be called with the LwIP stack lock |
383 | | * already acquired |
384 | | */ |
385 | | INET_ERROR RawEndPoint::Listen(void) |
386 | 0 | { |
387 | 0 | INET_ERROR res = INET_NO_ERROR; |
388 | |
|
389 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
390 | 0 | Weave::System::Layer& lSystemLayer = SystemLayer(); |
391 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
392 | |
|
393 | 0 | if (mState == kState_Listening) |
394 | 0 | { |
395 | 0 | res = INET_NO_ERROR; |
396 | 0 | goto exit; |
397 | 0 | } |
398 | | |
399 | 0 | if (mState != kState_Bound) |
400 | 0 | { |
401 | 0 | res = INET_ERROR_INCORRECT_STATE; |
402 | 0 | goto exit; |
403 | 0 | } |
404 | | |
405 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
406 | | |
407 | | // Lock LwIP stack |
408 | | LOCK_TCPIP_CORE(); |
409 | | |
410 | | #if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5 |
411 | | raw_recv(mRaw, LwIPReceiveRawMessage, this); |
412 | | #else // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5 |
413 | | if (PCB_ISIPV6(mRaw)) |
414 | | raw_recv_ip6(mRaw, LwIPReceiveRawMessage, this); |
415 | | else |
416 | | raw_recv(mRaw, LwIPReceiveRawMessage, this); |
417 | | #endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5 |
418 | | |
419 | | // Unlock LwIP stack |
420 | | UNLOCK_TCPIP_CORE(); |
421 | | |
422 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
423 | | |
424 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
425 | | |
426 | | // Wake the thread calling select so that it starts selecting on the new socket. |
427 | 0 | lSystemLayer.WakeSelect(); |
428 | |
|
429 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
430 | |
|
431 | 0 | if (res == INET_NO_ERROR) |
432 | 0 | { |
433 | 0 | mState = kState_Listening; |
434 | 0 | } |
435 | |
|
436 | 0 | exit: |
437 | 0 | return res; |
438 | 0 | } |
439 | | |
440 | | /** |
441 | | * @brief Close the endpoint. |
442 | | * |
443 | | * @details |
444 | | * If <tt>mState != kState_Closed</tt>, then closes the endpoint, removing |
445 | | * it from the set of endpoints eligible for communication events. |
446 | | * |
447 | | * On LwIP systems, this method must not be called with the LwIP stack |
448 | | * lock already acquired. |
449 | | */ |
450 | | void RawEndPoint::Close(void) |
451 | 0 | { |
452 | 0 | if (mState != kState_Closed) |
453 | 0 | { |
454 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
455 | | |
456 | | // Lock LwIP stack |
457 | | LOCK_TCPIP_CORE(); |
458 | | |
459 | | // Since Raw PCB is released synchronously here, but Raw endpoint itself might have to wait |
460 | | // for destruction asynchronously, there could be more allocated Raw endpoints than Raw PCBs. |
461 | | if (mRaw != NULL) |
462 | | { |
463 | | raw_remove(mRaw); |
464 | | mRaw = NULL; |
465 | | mLwIPEndPointType = kLwIPEndPointType_Unknown; |
466 | | } |
467 | | |
468 | | // Unlock LwIP stack |
469 | | UNLOCK_TCPIP_CORE(); |
470 | | |
471 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
472 | |
|
473 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
474 | |
|
475 | 0 | if (mSocket != INET_INVALID_SOCKET_FD) |
476 | 0 | { |
477 | 0 | Weave::System::Layer& lSystemLayer = SystemLayer(); |
478 | | |
479 | | // Wake the thread calling select so that it recognizes the socket is closed. |
480 | 0 | lSystemLayer.WakeSelect(); |
481 | |
|
482 | 0 | close(mSocket); |
483 | 0 | mSocket = INET_INVALID_SOCKET_FD; |
484 | 0 | } |
485 | | |
486 | | // Clear any results from select() that indicate pending I/O for the socket. |
487 | 0 | mPendingIO.Clear(); |
488 | |
|
489 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
490 | |
|
491 | 0 | mState = kState_Closed; |
492 | 0 | } |
493 | 0 | } |
494 | | |
495 | | /** |
496 | | * @brief Close the endpoint and recycle its memory. |
497 | | * |
498 | | * @details |
499 | | * Invokes the \c Close method, then invokes the |
500 | | * <tt>InetLayerBasis::Release</tt> method to return the object to its |
501 | | * memory pool. |
502 | | * |
503 | | * On LwIP systems, this method must not be called with the LwIP stack |
504 | | * lock already acquired. |
505 | | */ |
506 | | void RawEndPoint::Free(void) |
507 | 0 | { |
508 | 0 | Close(); |
509 | |
|
510 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
511 | | DeferredFree(kReleaseDeferralErrorTactic_Die); |
512 | | #else // !WEAVE_SYSTEM_CONFIG_USE_LWIP |
513 | 0 | Release(); |
514 | 0 | #endif // !WEAVE_SYSTEM_CONFIG_USE_LWIP |
515 | 0 | } |
516 | | |
517 | | /** |
518 | | * A synonym for <tt>SendTo(addr, INET_NULL_INTERFACEID, msg, |
519 | | * sendFlags)</tt>. |
520 | | */ |
521 | | INET_ERROR RawEndPoint::SendTo(IPAddress addr, Weave::System::PacketBuffer *msg, uint16_t sendFlags) |
522 | 0 | { |
523 | 0 | return SendTo(addr, INET_NULL_INTERFACEID, msg, sendFlags); |
524 | 0 | } |
525 | | |
526 | | /** |
527 | | * @brief Send an ICMP message to the specified destination address. |
528 | | * |
529 | | * @param[in] addr the destination IP address |
530 | | * @param[in] intfId an optional network interface indicator |
531 | | * @param[in] msg the packet buffer containing the UDP message |
532 | | * @param[in] sendFlags optional transmit option flags |
533 | | * |
534 | | * @retval INET_NO_ERROR |
535 | | * success: \c msg is queued for transmit. |
536 | | * |
537 | | * @retval INET_ERROR_NOT_SUPPORTED |
538 | | * the system does not support the requested operation. |
539 | | * |
540 | | * @retval INET_ERROR_WRONG_ADDRESS_TYPE |
541 | | * the destination address and the bound interface address do not |
542 | | * have matching protocol versions or address type. |
543 | | * |
544 | | * @retval INET_ERROR_MESSAGE_TOO_LONG |
545 | | * \c msg does not contain the whole ICMP message. |
546 | | * |
547 | | * @retval INET_ERROR_OUTBOUND_MESSAGE_TRUNCATED |
548 | | * On some platforms, only a truncated portion of \c msg was queued |
549 | | * for transmit. |
550 | | * |
551 | | * @retval other another system or platform error |
552 | | * |
553 | | * @details |
554 | | * Send the ICMP message in \c msg to the destination given in \c addr. |
555 | | * |
556 | | * Where <tt>(sendFlags & kSendFlag_RetainBuffer) != 0</tt>, calls |
557 | | * <tt>Weave::System::PacketBuffer::Free</tt> on behalf of the caller, otherwise this |
558 | | * method deep-copies \c msg into a fresh object, and queues that for |
559 | | * transmission, leaving the original \c msg available after return. |
560 | | */ |
561 | | INET_ERROR RawEndPoint::SendTo(IPAddress addr, InterfaceId intfId, Weave::System::PacketBuffer *msg, uint16_t sendFlags) |
562 | 0 | { |
563 | 0 | IPPacketInfo pktInfo; |
564 | 0 | pktInfo.Clear(); |
565 | 0 | pktInfo.DestAddress = addr; |
566 | 0 | pktInfo.Interface = intfId; |
567 | 0 | return SendMsg(&pktInfo, msg, sendFlags); |
568 | 0 | } |
569 | | |
570 | | /** |
571 | | * @brief Send an ICMP message to the specified destination. |
572 | | * |
573 | | * @param[in] pktInfo destination information for the message |
574 | | * @param[in] msg the packet buffer containing the UDP message |
575 | | * @param[in] sendFlags optional transmit option flags |
576 | | * |
577 | | * @retval INET_NO_ERROR |
578 | | * success: \c msg is queued for transmit. |
579 | | * |
580 | | * @retval INET_ERROR_NOT_SUPPORTED |
581 | | * the system does not support the requested operation. |
582 | | * |
583 | | * @retval INET_ERROR_WRONG_ADDRESS_TYPE |
584 | | * the destination address and the bound interface address do not |
585 | | * have matching protocol versions or address type. |
586 | | * |
587 | | * @retval INET_ERROR_MESSAGE_TOO_LONG |
588 | | * \c msg does not contain the whole ICMP message. |
589 | | * |
590 | | * @retval INET_ERROR_OUTBOUND_MESSAGE_TRUNCATED |
591 | | * On some platforms, only a truncated portion of \c msg was queued |
592 | | * for transmit. |
593 | | * |
594 | | * @retval other another system or platform error |
595 | | * |
596 | | * @details |
597 | | * Send the ICMP message \c msg using the destination information given in \c addr. |
598 | | * |
599 | | * Where <tt>(sendFlags & kSendFlag_RetainBuffer) != 0</tt>, calls |
600 | | * <tt>Weave::System::PacketBuffer::Free</tt> on behalf of the caller, otherwise this |
601 | | * method deep-copies \c msg into a fresh object, and queues that for |
602 | | * transmission, leaving the original \c msg available after return. |
603 | | */ |
604 | | INET_ERROR RawEndPoint::SendMsg(const IPPacketInfo *pktInfo, Weave::System::PacketBuffer *msg, uint16_t sendFlags) |
605 | 0 | { |
606 | 0 | INET_ERROR res = INET_NO_ERROR; |
607 | 0 | const IPAddress & addr = pktInfo->DestAddress; |
608 | |
|
609 | 0 | INET_FAULT_INJECT(FaultInjection::kFault_Send, |
610 | 0 | if ((sendFlags & kSendFlag_RetainBuffer) == 0) |
611 | 0 | PacketBuffer::Free(msg); |
612 | 0 | return INET_ERROR_UNKNOWN_INTERFACE; |
613 | 0 | ); |
614 | 0 | INET_FAULT_INJECT(FaultInjection::kFault_SendNonCritical, |
615 | 0 | if ((sendFlags & kSendFlag_RetainBuffer) == 0) |
616 | 0 | PacketBuffer::Free(msg); |
617 | 0 | return INET_ERROR_NO_MEMORY; |
618 | 0 | ); |
619 | | |
620 | | // Do not allow sending an IPv4 address on an IPv6 end point and |
621 | | // vice versa. |
622 | | |
623 | 0 | if (IPVer == kIPVersion_6 && addr.Type() != kIPAddressType_IPv6) |
624 | 0 | { |
625 | 0 | return INET_ERROR_WRONG_ADDRESS_TYPE; |
626 | 0 | } |
627 | 0 | #if INET_CONFIG_ENABLE_IPV4 |
628 | 0 | else if (IPVer == kIPVersion_4 && addr.Type() != kIPAddressType_IPv4) |
629 | 0 | { |
630 | 0 | return INET_ERROR_WRONG_ADDRESS_TYPE; |
631 | 0 | } |
632 | 0 | #endif // INET_CONFIG_ENABLE_IPV4 |
633 | | |
634 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
635 | | |
636 | | if (sendFlags & kSendFlag_RetainBuffer) |
637 | | { |
638 | | // when retaining a buffer, the caller expects the msg to be |
639 | | // unmodified. LwIP stack will normally prepend the packet |
640 | | // headers as the packet traverses the IP/netif layers, |
641 | | // which normally modifies the packet. We prepend a small |
642 | | // pbuf to the beginning of the pbuf chain, s.t. all headers |
643 | | // are added to the temporary space, just large enough to hold |
644 | | // the transport headers. Careful reader will note: |
645 | | // |
646 | | // * we're actually oversizing the reserved space, the |
647 | | // transport header is large enough for the TCP header which |
648 | | // is larger than the UDP header, but it seemed cleaner than |
649 | | // the combination of PBUF_IP for reserve space, UDP_HLEN |
650 | | // for payload, and post allocation adjustment of the header |
651 | | // space). |
652 | | // |
653 | | // * the code deviates from the existing PacketBuffer |
654 | | // abstractions and needs to reach into the underlying pbuf |
655 | | // code. The code in PacketBuffer also forces us to perform |
656 | | // (effectively) a reinterpret_cast rather than a |
657 | | // static_cast. JIRA WEAV-811 is filed to track the |
658 | | // re-architecting of the memory management. |
659 | | |
660 | | pbuf *msgCopy = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM); |
661 | | |
662 | | if (msgCopy == NULL) |
663 | | { |
664 | | return INET_ERROR_NO_MEMORY; |
665 | | } |
666 | | |
667 | | pbuf_chain(msgCopy, (pbuf *) msg); |
668 | | msg = (PacketBuffer *)msgCopy; |
669 | | } |
670 | | |
671 | | // Lock LwIP stack |
672 | | LOCK_TCPIP_CORE(); |
673 | | |
674 | | // Make sure we have the appropriate type of PCB based on the destination address. |
675 | | res = GetPCB(addr.Type()); |
676 | | SuccessOrExit(res); |
677 | | |
678 | | // Send the message to the specified address/port. |
679 | | { |
680 | | err_t lwipErr = ERR_VAL; |
681 | | |
682 | | #if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5 |
683 | | ip_addr_t ipAddr = addr.ToLwIPAddr(); |
684 | | |
685 | | lwipErr = raw_sendto(mRaw, (pbuf *)msg, &ipAddr); |
686 | | #else // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5 |
687 | | if (PCB_ISIPV6(mRaw)) |
688 | | { |
689 | | ip6_addr_t ipv6Addr = addr.ToIPv6(); |
690 | | |
691 | | lwipErr = raw_sendto_ip6(mRaw, (pbuf *)msg, &ipv6Addr); |
692 | | } |
693 | | #if INET_CONFIG_ENABLE_IPV4 |
694 | | else |
695 | | { |
696 | | ip4_addr_t ipv4Addr = addr.ToIPv4(); |
697 | | |
698 | | lwipErr = raw_sendto(mRaw, (pbuf *)msg, &ipv4Addr); |
699 | | } |
700 | | #endif // INET_CONFIG_ENABLE_IPV4 |
701 | | #endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5 |
702 | | |
703 | | if (lwipErr != ERR_OK) |
704 | | res = Weave::System::MapErrorLwIP(lwipErr); |
705 | | } |
706 | | |
707 | | // Unlock LwIP stack |
708 | | UNLOCK_TCPIP_CORE(); |
709 | | |
710 | | PacketBuffer::Free(msg); |
711 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
712 | | |
713 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
714 | | // Make sure we have the appropriate type of socket based on the |
715 | | // destination address. |
716 | | |
717 | 0 | res = GetSocket(addr.Type()); |
718 | 0 | SuccessOrExit(res); |
719 | | |
720 | 0 | res = IPEndPointBasis::SendMsg(pktInfo, msg, sendFlags); |
721 | |
|
722 | 0 | if ((sendFlags & kSendFlag_RetainBuffer) == 0) |
723 | 0 | PacketBuffer::Free(msg); |
724 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
725 | |
|
726 | 0 | exit: |
727 | 0 | WEAVE_SYSTEM_FAULT_INJECT_ASYNC_EVENT(); |
728 | |
|
729 | 0 | return res; |
730 | 0 | } |
731 | | |
732 | | /** |
733 | | * @brief Set the ICMP6 filter parameters in the network stack. |
734 | | * |
735 | | * @param[in] numICMPTypes length of array at \c aICMPTypes |
736 | | * @param[in] aICMPTypes the set of ICMPv6 type codes to filter. |
737 | | * |
738 | | * @retval INET_NO_ERROR success: filter parameters set |
739 | | * @retval INET_ERROR_NOT_IMPLEMENTED system does not implement |
740 | | * @retval INET_ERROR_WRONG_ADDRESS_TYPE endpoint not IPv6 type |
741 | | * @retval INET_ERROR_WRONG_PROTOCOL_TYPE endpoint not ICMP6 type |
742 | | * |
743 | | * @retval other another system or platform error |
744 | | * |
745 | | * @details |
746 | | * Apply the ICMPv6 filtering parameters for the codes in \c aICMPTypes to |
747 | | * the underlying endpoint in the system networking stack. |
748 | | */ |
749 | | INET_ERROR RawEndPoint::SetICMPFilter(uint8_t numICMPTypes, const uint8_t * aICMPTypes) |
750 | 0 | { |
751 | 0 | INET_ERROR err; |
752 | |
|
753 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
754 | | #if !(HAVE_NETINET_ICMP6_H && HAVE_ICMP6_FILTER) |
755 | | err = INET_ERROR_NOT_IMPLEMENTED; |
756 | | ExitNow(); |
757 | | #endif //!(HAVE_NETINET_ICMP6_H && HAVE_ICMP6_FILTER) |
758 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
759 | |
|
760 | 0 | VerifyOrExit(IPVer == kIPVersion_6, err = INET_ERROR_WRONG_ADDRESS_TYPE); |
761 | 0 | VerifyOrExit(IPProto == kIPProtocol_ICMPv6, err = INET_ERROR_WRONG_PROTOCOL_TYPE); |
762 | 0 | VerifyOrExit((numICMPTypes == 0 && aICMPTypes == NULL) || (numICMPTypes != 0 && aICMPTypes != NULL), err = |
763 | 0 | INET_ERROR_BAD_ARGS); |
764 | | |
765 | 0 | err = INET_NO_ERROR; |
766 | |
|
767 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
768 | | LOCK_TCPIP_CORE(); |
769 | | NumICMPTypes = numICMPTypes; |
770 | | ICMPTypes = aICMPTypes; |
771 | | UNLOCK_TCPIP_CORE(); |
772 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
773 | |
|
774 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
775 | 0 | #if HAVE_NETINET_ICMP6_H && HAVE_ICMP6_FILTER |
776 | 0 | struct icmp6_filter filter; |
777 | 0 | if (numICMPTypes > 0) |
778 | 0 | { |
779 | 0 | ICMP6_FILTER_SETBLOCKALL(&filter); |
780 | 0 | for (int j = 0; j < numICMPTypes; ++j) |
781 | 0 | { |
782 | 0 | ICMP6_FILTER_SETPASS(aICMPTypes[j], &filter); |
783 | 0 | } |
784 | 0 | } |
785 | 0 | else |
786 | 0 | { |
787 | 0 | ICMP6_FILTER_SETPASSALL(&filter); |
788 | 0 | } |
789 | 0 | if (setsockopt(mSocket, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)) == -1) |
790 | 0 | { |
791 | 0 | err = Weave::System::MapErrorPOSIX(errno); |
792 | 0 | } |
793 | 0 | #endif // HAVE_NETINET_ICMP6_H && HAVE_ICMP6_FILTER |
794 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
795 | |
|
796 | 0 | exit: |
797 | 0 | return err; |
798 | 0 | } |
799 | | |
800 | | /** |
801 | | * @brief Bind the endpoint to a network interface. |
802 | | * |
803 | | * @param[in] addrType the protocol version of the IP address. |
804 | | * |
805 | | * @param[in] intf indicator of the network interface. |
806 | | * |
807 | | * @retval INET_NO_ERROR success: endpoint bound to address |
808 | | * @retval INET_NO_MEMORY insufficient memory for endpoint |
809 | | * @retval INET_ERROR_NOT_IMPLEMENTED system implementation not complete. |
810 | | * |
811 | | * @retval INET_ERROR_UNKNOWN_INTERFACE |
812 | | * On some platforms, the interface is not present. |
813 | | * |
814 | | * @retval other another system or platform error |
815 | | * |
816 | | * @details |
817 | | * Binds the endpoint to the specified network interface IP address. |
818 | | * |
819 | | * On LwIP, this method must not be called with the LwIP stack lock |
820 | | * already acquired. |
821 | | */ |
822 | | INET_ERROR RawEndPoint::BindInterface(IPAddressType addrType, InterfaceId intfId) |
823 | 0 | { |
824 | 0 | INET_ERROR err = INET_NO_ERROR; |
825 | | |
826 | | //A lock is required because the LwIP thread may be referring to intf_filter, |
827 | | //while this code running in the Inet application is potentially modifying it. |
828 | | //NOTE: this only supports LwIP interfaces whose number is no bigger than 9. |
829 | |
|
830 | 0 | if (mState != kState_Ready && mState != kState_Bound) |
831 | 0 | return INET_ERROR_INCORRECT_STATE; |
832 | | |
833 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
834 | | LOCK_TCPIP_CORE(); |
835 | | |
836 | | // Make sure we have the appropriate type of PCB. |
837 | | err = GetPCB(addrType); |
838 | | SuccessOrExit(err); |
839 | | |
840 | | err = LwIPBindInterface(mRaw, intfId); |
841 | | |
842 | | UNLOCK_TCPIP_CORE(); |
843 | | |
844 | | SuccessOrExit(err); |
845 | | |
846 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
847 | | |
848 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
849 | | // Make sure we have the appropriate type of socket. |
850 | 0 | err = GetSocket(addrType); |
851 | 0 | SuccessOrExit(err); |
852 | | |
853 | 0 | err = IPEndPointBasis::BindInterface(addrType, intfId); |
854 | 0 | SuccessOrExit(err); |
855 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
856 | | |
857 | 0 | if (err == INET_NO_ERROR) |
858 | 0 | { |
859 | 0 | mState = kState_Bound; |
860 | 0 | } |
861 | |
|
862 | 0 | exit: |
863 | 0 | return err; |
864 | 0 | } |
865 | | |
866 | | void RawEndPoint::Init(InetLayer *inetLayer, IPVersion ipVer, IPProtocol ipProto) |
867 | 0 | { |
868 | 0 | IPEndPointBasis::Init(inetLayer); |
869 | |
|
870 | 0 | IPVer = ipVer; |
871 | 0 | IPProto = ipProto; |
872 | 0 | } |
873 | | |
874 | | /** |
875 | | * Get the bound interface on this endpoint. |
876 | | * |
877 | | * @return InterfaceId The bound interface id. |
878 | | */ |
879 | | InterfaceId RawEndPoint::GetBoundInterface(void) |
880 | 0 | { |
881 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
882 | | #if HAVE_LWIP_RAW_BIND_NETIF |
883 | | return netif_get_by_index(mRaw->netif_idx); |
884 | | #else |
885 | | return mRaw->intf_filter; |
886 | | #endif |
887 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
888 | |
|
889 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
890 | 0 | return mBoundIntfId; |
891 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
892 | 0 | } |
893 | | |
894 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
895 | | |
896 | | void RawEndPoint::HandleDataReceived(PacketBuffer *msg) |
897 | | { |
898 | | IPEndPointBasis::HandleDataReceived(msg); |
899 | | } |
900 | | |
901 | | INET_ERROR RawEndPoint::GetPCB(IPAddressType addrType) |
902 | | { |
903 | | INET_ERROR lRetval = INET_NO_ERROR; |
904 | | |
905 | | // IMPORTANT: This method MUST be called with the LwIP stack LOCKED! |
906 | | |
907 | | #if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5 |
908 | | if (mRaw == NULL) |
909 | | { |
910 | | switch (addrType) |
911 | | { |
912 | | case kIPAddressType_IPv6: |
913 | | #if INET_CONFIG_ENABLE_IPV4 |
914 | | case kIPAddressType_IPv4: |
915 | | #endif // INET_CONFIG_ENABLE_IPV4 |
916 | | mRaw = raw_new_ip_type(IPAddress::ToLwIPAddrType(addrType), IPProto); |
917 | | break; |
918 | | |
919 | | default: |
920 | | lRetval = INET_ERROR_WRONG_ADDRESS_TYPE; |
921 | | goto exit; |
922 | | } |
923 | | |
924 | | if (mRaw == NULL) |
925 | | { |
926 | | WeaveLogError(Inet, "raw_new_ip_type failed"); |
927 | | lRetval = INET_ERROR_NO_MEMORY; |
928 | | goto exit; |
929 | | } |
930 | | else |
931 | | { |
932 | | mLwIPEndPointType = kLwIPEndPointType_Raw; |
933 | | } |
934 | | } |
935 | | else |
936 | | { |
937 | | const lwip_ip_addr_type lLwIPAddrType = static_cast<lwip_ip_addr_type>(IP_GET_TYPE(&mRaw->local_ip)); |
938 | | |
939 | | switch (lLwIPAddrType) |
940 | | { |
941 | | case IPADDR_TYPE_V6: |
942 | | VerifyOrExit(addrType == kIPAddressType_IPv6, lRetval = INET_ERROR_WRONG_ADDRESS_TYPE); |
943 | | break; |
944 | | |
945 | | #if INET_CONFIG_ENABLE_IPV4 |
946 | | case IPADDR_TYPE_V4: |
947 | | VerifyOrExit(addrType == kIPAddressType_IPv4, lRetval = INET_ERROR_WRONG_ADDRESS_TYPE); |
948 | | break; |
949 | | #endif // INET_CONFIG_ENABLE_IPV4 |
950 | | |
951 | | default: |
952 | | break; |
953 | | } |
954 | | } |
955 | | #else // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5 |
956 | | if (mRaw == NULL) |
957 | | { |
958 | | if (IPVer == kIPVersion_6) |
959 | | { |
960 | | mRaw = raw_new_ip6(IPProto); |
961 | | if (mRaw != NULL) |
962 | | ip_set_option(mRaw, SOF_REUSEADDR); |
963 | | } |
964 | | #if INET_CONFIG_ENABLE_IPV4 |
965 | | else if (IPVer == kIPVersion_4) |
966 | | { |
967 | | mRaw = raw_new(IPProto); |
968 | | } |
969 | | #endif // INET_CONFIG_ENABLE_IPV4 |
970 | | else |
971 | | { |
972 | | lRetval = INET_ERROR_WRONG_ADDRESS_TYPE; |
973 | | goto exit; |
974 | | } |
975 | | |
976 | | if (mRaw == NULL) |
977 | | { |
978 | | WeaveLogError(Inet, "raw_new failed"); |
979 | | lRetval = INET_ERROR_NO_MEMORY; |
980 | | goto exit; |
981 | | } |
982 | | else |
983 | | { |
984 | | mLwIPEndPointType = kLwIPEndPointType_Raw; |
985 | | } |
986 | | } |
987 | | else |
988 | | { |
989 | | #if INET_CONFIG_ENABLE_IPV4 |
990 | | const IPAddressType pcbType = PCB_ISIPV6(mRaw) ? kIPAddressType_IPv6 : kIPAddressType_IPv4; |
991 | | #else // !INET_CONFIG_ENABLE_IPV4 |
992 | | const IPAddressType pcbType = kIPAddressType_IPv6; |
993 | | #endif // !INET_CONFIG_ENABLE_IPV4 |
994 | | |
995 | | if (addrType != pcbType) { |
996 | | lRetval = INET_ERROR_WRONG_ADDRESS_TYPE; |
997 | | goto exit; |
998 | | } |
999 | | } |
1000 | | #endif // LWIP_VERSION_MAJOR <= 1 || LWIP_VERSION_MINOR >= 5 |
1001 | | |
1002 | | exit: |
1003 | | return (lRetval); |
1004 | | } |
1005 | | |
1006 | | /* This function is executed when a raw_pcb is listening and an IP datagram (v4 or v6) is received. |
1007 | | * NOTE: currently ICMPv4 filtering is currently not implemented, but it can easily be added later. |
1008 | | * This fn() may be executed concurrently with SetICMPFilter() |
1009 | | * - this fn() runs in the LwIP thread (and the lock has already been taken) |
1010 | | * - SetICMPFilter() runs in the Inet thread. |
1011 | | */ |
1012 | | #if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5 |
1013 | | u8_t RawEndPoint::LwIPReceiveRawMessage(void *arg, struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *addr) |
1014 | | #else // LWIP_VERSION_MAJOR <= 1 && LWIP_VERSION_MINOR < 5 |
1015 | | u8_t RawEndPoint::LwIPReceiveRawMessage(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr) |
1016 | | #endif // LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5 |
1017 | | { |
1018 | | RawEndPoint* ep = static_cast<RawEndPoint*>(arg); |
1019 | | PacketBuffer* buf = reinterpret_cast<PacketBuffer*>(static_cast<void*>(p)); |
1020 | | Weave::System::Layer& lSystemLayer = ep->SystemLayer(); |
1021 | | IPPacketInfo* pktInfo = NULL; |
1022 | | uint8_t enqueue = 1; |
1023 | | |
1024 | | //Filtering based on the saved ICMP6 types (the only protocol currently supported.) |
1025 | | if ((ep->IPVer == kIPVersion_6) && |
1026 | | (ep->IPProto == kIPProtocol_ICMPv6)) |
1027 | | { |
1028 | | if (ep->NumICMPTypes > 0) |
1029 | | { //When no filter is defined, let all ICMPv6 packets pass |
1030 | | //The type is the first 8 bits field of an ICMP (v4 or v6) packet |
1031 | | uint8_t icmp_type = *(buf->Start() + ip_current_header_tot_len()); |
1032 | | uint8_t icmp_type_found = 0; |
1033 | | for (int j = 0; j < ep->NumICMPTypes; ++j) |
1034 | | { |
1035 | | if (ep->ICMPTypes[j] == icmp_type) |
1036 | | { |
1037 | | icmp_type_found = 1; |
1038 | | break; |
1039 | | } |
1040 | | } |
1041 | | if ( !icmp_type_found ) |
1042 | | { |
1043 | | enqueue = 0; //do not eat it |
1044 | | } |
1045 | | } |
1046 | | } |
1047 | | |
1048 | | if (enqueue) |
1049 | | { |
1050 | | pktInfo = GetPacketInfo(buf); |
1051 | | |
1052 | | if (pktInfo != NULL) |
1053 | | { |
1054 | | #if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5 |
1055 | | pktInfo->SrcAddress = IPAddress::FromLwIPAddr(*addr); |
1056 | | pktInfo->DestAddress = IPAddress::FromLwIPAddr(*ip_current_dest_addr()); |
1057 | | #else // LWIP_VERSION_MAJOR <= 1 |
1058 | | if (PCB_ISIPV6(pcb)) |
1059 | | { |
1060 | | pktInfo->SrcAddress = IPAddress::FromIPv6(*(ip6_addr_t *)addr); |
1061 | | pktInfo->DestAddress = IPAddress::FromIPv6(*ip6_current_dest_addr()); |
1062 | | } |
1063 | | #if INET_CONFIG_ENABLE_IPV4 |
1064 | | else |
1065 | | { |
1066 | | pktInfo->SrcAddress = IPAddress::FromIPv4(*addr); |
1067 | | pktInfo->DestAddress = IPAddress::FromIPv4(*ip_current_dest_addr()); |
1068 | | } |
1069 | | #endif // INET_CONFIG_ENABLE_IPV4 |
1070 | | #endif // LWIP_VERSION_MAJOR <= 1 |
1071 | | |
1072 | | pktInfo->Interface = ip_current_netif(); |
1073 | | pktInfo->SrcPort = 0; |
1074 | | pktInfo->DestPort = 0; |
1075 | | } |
1076 | | |
1077 | | if (lSystemLayer.PostEvent(*ep, kInetEvent_RawDataReceived, (uintptr_t)buf) != INET_NO_ERROR) |
1078 | | PacketBuffer::Free(buf); |
1079 | | } |
1080 | | |
1081 | | return enqueue; |
1082 | | } |
1083 | | |
1084 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
1085 | | |
1086 | | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
1087 | | INET_ERROR RawEndPoint::GetSocket(IPAddressType aAddressType) |
1088 | 0 | { |
1089 | 0 | INET_ERROR lRetval = INET_NO_ERROR; |
1090 | 0 | const int lType = (SOCK_RAW | SOCK_FLAGS); |
1091 | 0 | int lProtocol; |
1092 | |
|
1093 | 0 | switch (aAddressType) |
1094 | 0 | { |
1095 | 0 | case kIPAddressType_IPv6: |
1096 | 0 | lProtocol = IPPROTO_ICMPV6; |
1097 | 0 | break; |
1098 | | |
1099 | 0 | #if INET_CONFIG_ENABLE_IPV4 |
1100 | 0 | case kIPAddressType_IPv4: |
1101 | 0 | lProtocol = IPPROTO_ICMP; |
1102 | 0 | break; |
1103 | 0 | #endif // INET_CONFIG_ENABLE_IPV4 |
1104 | | |
1105 | 0 | default: |
1106 | 0 | lRetval = INET_ERROR_WRONG_ADDRESS_TYPE; |
1107 | 0 | goto exit; |
1108 | 0 | } |
1109 | | |
1110 | 0 | lRetval = IPEndPointBasis::GetSocket(aAddressType, lType, lProtocol); |
1111 | 0 | SuccessOrExit(lRetval); |
1112 | | |
1113 | 0 | exit: |
1114 | 0 | return (lRetval); |
1115 | 0 | } |
1116 | | |
1117 | | SocketEvents RawEndPoint::PrepareIO(void) |
1118 | 0 | { |
1119 | 0 | return (IPEndPointBasis::PrepareIO()); |
1120 | 0 | } |
1121 | | |
1122 | | void RawEndPoint::HandlePendingIO(void) |
1123 | 0 | { |
1124 | 0 | if (mState == kState_Listening && OnMessageReceived != NULL && mPendingIO.IsReadable()) |
1125 | 0 | { |
1126 | 0 | const uint16_t lPort = 0; |
1127 | |
|
1128 | 0 | IPEndPointBasis::HandlePendingIO(lPort); |
1129 | 0 | } |
1130 | |
|
1131 | 0 | mPendingIO.Clear(); |
1132 | 0 | } |
1133 | | |
1134 | | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
1135 | | |
1136 | | } // namespace Inet |
1137 | | } // namespace nl |