59
59
#define MLDREPORT_V2 ((FAR struct mld_mcast_listen_report_v2_s *)icmpv6)
60
60
#define MLDDONE ((FAR struct mld_mcast_listen_done_s *)icmpv6)
61
61
62
+ #ifdef CONFIG_NET_ICMPv6_SOCKET
63
+
64
+ /****************************************************************************
65
+ * Private Types
66
+ ****************************************************************************/
67
+
68
+ struct icmpv6_deliver_s
69
+ {
70
+ FAR struct net_driver_s * dev ; /* Current network device */
71
+ unsigned int iplen ; /* The size of the IPv6 header */
72
+ bool delivered ; /* Whether the message is delivered */
73
+ };
74
+
62
75
/****************************************************************************
63
76
* Private Functions
64
77
****************************************************************************/
65
78
79
+ static bool icmpv6_filter (FAR const uint32_t * data , uint8_t type )
80
+ {
81
+ /* We require only the four bytes of the ICMPv6 header. */
82
+
83
+ DEBUGASSERT (data != NULL );
84
+
85
+ return (data [type >> 5 ] & (1u << (type & 31 ))) != 0 ;
86
+ }
87
+
66
88
/****************************************************************************
67
89
* Name: icmpv6_datahandler
68
90
*
82
104
*
83
105
****************************************************************************/
84
106
85
- #ifdef CONFIG_NET_ICMPv6_SOCKET
86
107
static uint16_t icmpv6_datahandler (FAR struct net_driver_s * dev ,
87
108
FAR struct icmpv6_conn_s * conn ,
88
109
unsigned int iplen )
@@ -93,9 +114,14 @@ static uint16_t icmpv6_datahandler(FAR struct net_driver_s *dev,
93
114
uint16_t buflen ;
94
115
int ret ;
95
116
117
+ iob = iob_tryalloc (false);
118
+ if (iob == NULL )
119
+ {
120
+ return - ENOMEM ;
121
+ }
122
+
96
123
/* Put the IPv6 address at the beginning of the read-ahead buffer */
97
124
98
- iob = dev -> d_iob ;
99
125
ipv6 = IPv6BUF ;
100
126
inaddr .sin6_family = AF_INET6 ;
101
127
inaddr .sin6_port = 0 ;
@@ -107,13 +133,19 @@ static uint16_t icmpv6_datahandler(FAR struct net_driver_s *dev,
107
133
108
134
memcpy (iob -> io_data , & inaddr , sizeof (struct sockaddr_in6 ));
109
135
110
- /* Copy the new ICMPv6 reply into the I/O buffer chain (without waiting) */
136
+ iob_reserve ( iob , sizeof ( struct sockaddr_in6 ));
111
137
112
- buflen = ICMPv6SIZE ;
138
+ /* Copy the ICMPv6 message into the I/O buffer chain (without waiting) */
113
139
114
- /* Trim l3 header */
140
+ ret = iob_clone_partial (dev -> d_iob , dev -> d_iob -> io_pktlen ,
141
+ iplen , iob , 0 , true, false);
142
+ if (ret < 0 )
143
+ {
144
+ iob_free_chain (iob );
145
+ return ret ;
146
+ }
115
147
116
- iob = iob_trimhead ( iob , iplen ) ;
148
+ buflen = ICMPv6SIZE ;
117
149
118
150
/* Add the new I/O buffer chain to the tail of the read-ahead queue (again
119
151
* without waiting).
@@ -130,12 +162,81 @@ static uint16_t icmpv6_datahandler(FAR struct net_driver_s *dev,
130
162
ninfo ("Buffered %d bytes\n" , buflen );
131
163
}
132
164
133
- /* Device buffer must be enqueue or freed, clear the handle */
134
-
135
- netdev_iob_clear (dev );
136
165
return buflen ;
137
166
}
138
- #endif
167
+
168
+ /****************************************************************************
169
+ * Name: icmpv6_delivery_callback
170
+ *
171
+ * Description:
172
+ * Copy the icmpv6 package to the application according to the filter
173
+ * conditions, but ICMPv6_ECHO_REPLY is a special message type, if there
174
+ * is an application waiting, it will also copy.
175
+ *
176
+ * Input Parameters:
177
+ * conn - A pointer to the ICMPv6 connection structure.
178
+ * arg - The context information
179
+ *
180
+ ****************************************************************************/
181
+
182
+ static int icmpv6_delivery_callback (FAR struct icmpv6_conn_s * conn ,
183
+ FAR void * arg )
184
+ {
185
+ FAR struct icmpv6_deliver_s * info = arg ;
186
+ FAR struct net_driver_s * dev = info -> dev ;
187
+ FAR struct icmpv6_hdr_s * icmpv6 = IPBUF (info -> iplen );
188
+
189
+ if (icmpv6_filter (conn -> filter .icmp6_filt , icmpv6 -> type ) &&
190
+ (icmpv6 -> type != ICMPv6_ECHO_REPLY || conn -> id != ICMPv6REPLY -> id ||
191
+ conn -> dev != dev ))
192
+ {
193
+ return 0 ;
194
+ }
195
+
196
+ info -> delivered = true;
197
+ if (devif_conn_event (dev , ICMPv6_NEWDATA , conn -> sconn .list ) !=
198
+ ICMPv6_NEWDATA )
199
+ {
200
+ dev -> d_len = dev -> d_iob -> io_pktlen ;
201
+ }
202
+ else
203
+ {
204
+ icmpv6_datahandler (dev , conn , info -> iplen );
205
+ }
206
+
207
+ return 0 ;
208
+ }
209
+
210
+ /****************************************************************************
211
+ * Name: icmpv6_deliver
212
+ *
213
+ * Description:
214
+ * Copy the icmpv6 package to the application according to the filter
215
+ * conditions, but ICMPv6_ECHO_REPLY is a special message type, if there
216
+ * is an application waiting, it will also copy.
217
+ *
218
+ * Input Parameters:
219
+ * dev - Reference to a device driver structure.
220
+ * iplen - The size of the IPv6 header. This may be larger than
221
+ * IPv6_HDRLEN the IPv6 header if IPv6 extension headers are
222
+ * present.
223
+ *
224
+ ****************************************************************************/
225
+
226
+ static bool icmpv6_deliver (FAR struct net_driver_s * dev , unsigned int iplen )
227
+ {
228
+ struct icmpv6_deliver_s info ;
229
+
230
+ info .dev = dev ;
231
+ info .iplen = iplen ;
232
+ info .delivered = false;
233
+
234
+ icmpv6_foreach (icmpv6_delivery_callback , & info );
235
+
236
+ return info .delivered ;
237
+ }
238
+
239
+ #endif /* CONFIG_NET_ICMPv6_SOCKET */
139
240
140
241
/****************************************************************************
141
242
* Public Functions
@@ -166,6 +267,9 @@ void icmpv6_input(FAR struct net_driver_s *dev, unsigned int iplen)
166
267
{
167
268
FAR struct ipv6_hdr_s * ipv6 = IPv6BUF ;
168
269
FAR struct icmpv6_hdr_s * icmpv6 = IPBUF (iplen );
270
+ #ifdef CONFIG_NET_ICMPv6_SOCKET
271
+ bool delivered = icmpv6_deliver (dev , iplen );
272
+ #endif
169
273
170
274
#ifdef CONFIG_NET_STATISTICS
171
275
g_netstats .icmpv6 .recv ++ ;
@@ -443,61 +547,6 @@ void icmpv6_input(FAR struct net_driver_s *dev, unsigned int iplen)
443
547
}
444
548
break ;
445
549
446
- #ifdef CONFIG_NET_ICMPv6_SOCKET
447
- /* If an ICMPv6 echo reply is received then there should also be
448
- * a thread waiting to received the echo response.
449
- */
450
-
451
- case ICMPv6_ECHO_REPLY :
452
- {
453
- FAR struct icmpv6_echo_reply_s * reply ;
454
- FAR struct icmpv6_conn_s * conn ;
455
- uint16_t flags = ICMPv6_NEWDATA ;
456
-
457
- /* Nothing consumed the ICMP reply. That might be because this is
458
- * an old, invalid reply or simply because the ping application
459
- * has not yet put its poll or recv in place.
460
- */
461
-
462
- /* Is there any connection that might expect this reply? */
463
-
464
- reply = ICMPv6REPLY ;
465
- conn = icmpv6_findconn (dev , reply -> id );
466
- if (conn == NULL )
467
- {
468
- /* No.. drop the packet */
469
-
470
- goto icmpv6_drop_packet ;
471
- }
472
-
473
- /* Dispatch the ECHO reply to the waiting thread */
474
-
475
- flags = devif_conn_event (dev , flags , conn -> sconn .list );
476
-
477
- /* Was the ECHO reply consumed by any waiting thread? */
478
-
479
- if ((flags & ICMPv6_NEWDATA ) != 0 )
480
- {
481
- uint16_t nbuffered ;
482
-
483
- /* Yes.. Add the ICMP echo reply to the IPPROTO_ICMP socket read
484
- * ahead buffer.
485
- */
486
-
487
- nbuffered = icmpv6_datahandler (dev , conn , iplen );
488
- if (nbuffered == 0 )
489
- {
490
- /* Could not buffer the data.. drop the packet */
491
-
492
- goto icmpv6_drop_packet ;
493
- }
494
- }
495
-
496
- goto icmpv6_send_nothing ;
497
- }
498
- break ;
499
- #endif
500
-
501
550
#ifdef CONFIG_NET_MLD
502
551
/* Dispatch received Multicast Listener Discovery (MLD) packets. */
503
552
@@ -556,6 +605,13 @@ void icmpv6_input(FAR struct net_driver_s *dev, unsigned int iplen)
556
605
557
606
default :
558
607
{
608
+ #ifdef CONFIG_NET_ICMPv6_SOCKET
609
+ if (delivered )
610
+ {
611
+ goto icmpv6_send_nothing ;
612
+ }
613
+ #endif
614
+
559
615
nwarn ("WARNING: Unknown ICMPv6 type: %d\n" , icmpv6 -> type );
560
616
goto icmpv6_type_error ;
561
617
}
0 commit comments