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