@@ -11,6 +11,24 @@ use crate::socket::AnySocket;
11
11
use crate :: phy:: PacketMeta ;
12
12
use crate :: wire:: * ;
13
13
14
+ /// Enum used for the process_hopbyhop function. In some cases, when discarding a packet, an ICMMP
15
+ /// parameter problem message needs to be transmitted to the source of the address. In other cases,
16
+ /// the processing of the IP packet can continue.
17
+ #[ allow( clippy:: large_enum_variant) ]
18
+ enum HopByHopResponse < ' frame > {
19
+ /// Continue processing the IPv6 packet.
20
+ Continue ( ( IpProtocol , & ' frame [ u8 ] ) ) ,
21
+ /// Discard the packet and maybe send back an ICMPv6 packet.
22
+ Discard ( Option < IpPacket < ' frame > > ) ,
23
+ }
24
+
25
+ // We implement `Default` such that we can use the check! macro.
26
+ impl Default for HopByHopResponse < ' _ > {
27
+ fn default ( ) -> Self {
28
+ Self :: Discard ( None )
29
+ }
30
+ }
31
+
14
32
impl InterfaceInner {
15
33
pub ( super ) fn process_ipv6 < ' frame > (
16
34
& mut self ,
@@ -26,7 +44,19 @@ impl InterfaceInner {
26
44
return None ;
27
45
}
28
46
29
- let ip_payload = ipv6_packet. payload ( ) ;
47
+ let ( next_header, ip_payload) = if ipv6_repr. next_header == IpProtocol :: HopByHop {
48
+ match self . process_hopbyhop ( ipv6_repr, ipv6_packet. payload ( ) ) {
49
+ HopByHopResponse :: Discard ( e) => return e,
50
+ HopByHopResponse :: Continue ( next) => next,
51
+ }
52
+ } else {
53
+ ( ipv6_repr. next_header , ipv6_packet. payload ( ) )
54
+ } ;
55
+
56
+ if !self . has_ip_addr ( ipv6_repr. dst_addr ) && !self . has_multicast_group ( ipv6_repr. dst_addr ) {
57
+ net_trace ! ( "packet IP address not for this interface" ) ;
58
+ return None ;
59
+ }
30
60
31
61
#[ cfg( feature = "socket-raw" ) ]
32
62
let handled_by_raw_socket = self . raw_socket_filter ( sockets, & ipv6_repr. into ( ) , ip_payload) ;
@@ -37,15 +67,71 @@ impl InterfaceInner {
37
67
sockets,
38
68
meta,
39
69
ipv6_repr,
40
- ipv6_repr . next_header ,
70
+ next_header,
41
71
handled_by_raw_socket,
42
72
ip_payload,
43
73
)
44
74
}
45
75
76
+ fn process_hopbyhop < ' frame > (
77
+ & mut self ,
78
+ ipv6_repr : Ipv6Repr ,
79
+ ip_payload : & ' frame [ u8 ] ,
80
+ ) -> HopByHopResponse < ' frame > {
81
+ let param_problem = || {
82
+ let payload_len =
83
+ icmp_reply_payload_len ( ip_payload. len ( ) , IPV6_MIN_MTU , ipv6_repr. buffer_len ( ) ) ;
84
+ self . icmpv6_reply (
85
+ ipv6_repr,
86
+ Icmpv6Repr :: ParamProblem {
87
+ reason : Icmpv6ParamProblem :: UnrecognizedOption ,
88
+ pointer : ipv6_repr. buffer_len ( ) as u32 ,
89
+ header : ipv6_repr,
90
+ data : & ip_payload[ 0 ..payload_len] ,
91
+ } ,
92
+ )
93
+ } ;
94
+
95
+ let ext_hdr = check ! ( Ipv6ExtHeader :: new_checked( ip_payload) ) ;
96
+ let ext_repr = check ! ( Ipv6ExtHeaderRepr :: parse( & ext_hdr) ) ;
97
+ let hbh_hdr = check ! ( Ipv6HopByHopHeader :: new_checked( ext_repr. data) ) ;
98
+ let hbh_repr = check ! ( Ipv6HopByHopRepr :: parse( & hbh_hdr) ) ;
99
+
100
+ for opt_repr in & hbh_repr. options {
101
+ match opt_repr {
102
+ Ipv6OptionRepr :: Pad1 | Ipv6OptionRepr :: PadN ( _) => ( ) ,
103
+ #[ cfg( feature = "proto-rpl" ) ]
104
+ Ipv6OptionRepr :: Rpl ( _) => { }
105
+
106
+ Ipv6OptionRepr :: Unknown { type_, .. } => {
107
+ match Ipv6OptionFailureType :: from ( * type_) {
108
+ Ipv6OptionFailureType :: Skip => ( ) ,
109
+ Ipv6OptionFailureType :: Discard => {
110
+ return HopByHopResponse :: Discard ( None ) ;
111
+ }
112
+ Ipv6OptionFailureType :: DiscardSendAll => {
113
+ return HopByHopResponse :: Discard ( param_problem ( ) ) ;
114
+ }
115
+ Ipv6OptionFailureType :: DiscardSendUnicast
116
+ if !ipv6_repr. dst_addr . is_multicast ( ) =>
117
+ {
118
+ return HopByHopResponse :: Discard ( param_problem ( ) ) ;
119
+ }
120
+ _ => unreachable ! ( ) ,
121
+ }
122
+ }
123
+ }
124
+ }
125
+
126
+ HopByHopResponse :: Continue ( (
127
+ ext_repr. next_header ,
128
+ & ip_payload[ ext_repr. header_len ( ) + ext_repr. data . len ( ) ..] ,
129
+ ) )
130
+ }
131
+
46
132
/// Given the next header value forward the payload onto the correct process
47
133
/// function.
48
- pub ( super ) fn process_nxt_hdr < ' frame > (
134
+ fn process_nxt_hdr < ' frame > (
49
135
& mut self ,
50
136
sockets : & mut SocketSet ,
51
137
meta : PacketMeta ,
@@ -81,10 +167,6 @@ impl InterfaceInner {
81
167
#[ cfg( feature = "socket-tcp" ) ]
82
168
IpProtocol :: Tcp => self . process_tcp ( sockets, ipv6_repr. into ( ) , ip_payload) ,
83
169
84
- IpProtocol :: HopByHop => {
85
- self . process_hopbyhop ( sockets, meta, ipv6_repr, handled_by_raw_socket, ip_payload)
86
- }
87
-
88
170
#[ cfg( feature = "socket-raw" ) ]
89
171
_ if handled_by_raw_socket => None ,
90
172
@@ -235,70 +317,27 @@ impl InterfaceInner {
235
317
}
236
318
}
237
319
238
- pub ( super ) fn process_hopbyhop < ' frame > (
239
- & mut self ,
240
- sockets : & mut SocketSet ,
241
- meta : PacketMeta ,
242
- ipv6_repr : Ipv6Repr ,
243
- handled_by_raw_socket : bool ,
244
- ip_payload : & ' frame [ u8 ] ,
245
- ) -> Option < IpPacket < ' frame > > {
246
- let ext_hdr = check ! ( Ipv6ExtHeader :: new_checked( ip_payload) ) ;
247
- let ext_repr = check ! ( Ipv6ExtHeaderRepr :: parse( & ext_hdr) ) ;
248
- let hbh_hdr = check ! ( Ipv6HopByHopHeader :: new_checked( ext_repr. data) ) ;
249
- let hbh_repr = check ! ( Ipv6HopByHopRepr :: parse( & hbh_hdr) ) ;
250
-
251
- for opt_repr in & hbh_repr. options {
252
- match opt_repr {
253
- Ipv6OptionRepr :: Pad1 | Ipv6OptionRepr :: PadN ( _) => ( ) ,
254
- #[ cfg( feature = "proto-rpl" ) ]
255
- Ipv6OptionRepr :: Rpl ( _) => { }
256
-
257
- Ipv6OptionRepr :: Unknown { type_, .. } => {
258
- match Ipv6OptionFailureType :: from ( * type_) {
259
- Ipv6OptionFailureType :: Skip => ( ) ,
260
- Ipv6OptionFailureType :: Discard => {
261
- return None ;
262
- }
263
- _ => {
264
- // FIXME(dlrobertson): Send an ICMPv6 parameter problem message
265
- // here.
266
- return None ;
267
- }
268
- }
269
- }
270
- }
271
- }
272
- self . process_nxt_hdr (
273
- sockets,
274
- meta,
275
- ipv6_repr,
276
- ext_repr. next_header ,
277
- handled_by_raw_socket,
278
- & ip_payload[ ext_repr. header_len ( ) + ext_repr. data . len ( ) ..] ,
279
- )
280
- }
281
-
282
320
pub ( super ) fn icmpv6_reply < ' frame , ' icmp : ' frame > (
283
321
& self ,
284
322
ipv6_repr : Ipv6Repr ,
285
323
icmp_repr : Icmpv6Repr < ' icmp > ,
286
324
) -> Option < IpPacket < ' frame > > {
287
- if ipv6_repr. dst_addr . is_unicast ( ) {
288
- let ipv6_reply_repr = Ipv6Repr {
289
- src_addr : ipv6_repr. dst_addr ,
290
- dst_addr : ipv6_repr. src_addr ,
291
- next_header : IpProtocol :: Icmpv6 ,
292
- payload_len : icmp_repr. buffer_len ( ) ,
293
- hop_limit : 64 ,
294
- } ;
295
- Some ( IpPacket :: new_ipv6 (
296
- ipv6_reply_repr,
297
- IpPayload :: Icmpv6 ( icmp_repr) ,
298
- ) )
325
+ let src_addr = if ipv6_repr. dst_addr . is_unicast ( ) {
326
+ ipv6_repr. dst_addr
299
327
} else {
300
- // Do not send any ICMP replies to a broadcast destination address.
301
- None
302
- }
328
+ self . ipv6_addr ( ) . unwrap ( )
329
+ } ;
330
+
331
+ let ipv6_reply_repr = Ipv6Repr {
332
+ src_addr,
333
+ dst_addr : ipv6_repr. src_addr ,
334
+ next_header : IpProtocol :: Icmpv6 ,
335
+ payload_len : icmp_repr. buffer_len ( ) ,
336
+ hop_limit : 64 ,
337
+ } ;
338
+ Some ( IpPacket :: new_ipv6 (
339
+ ipv6_reply_repr,
340
+ IpPayload :: Icmpv6 ( icmp_repr) ,
341
+ ) )
303
342
}
304
343
}
0 commit comments