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