netstack3_ip/raw/
checksum.rs
1use log::error;
8use net_types::ip::{GenericOverIp, Ip, IpInvariant, Ipv4Addr, Ipv6Addr};
9use netstack3_base::IpExt;
10use packet::{Buf, BufferViewMut, ParsablePacket as _, ParseBuffer as _};
11use packet_formats::icmp::{IcmpParseArgs, Icmpv6Packet, Icmpv6PacketRaw};
12use packet_formats::ip::{IpPacket, IpProto, Ipv4Proto, Ipv6Proto};
13use packet_formats::ipv4::Ipv4Packet;
14use packet_formats::ipv6::Ipv6Packet;
15use zerocopy::SplitByteSlice;
16
17#[derive(GenericOverIp)]
19#[generic_over_ip()]
20pub(super) enum ChecksumError {
21 ProtocolNotSupported,
23 ChecksumFailed,
25}
26
27pub(super) fn has_valid_checksum<I: IpExt, B: SplitByteSlice>(packet: &I::Packet<B>) -> bool {
29 match I::map_ip(
30 packet,
31 |packet| validate_ipv4_checksum(packet),
32 |packet| validate_ipv6_checksum(packet),
33 ) {
34 Ok(()) => true,
35 Err(ChecksumError::ChecksumFailed) => false,
36 Err(ChecksumError::ProtocolNotSupported) => {
37 error!(
40 "raw IP sockets asked to validate checksum for unsupported protocol: {:?}",
41 packet.proto()
42 );
43 false
44 }
45 }
46}
47
48fn validate_ipv4_checksum<B: SplitByteSlice>(packet: &Ipv4Packet<B>) -> Result<(), ChecksumError> {
50 match packet.proto() {
51 Ipv4Proto::Icmp
52 | Ipv4Proto::Igmp
53 | Ipv4Proto::Proto(IpProto::Udp)
54 | Ipv4Proto::Proto(IpProto::Tcp)
55 | Ipv4Proto::Proto(IpProto::Reserved)
56 | Ipv4Proto::Other(_) => Err(ChecksumError::ProtocolNotSupported),
57 }
58}
59
60fn validate_ipv6_checksum<B: SplitByteSlice>(packet: &Ipv6Packet<B>) -> Result<(), ChecksumError> {
62 match packet.proto() {
63 Ipv6Proto::Icmpv6 => {
64 let mut buffer = Buf::new(packet.body(), ..);
66 match buffer.parse_with::<_, Icmpv6Packet<_>>(IcmpParseArgs::new(
67 packet.src_ip(),
68 packet.dst_ip(),
69 )) {
70 Ok(_packet) => Ok(()),
71 Err(_) => Err(ChecksumError::ChecksumFailed),
72 }
73 }
74 Ipv6Proto::NoNextHeader
75 | Ipv6Proto::Proto(IpProto::Udp)
76 | Ipv6Proto::Proto(IpProto::Tcp)
77 | Ipv6Proto::Proto(IpProto::Reserved)
78 | Ipv6Proto::Other(_) => Err(ChecksumError::ProtocolNotSupported),
79 }
80}
81
82pub(super) fn populate_checksum<'a, I: IpExt, B: BufferViewMut<&'a mut [u8]>>(
87 src_ip: I::Addr,
88 dst_ip: I::Addr,
89 proto: I::Proto,
90 body: B,
91) -> bool {
92 match I::map_ip(
93 (src_ip, dst_ip, proto, IpInvariant(body)),
94 |(src_ip, dst_ip, proto, IpInvariant(body))| {
95 populate_ipv4_checksum(src_ip, dst_ip, proto, body)
96 },
97 |(src_ip, dst_ip, proto, IpInvariant(body))| {
98 populate_ipv6_checksum(src_ip, dst_ip, proto, body)
99 },
100 ) {
101 Ok(()) => true,
102 Err(ChecksumError::ChecksumFailed) => false,
103 Err(ChecksumError::ProtocolNotSupported) => {
104 error!("raw IP sockets asked to generate checksum for unsupported protocol: {proto:?}");
107 false
108 }
109 }
110}
111
112fn populate_ipv4_checksum<'a, B: BufferViewMut<&'a mut [u8]>>(
114 _src_ip: Ipv4Addr,
115 _dst_ip: Ipv4Addr,
116 proto: Ipv4Proto,
117 _body: B,
118) -> Result<(), ChecksumError> {
119 match proto {
120 Ipv4Proto::Icmp
121 | Ipv4Proto::Igmp
122 | Ipv4Proto::Proto(IpProto::Udp)
123 | Ipv4Proto::Proto(IpProto::Tcp)
124 | Ipv4Proto::Proto(IpProto::Reserved)
125 | Ipv4Proto::Other(_) => Err(ChecksumError::ProtocolNotSupported),
126 }
127}
128
129fn populate_ipv6_checksum<'a, B: BufferViewMut<&'a mut [u8]>>(
131 src_ip: Ipv6Addr,
132 dst_ip: Ipv6Addr,
133 proto: Ipv6Proto,
134 body: B,
135) -> Result<(), ChecksumError> {
136 match proto {
137 Ipv6Proto::Icmpv6 => {
138 match Icmpv6PacketRaw::parse_mut(body, ()) {
139 Ok(mut packet) => {
140 if packet.try_write_checksum(src_ip, dst_ip) {
141 Ok(())
142 } else {
143 Err(ChecksumError::ChecksumFailed)
144 }
145 }
146 Err(_) => {
147 Err(ChecksumError::ChecksumFailed)
151 }
152 }
153 }
154 Ipv6Proto::NoNextHeader
155 | Ipv6Proto::Proto(IpProto::Udp)
156 | Ipv6Proto::Proto(IpProto::Tcp)
157 | Ipv6Proto::Proto(IpProto::Reserved)
158 | Ipv6Proto::Other(_) => Err(ChecksumError::ProtocolNotSupported),
159 }
160}