1use super::*;
2
3impl Interface {
4 #[cfg(feature = "proto-ipv4-fragmentation")]
10 pub(super) fn ipv4_egress(&mut self, device: &mut (impl Device + ?Sized)) {
11 if self.fragmenter.finished() {
13 self.fragmenter.reset();
14 }
15
16 if self.fragmenter.is_empty() {
17 return;
18 }
19
20 let pkt = &self.fragmenter;
21 if pkt.packet_len > pkt.sent_bytes
22 && let Some(tx_token) = device.transmit(self.inner.now)
23 {
24 self.inner
25 .dispatch_ipv4_frag(tx_token, &mut self.fragmenter);
26 }
27 }
28}
29
30impl InterfaceInner {
31 #[cfg(feature = "proto-ipv4-fragmentation")]
33 pub(super) fn next_ipv4_frag_ident(&mut self) -> u16 {
34 let ipv4_id = self.ipv4_id;
35 self.ipv4_id = self.ipv4_id.wrapping_add(1);
36 ipv4_id
37 }
38
39 #[allow(unused)]
45 pub(crate) fn get_source_address_ipv4(&self, dst_addr: &Ipv4Address) -> Option<Ipv4Address> {
46 let mut first_ipv4 = None;
47 for cidr in self.ip_addrs.iter() {
48 #[allow(irrefutable_let_patterns)] if let IpCidr::Ipv4(cidr) = cidr {
50 if cidr.contains_addr(dst_addr) {
52 return Some(cidr.address());
53 }
54
55 if first_ipv4.is_none() {
57 first_ipv4 = Some(cidr.address());
58 }
59 }
60 }
61 first_ipv4
62 }
63
64 pub(crate) fn is_broadcast_v4(&self, address: Ipv4Address) -> bool {
67 if address.is_broadcast() {
68 return true;
69 }
70
71 self.ip_addrs
72 .iter()
73 .filter_map(|own_cidr| match own_cidr {
74 IpCidr::Ipv4(own_ip) => Some(own_ip.broadcast()?),
75 #[cfg(feature = "proto-ipv6")]
76 IpCidr::Ipv6(_) => None,
77 })
78 .any(|broadcast_address| address == broadcast_address)
79 }
80
81 fn is_unicast_v4(&self, address: Ipv4Address) -> bool {
83 address.x_is_unicast() && !self.is_broadcast_v4(address)
84 }
85
86 pub fn ipv4_addr(&self) -> Option<Ipv4Address> {
88 self.ip_addrs.iter().find_map(|addr| match *addr {
89 IpCidr::Ipv4(cidr) => Some(cidr.address()),
90 #[allow(unreachable_patterns)]
91 _ => None,
92 })
93 }
94
95 pub(super) fn process_ipv4<'a>(
96 &mut self,
97 sockets: &mut SocketSet,
98 meta: PacketMeta,
99 source_hardware_addr: HardwareAddress,
100 ipv4_packet: &Ipv4Packet<&'a [u8]>,
101 frag: &'a mut FragmentsBuffer,
102 ) -> Option<Packet<'a>> {
103 let mut ipv4_repr = check!(Ipv4Repr::parse(ipv4_packet, &self.caps.checksum));
104 if !self.is_unicast_v4(ipv4_repr.src_addr) && !ipv4_repr.src_addr.is_unspecified() {
105 net_debug!("non-unicast or unspecified source address");
107 return None;
108 }
109
110 #[cfg(feature = "proto-ipv4-fragmentation")]
111 let ip_payload = {
112 if ipv4_packet.more_frags() || ipv4_packet.frag_offset() != 0 {
113 let key = FragKey::Ipv4(ipv4_packet.get_key());
114
115 let f = match frag.assembler.get(&key, self.now + frag.reassembly_timeout) {
116 Ok(f) => f,
117 Err(_) => {
118 net_debug!("No available packet assembler for fragmented packet");
119 return None;
120 }
121 };
122
123 if !ipv4_packet.more_frags() {
124 check!(f.set_total_size(
126 ipv4_packet.total_len() as usize - ipv4_packet.header_len() as usize
127 + ipv4_packet.frag_offset() as usize,
128 ));
129 }
130
131 if let Err(e) = f.add(ipv4_packet.payload(), ipv4_packet.frag_offset() as usize) {
132 net_debug!("fragmentation error: {:?}", e);
133 return None;
134 }
135
136 let payload = f.assemble()?;
137 ipv4_repr.payload_len = payload.len();
139 payload
140 } else {
141 ipv4_packet.payload()
142 }
143 };
144
145 #[cfg(not(feature = "proto-ipv4-fragmentation"))]
146 let ip_payload = ipv4_packet.payload();
147
148 let ip_repr = IpRepr::Ipv4(ipv4_repr);
149
150 #[cfg(feature = "socket-raw")]
151 let handled_by_raw_socket = self.raw_socket_filter(sockets, &ip_repr, ip_payload);
152 #[cfg(not(feature = "socket-raw"))]
153 let handled_by_raw_socket = false;
154
155 #[cfg(feature = "socket-dhcpv4")]
156 {
157 use crate::socket::dhcpv4::Socket as Dhcpv4Socket;
158
159 if ipv4_repr.next_header == IpProtocol::Udp
160 && matches!(self.caps.medium, Medium::Ethernet)
161 {
162 let udp_packet = check!(UdpPacket::new_checked(ip_payload));
163 if let Some(dhcp_socket) = sockets
164 .items_mut()
165 .find_map(|i| Dhcpv4Socket::downcast_mut(&mut i.socket))
166 {
167 if udp_packet.src_port() == dhcp_socket.server_port
170 && udp_packet.dst_port() == dhcp_socket.client_port
171 {
172 let udp_repr = check!(UdpRepr::parse(
173 &udp_packet,
174 &ipv4_repr.src_addr.into(),
175 &ipv4_repr.dst_addr.into(),
176 &self.caps.checksum
177 ));
178 dhcp_socket.process(self, &ipv4_repr, &udp_repr, udp_packet.payload());
179 return None;
180 }
181 }
182 }
183 }
184
185 if !self.has_ip_addr(ipv4_repr.dst_addr)
186 && !self.has_multicast_group(ipv4_repr.dst_addr)
187 && !self.is_broadcast_v4(ipv4_repr.dst_addr)
188 {
189 if !ipv4_repr.dst_addr.x_is_unicast() {
192 net_trace!(
193 "Rejecting IPv4 packet; {} is not a unicast address",
194 ipv4_repr.dst_addr
195 );
196 return None;
197 }
198
199 if self
200 .routes
201 .lookup(&IpAddress::Ipv4(ipv4_repr.dst_addr), self.now)
202 .is_none_or(|router_addr| !self.has_ip_addr(router_addr))
203 {
204 net_trace!("Rejecting IPv4 packet; no matching routes");
205
206 return None;
207 }
208
209 net_trace!("Rejecting IPv4 packet; no assigned address");
210 return None;
211 }
212
213 #[cfg(feature = "medium-ethernet")]
214 if self.is_unicast_v4(ipv4_repr.dst_addr) {
215 self.neighbor_cache.reset_expiry_if_existing(
216 IpAddress::Ipv4(ipv4_repr.src_addr),
217 source_hardware_addr,
218 self.now,
219 );
220 }
221
222 match ipv4_repr.next_header {
223 IpProtocol::Icmp => self.process_icmpv4(sockets, ipv4_repr, ip_payload),
224
225 #[cfg(feature = "multicast")]
226 IpProtocol::Igmp => self.process_igmp(ipv4_repr, ip_payload),
227
228 #[cfg(any(feature = "socket-udp", feature = "socket-dns"))]
229 IpProtocol::Udp => {
230 self.process_udp(sockets, meta, handled_by_raw_socket, ip_repr, ip_payload)
231 }
232
233 #[cfg(feature = "socket-tcp")]
234 IpProtocol::Tcp => {
235 self.process_tcp(sockets, handled_by_raw_socket, ip_repr, ip_payload)
236 }
237
238 _ if handled_by_raw_socket => None,
239
240 _ => {
241 let payload_len =
243 icmp_reply_payload_len(ip_payload.len(), IPV4_MIN_MTU, ipv4_repr.buffer_len());
244 let icmp_reply_repr = Icmpv4Repr::DstUnreachable {
245 reason: Icmpv4DstUnreachable::ProtoUnreachable,
246 header: ipv4_repr,
247 data: &ip_payload[0..payload_len],
248 };
249 self.icmpv4_reply(ipv4_repr, icmp_reply_repr)
250 }
251 }
252 }
253
254 #[cfg(feature = "medium-ethernet")]
255 pub(super) fn process_arp<'frame>(
256 &mut self,
257 timestamp: Instant,
258 eth_frame: &EthernetFrame<&'frame [u8]>,
259 ) -> Option<EthernetPacket<'frame>> {
260 let arp_packet = check!(ArpPacket::new_checked(eth_frame.payload()));
261 let arp_repr = check!(ArpRepr::parse(&arp_packet));
262
263 match arp_repr {
264 ArpRepr::EthernetIpv4 {
265 operation,
266 source_hardware_addr,
267 source_protocol_addr,
268 target_protocol_addr,
269 ..
270 } => {
271 if !self.has_ip_addr(target_protocol_addr) {
273 return None;
274 }
275
276 if let ArpOperation::Unknown(_) = operation {
278 net_debug!("arp: unknown operation code");
279 return None;
280 }
281
282 if !source_protocol_addr.x_is_unicast() || !source_hardware_addr.is_unicast() {
284 net_debug!("arp: non-unicast source address");
285 return None;
286 }
287
288 if !self.in_same_network(&IpAddress::Ipv4(source_protocol_addr)) {
289 net_debug!("arp: source IP address not in same network as us");
290 return None;
291 }
292
293 self.neighbor_cache.fill(
298 source_protocol_addr.into(),
299 source_hardware_addr.into(),
300 timestamp,
301 );
302
303 if operation == ArpOperation::Request {
304 let src_hardware_addr = self.hardware_addr.ethernet_or_panic();
305
306 Some(EthernetPacket::Arp(ArpRepr::EthernetIpv4 {
307 operation: ArpOperation::Reply,
308 source_hardware_addr: src_hardware_addr,
309 source_protocol_addr: target_protocol_addr,
310 target_hardware_addr: source_hardware_addr,
311 target_protocol_addr: source_protocol_addr,
312 }))
313 } else {
314 None
315 }
316 }
317 }
318 }
319
320 pub(super) fn process_icmpv4<'frame>(
321 &mut self,
322 _sockets: &mut SocketSet,
323 ip_repr: Ipv4Repr,
324 ip_payload: &'frame [u8],
325 ) -> Option<Packet<'frame>> {
326 let icmp_packet = check!(Icmpv4Packet::new_checked(ip_payload));
327 let icmp_repr = check!(Icmpv4Repr::parse(&icmp_packet, &self.caps.checksum));
328
329 #[cfg(feature = "socket-icmp")]
330 let mut handled_by_icmp_socket = false;
331
332 #[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))]
333 for icmp_socket in _sockets
334 .items_mut()
335 .filter_map(|i| icmp::Socket::downcast_mut(&mut i.socket))
336 {
337 if icmp_socket.accepts_v4(self, &ip_repr, &icmp_repr) {
338 icmp_socket.process_v4(self, &ip_repr, &icmp_repr);
339 handled_by_icmp_socket = true;
340 }
341 }
342
343 match icmp_repr {
344 #[cfg(all(feature = "proto-ipv4", feature = "auto-icmp-echo-reply"))]
346 Icmpv4Repr::EchoRequest {
347 ident,
348 seq_no,
349 data,
350 } => {
351 let icmp_reply_repr = Icmpv4Repr::EchoReply {
352 ident,
353 seq_no,
354 data,
355 };
356 self.icmpv4_reply(ip_repr, icmp_reply_repr)
357 }
358
359 Icmpv4Repr::EchoReply { .. } => None,
361
362 #[cfg(feature = "socket-icmp")]
365 _ if handled_by_icmp_socket => None,
366
367 _ => None,
370 }
371 }
372
373 pub(super) fn icmpv4_reply<'frame, 'icmp: 'frame>(
374 &self,
375 ipv4_repr: Ipv4Repr,
376 icmp_repr: Icmpv4Repr<'icmp>,
377 ) -> Option<Packet<'frame>> {
378 if !self.is_unicast_v4(ipv4_repr.src_addr) {
379 None
381 } else if self.is_unicast_v4(ipv4_repr.dst_addr) {
382 let ipv4_reply_repr = Ipv4Repr {
384 src_addr: ipv4_repr.dst_addr,
385 dst_addr: ipv4_repr.src_addr,
386 next_header: IpProtocol::Icmp,
387 payload_len: icmp_repr.buffer_len(),
388 hop_limit: 64,
389 };
390 Some(Packet::new_ipv4(
391 ipv4_reply_repr,
392 IpPayload::Icmpv4(icmp_repr),
393 ))
394 } else if self.is_broadcast_v4(ipv4_repr.dst_addr) {
395 match icmp_repr {
397 Icmpv4Repr::EchoReply { .. } => match self.ipv4_addr() {
398 Some(src_addr) => {
399 let ipv4_reply_repr = Ipv4Repr {
400 src_addr,
401 dst_addr: ipv4_repr.src_addr,
402 next_header: IpProtocol::Icmp,
403 payload_len: icmp_repr.buffer_len(),
404 hop_limit: 64,
405 };
406 Some(Packet::new_ipv4(
407 ipv4_reply_repr,
408 IpPayload::Icmpv4(icmp_repr),
409 ))
410 }
411 None => None,
412 },
413 _ => None,
414 }
415 } else {
416 None
417 }
418 }
419
420 #[cfg(feature = "proto-ipv4-fragmentation")]
421 pub(super) fn dispatch_ipv4_frag<Tx: TxToken>(&mut self, tx_token: Tx, frag: &mut Fragmenter) {
422 let caps = self.caps.clone();
423
424 let max_fragment_size = caps.max_ipv4_fragment_size(frag.ipv4.repr.buffer_len());
425 let payload_len = (frag.packet_len - frag.sent_bytes).min(max_fragment_size);
426 let ip_len = payload_len + frag.ipv4.repr.buffer_len();
427
428 let more_frags = (frag.packet_len - frag.sent_bytes) != payload_len;
429 frag.ipv4.repr.payload_len = payload_len;
430 frag.sent_bytes += payload_len;
431
432 let mut tx_len = ip_len;
433 #[cfg(feature = "medium-ethernet")]
434 if matches!(caps.medium, Medium::Ethernet) {
435 tx_len += EthernetFrame::<&[u8]>::header_len();
436 }
437
438 #[cfg(feature = "medium-ethernet")]
440 let emit_ethernet = |repr: &IpRepr, tx_buffer: &mut [u8]| {
441 let mut frame = EthernetFrame::new_unchecked(tx_buffer);
442
443 let src_addr = self.hardware_addr.ethernet_or_panic();
444 frame.set_src_addr(src_addr);
445 frame.set_dst_addr(frag.ipv4.dst_hardware_addr);
446
447 match repr.version() {
448 #[cfg(feature = "proto-ipv4")]
449 IpVersion::Ipv4 => frame.set_ethertype(EthernetProtocol::Ipv4),
450 #[cfg(feature = "proto-ipv6")]
451 IpVersion::Ipv6 => frame.set_ethertype(EthernetProtocol::Ipv6),
452 }
453 };
454
455 tx_token.consume(tx_len, |mut tx_buffer| {
456 #[cfg(feature = "medium-ethernet")]
457 if matches!(self.caps.medium, Medium::Ethernet) {
458 emit_ethernet(&IpRepr::Ipv4(frag.ipv4.repr), tx_buffer);
459 tx_buffer = &mut tx_buffer[EthernetFrame::<&[u8]>::header_len()..];
460 }
461
462 let mut packet =
463 Ipv4Packet::new_unchecked(&mut tx_buffer[..frag.ipv4.repr.buffer_len()]);
464 frag.ipv4.repr.emit(&mut packet, &caps.checksum);
465 packet.set_ident(frag.ipv4.ident);
466 packet.set_more_frags(more_frags);
467 packet.set_dont_frag(false);
468 packet.set_frag_offset(frag.ipv4.frag_offset);
469
470 if caps.checksum.ipv4.tx() {
471 packet.fill_checksum();
472 }
473
474 tx_buffer[frag.ipv4.repr.buffer_len()..][..payload_len].copy_from_slice(
475 &frag.buffer[frag.ipv4.frag_offset as usize + frag.ipv4.repr.buffer_len()..]
476 [..payload_len],
477 );
478
479 frag.ipv4.frag_offset += payload_len as u16;
481 })
482 }
483}