1use super::*;
2
3#[cfg(feature = "socket-dhcpv4")]
4use crate::socket::dhcpv4;
5#[cfg(feature = "socket-icmp")]
6use crate::socket::icmp;
7use crate::socket::AnySocket;
8
9use crate::phy::{Medium, TxToken};
10use crate::time::Instant;
11use crate::wire::*;
12
13impl InterfaceInner {
14 pub(super) fn process_ipv4<'a>(
15 &mut self,
16 sockets: &mut SocketSet,
17 meta: PacketMeta,
18 ipv4_packet: &Ipv4Packet<&'a [u8]>,
19 frag: &'a mut FragmentsBuffer,
20 ) -> Option<Packet<'a>> {
21 let ipv4_repr = check!(Ipv4Repr::parse(ipv4_packet, &self.caps.checksum));
22 if !self.is_unicast_v4(ipv4_repr.src_addr) && !ipv4_repr.src_addr.is_unspecified() {
23 net_debug!("non-unicast or unspecified source address");
25 return None;
26 }
27
28 #[cfg(feature = "proto-ipv4-fragmentation")]
29 let ip_payload = {
30 if ipv4_packet.more_frags() || ipv4_packet.frag_offset() != 0 {
31 let key = FragKey::Ipv4(ipv4_packet.get_key());
32
33 let f = match frag.assembler.get(&key, self.now + frag.reassembly_timeout) {
34 Ok(f) => f,
35 Err(_) => {
36 net_debug!("No available packet assembler for fragmented packet");
37 return None;
38 }
39 };
40
41 if !ipv4_packet.more_frags() {
42 check!(f.set_total_size(
44 ipv4_packet.total_len() as usize - ipv4_packet.header_len() as usize
45 + ipv4_packet.frag_offset() as usize,
46 ));
47 }
48
49 if let Err(e) = f.add(ipv4_packet.payload(), ipv4_packet.frag_offset() as usize) {
50 net_debug!("fragmentation error: {:?}", e);
51 return None;
52 }
53
54 match f.assemble() {
58 Some(payload) => payload,
59 None => return None,
60 }
61 } else {
62 ipv4_packet.payload()
63 }
64 };
65
66 #[cfg(not(feature = "proto-ipv4-fragmentation"))]
67 let ip_payload = ipv4_packet.payload();
68
69 let ip_repr = IpRepr::Ipv4(ipv4_repr);
70
71 #[cfg(feature = "socket-raw")]
72 let handled_by_raw_socket = self.raw_socket_filter(sockets, &ip_repr, ip_payload);
73 #[cfg(not(feature = "socket-raw"))]
74 let handled_by_raw_socket = false;
75
76 #[cfg(feature = "socket-dhcpv4")]
77 {
78 if ipv4_repr.next_header == IpProtocol::Udp
79 && matches!(self.caps.medium, Medium::Ethernet)
80 {
81 let udp_packet = check!(UdpPacket::new_checked(ip_payload));
82 if let Some(dhcp_socket) = sockets
83 .items_mut()
84 .find_map(|i| dhcpv4::Socket::downcast_mut(&mut i.socket))
85 {
86 if udp_packet.src_port() == dhcp_socket.server_port
89 && udp_packet.dst_port() == dhcp_socket.client_port
90 {
91 let (src_addr, dst_addr) = (ip_repr.src_addr(), ip_repr.dst_addr());
92 let udp_repr = check!(UdpRepr::parse(
93 &udp_packet,
94 &src_addr,
95 &dst_addr,
96 &self.caps.checksum
97 ));
98 let udp_payload = udp_packet.payload();
99
100 dhcp_socket.process(self, &ipv4_repr, &udp_repr, udp_payload);
101 return None;
102 }
103 }
104 }
105 }
106
107 if !self.has_ip_addr(ipv4_repr.dst_addr)
108 && !self.has_multicast_group(ipv4_repr.dst_addr)
109 && !self.is_broadcast_v4(ipv4_repr.dst_addr)
110 {
111 if !self.any_ip
114 || !ipv4_repr.dst_addr.is_unicast()
115 || self
116 .routes
117 .lookup(&IpAddress::Ipv4(ipv4_repr.dst_addr), self.now)
118 .map_or(true, |router_addr| !self.has_ip_addr(router_addr))
119 {
120 return None;
121 }
122 }
123
124 match ipv4_repr.next_header {
125 IpProtocol::Icmp => self.process_icmpv4(sockets, ip_repr, ip_payload),
126
127 #[cfg(feature = "proto-igmp")]
128 IpProtocol::Igmp => self.process_igmp(ipv4_repr, ip_payload),
129
130 #[cfg(any(feature = "socket-udp", feature = "socket-dns"))]
131 IpProtocol::Udp => {
132 let udp_packet = check!(UdpPacket::new_checked(ip_payload));
133 let udp_repr = check!(UdpRepr::parse(
134 &udp_packet,
135 &ipv4_repr.src_addr.into(),
136 &ipv4_repr.dst_addr.into(),
137 &self.checksum_caps(),
138 ));
139
140 self.process_udp(
141 sockets,
142 meta,
143 ip_repr,
144 udp_repr,
145 handled_by_raw_socket,
146 udp_packet.payload(),
147 ip_payload,
148 )
149 }
150
151 #[cfg(feature = "socket-tcp")]
152 IpProtocol::Tcp => self.process_tcp(sockets, ip_repr, ip_payload),
153
154 _ if handled_by_raw_socket => None,
155
156 _ => {
157 let payload_len =
159 icmp_reply_payload_len(ip_payload.len(), IPV4_MIN_MTU, ipv4_repr.buffer_len());
160 let icmp_reply_repr = Icmpv4Repr::DstUnreachable {
161 reason: Icmpv4DstUnreachable::ProtoUnreachable,
162 header: ipv4_repr,
163 data: &ip_payload[0..payload_len],
164 };
165 self.icmpv4_reply(ipv4_repr, icmp_reply_repr)
166 }
167 }
168 }
169
170 #[cfg(feature = "medium-ethernet")]
171 pub(super) fn process_arp<'frame>(
172 &mut self,
173 timestamp: Instant,
174 eth_frame: &EthernetFrame<&'frame [u8]>,
175 ) -> Option<EthernetPacket<'frame>> {
176 let arp_packet = check!(ArpPacket::new_checked(eth_frame.payload()));
177 let arp_repr = check!(ArpRepr::parse(&arp_packet));
178
179 match arp_repr {
180 ArpRepr::EthernetIpv4 {
181 operation,
182 source_hardware_addr,
183 source_protocol_addr,
184 target_protocol_addr,
185 ..
186 } => {
187 if !self.has_ip_addr(target_protocol_addr) {
189 return None;
190 }
191
192 if let ArpOperation::Unknown(_) = operation {
194 net_debug!("arp: unknown operation code");
195 return None;
196 }
197
198 if !source_protocol_addr.is_unicast() || !source_hardware_addr.is_unicast() {
200 net_debug!("arp: non-unicast source address");
201 return None;
202 }
203
204 if !self.in_same_network(&IpAddress::Ipv4(source_protocol_addr)) {
205 net_debug!("arp: source IP address not in same network as us");
206 return None;
207 }
208
209 self.neighbor_cache.fill(
214 source_protocol_addr.into(),
215 source_hardware_addr.into(),
216 timestamp,
217 );
218
219 if operation == ArpOperation::Request {
220 let src_hardware_addr = self.hardware_addr.ethernet_or_panic();
221
222 Some(EthernetPacket::Arp(ArpRepr::EthernetIpv4 {
223 operation: ArpOperation::Reply,
224 source_hardware_addr: src_hardware_addr,
225 source_protocol_addr: target_protocol_addr,
226 target_hardware_addr: source_hardware_addr,
227 target_protocol_addr: source_protocol_addr,
228 }))
229 } else {
230 None
231 }
232 }
233 }
234 }
235
236 pub(super) fn process_icmpv4<'frame>(
237 &mut self,
238 _sockets: &mut SocketSet,
239 ip_repr: IpRepr,
240 ip_payload: &'frame [u8],
241 ) -> Option<Packet<'frame>> {
242 let icmp_packet = check!(Icmpv4Packet::new_checked(ip_payload));
243 let icmp_repr = check!(Icmpv4Repr::parse(&icmp_packet, &self.caps.checksum));
244
245 #[cfg(feature = "socket-icmp")]
246 let mut handled_by_icmp_socket = false;
247
248 #[cfg(all(feature = "socket-icmp", feature = "proto-ipv4"))]
249 for icmp_socket in _sockets
250 .items_mut()
251 .filter_map(|i| icmp::Socket::downcast_mut(&mut i.socket))
252 {
253 if icmp_socket.accepts(self, &ip_repr, &icmp_repr.into()) {
254 icmp_socket.process(self, &ip_repr, &icmp_repr.into());
255 handled_by_icmp_socket = true;
256 }
257 }
258
259 match icmp_repr {
260 #[cfg(feature = "proto-ipv4")]
262 Icmpv4Repr::EchoRequest {
263 ident,
264 seq_no,
265 data,
266 } => {
267 let icmp_reply_repr = Icmpv4Repr::EchoReply {
268 ident,
269 seq_no,
270 data,
271 };
272 match ip_repr {
273 IpRepr::Ipv4(ipv4_repr) => self.icmpv4_reply(ipv4_repr, icmp_reply_repr),
274 #[allow(unreachable_patterns)]
275 _ => unreachable!(),
276 }
277 }
278
279 Icmpv4Repr::EchoReply { .. } => None,
281
282 #[cfg(feature = "socket-icmp")]
285 _ if handled_by_icmp_socket => None,
286
287 _ => None,
289 }
290 }
291
292 pub(super) fn icmpv4_reply<'frame, 'icmp: 'frame>(
293 &self,
294 ipv4_repr: Ipv4Repr,
295 icmp_repr: Icmpv4Repr<'icmp>,
296 ) -> Option<Packet<'frame>> {
297 if !self.is_unicast_v4(ipv4_repr.src_addr) {
298 None
300 } else if self.is_unicast_v4(ipv4_repr.dst_addr) {
301 let ipv4_reply_repr = Ipv4Repr {
303 src_addr: ipv4_repr.dst_addr,
304 dst_addr: ipv4_repr.src_addr,
305 next_header: IpProtocol::Icmp,
306 payload_len: icmp_repr.buffer_len(),
307 hop_limit: 64,
308 };
309 Some(Packet::new_ipv4(
310 ipv4_reply_repr,
311 IpPayload::Icmpv4(icmp_repr),
312 ))
313 } else if self.is_broadcast_v4(ipv4_repr.dst_addr) {
314 match icmp_repr {
316 Icmpv4Repr::EchoReply { .. } => match self.ipv4_addr() {
317 Some(src_addr) => {
318 let ipv4_reply_repr = Ipv4Repr {
319 src_addr,
320 dst_addr: ipv4_repr.src_addr,
321 next_header: IpProtocol::Icmp,
322 payload_len: icmp_repr.buffer_len(),
323 hop_limit: 64,
324 };
325 Some(Packet::new_ipv4(
326 ipv4_reply_repr,
327 IpPayload::Icmpv4(icmp_repr),
328 ))
329 }
330 None => None,
331 },
332 _ => None,
333 }
334 } else {
335 None
336 }
337 }
338
339 #[cfg(feature = "proto-ipv4-fragmentation")]
340 pub(super) fn dispatch_ipv4_frag<Tx: TxToken>(&mut self, tx_token: Tx, frag: &mut Fragmenter) {
341 let caps = self.caps.clone();
342
343 let mtu_max = self.ip_mtu();
344 let ip_len = (frag.packet_len - frag.sent_bytes + frag.ipv4.repr.buffer_len()).min(mtu_max);
345 let payload_len = ip_len - frag.ipv4.repr.buffer_len();
346
347 let more_frags = (frag.packet_len - frag.sent_bytes) != payload_len;
348 frag.ipv4.repr.payload_len = payload_len;
349 frag.sent_bytes += payload_len;
350
351 let mut tx_len = ip_len;
352 #[cfg(feature = "medium-ethernet")]
353 if matches!(caps.medium, Medium::Ethernet) {
354 tx_len += EthernetFrame::<&[u8]>::header_len();
355 }
356
357 #[cfg(feature = "medium-ethernet")]
359 let emit_ethernet = |repr: &IpRepr, tx_buffer: &mut [u8]| {
360 let mut frame = EthernetFrame::new_unchecked(tx_buffer);
361
362 let src_addr = self.hardware_addr.ethernet_or_panic();
363 frame.set_src_addr(src_addr);
364 frame.set_dst_addr(frag.ipv4.dst_hardware_addr);
365
366 match repr.version() {
367 #[cfg(feature = "proto-ipv4")]
368 IpVersion::Ipv4 => frame.set_ethertype(EthernetProtocol::Ipv4),
369 #[cfg(feature = "proto-ipv6")]
370 IpVersion::Ipv6 => frame.set_ethertype(EthernetProtocol::Ipv6),
371 }
372 };
373
374 tx_token.consume(tx_len, |mut tx_buffer| {
375 #[cfg(feature = "medium-ethernet")]
376 if matches!(self.caps.medium, Medium::Ethernet) {
377 emit_ethernet(&IpRepr::Ipv4(frag.ipv4.repr), tx_buffer);
378 tx_buffer = &mut tx_buffer[EthernetFrame::<&[u8]>::header_len()..];
379 }
380
381 let mut packet =
382 Ipv4Packet::new_unchecked(&mut tx_buffer[..frag.ipv4.repr.buffer_len()]);
383 frag.ipv4.repr.emit(&mut packet, &caps.checksum);
384 packet.set_ident(frag.ipv4.ident);
385 packet.set_more_frags(more_frags);
386 packet.set_dont_frag(false);
387 packet.set_frag_offset(frag.ipv4.frag_offset);
388
389 if caps.checksum.ipv4.tx() {
390 packet.fill_checksum();
391 }
392
393 tx_buffer[frag.ipv4.repr.buffer_len()..][..payload_len].copy_from_slice(
394 &frag.buffer[frag.ipv4.frag_offset as usize + frag.ipv4.repr.buffer_len()..]
395 [..payload_len],
396 );
397
398 frag.ipv4.frag_offset += payload_len as u16;
400 })
401 }
402
403 #[cfg(feature = "proto-igmp")]
404 pub(super) fn igmp_report_packet<'any>(
405 &self,
406 version: IgmpVersion,
407 group_addr: Ipv4Address,
408 ) -> Option<Packet<'any>> {
409 let iface_addr = self.ipv4_addr()?;
410 let igmp_repr = IgmpRepr::MembershipReport {
411 group_addr,
412 version,
413 };
414 let pkt = Packet::new_ipv4(
415 Ipv4Repr {
416 src_addr: iface_addr,
417 dst_addr: group_addr,
419 next_header: IpProtocol::Igmp,
420 payload_len: igmp_repr.buffer_len(),
421 hop_limit: 1,
422 },
424 IpPayload::Igmp(igmp_repr),
425 );
426 Some(pkt)
427 }
428
429 #[cfg(feature = "proto-igmp")]
430 pub(super) fn igmp_leave_packet<'any>(&self, group_addr: Ipv4Address) -> Option<Packet<'any>> {
431 self.ipv4_addr().map(|iface_addr| {
432 let igmp_repr = IgmpRepr::LeaveGroup { group_addr };
433 Packet::new_ipv4(
434 Ipv4Repr {
435 src_addr: iface_addr,
436 dst_addr: Ipv4Address::MULTICAST_ALL_ROUTERS,
437 next_header: IpProtocol::Igmp,
438 payload_len: igmp_repr.buffer_len(),
439 hop_limit: 1,
440 },
441 IpPayload::Igmp(igmp_repr),
442 )
443 })
444 }
445}