netstack3_ip/raw/
protocol.rs
1use net_types::ip::{GenericOverIp, Ip, IpVersion};
8use netstack3_base::IpExt;
9use packet_formats::ip::{IpProto, Ipv4Proto, Ipv6Proto};
10
11#[derive(Clone, Copy, Debug, Eq, GenericOverIp, Ord, PartialEq, PartialOrd)]
14#[generic_over_ip(I, Ip)]
15pub struct Protocol<I: IpExt>(I::Proto);
16
17impl<I: IpExt> Protocol<I> {
18 fn new(proto: I::Proto) -> Option<Protocol<I>> {
19 I::map_ip(
20 proto,
21 |v4_proto| match v4_proto {
22 Ipv4Proto::Proto(IpProto::Reserved) => None,
23 _ => Some(Protocol(v4_proto)),
24 },
25 |v6_proto| match v6_proto {
26 Ipv6Proto::Proto(IpProto::Reserved) => None,
27 _ => Some(Protocol(v6_proto)),
28 },
29 )
30 }
31}
32
33#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
35pub enum RawIpSocketProtocol<I: IpExt> {
36 Raw,
42 Proto(Protocol<I>),
44}
45
46impl<I: IpExt> RawIpSocketProtocol<I> {
47 pub fn new(proto: I::Proto) -> RawIpSocketProtocol<I> {
49 Protocol::new(proto).map_or(RawIpSocketProtocol::Raw, RawIpSocketProtocol::Proto)
50 }
51
52 pub fn proto(&self) -> I::Proto {
54 match self {
55 RawIpSocketProtocol::Raw => IpProto::Reserved.into(),
56 RawIpSocketProtocol::Proto(Protocol(proto)) => *proto,
57 }
58 }
59
60 pub fn is_icmp(&self) -> bool {
62 match self {
63 RawIpSocketProtocol::Raw => false,
64 RawIpSocketProtocol::Proto(Protocol(p)) => *p == I::ICMP_IP_PROTO,
65 }
66 }
67
68 pub fn requires_system_checksums(&self) -> bool {
70 self.is_icmp() && I::VERSION == IpVersion::V6
77 }
78}
79
80#[cfg(test)]
81mod test {
82 use super::*;
83 use ip_test_macro::ip_test;
84 use net_types::ip::{Ipv4, Ipv6};
85 use test_case::test_case;
86
87 #[ip_test(I)]
88 #[test_case(IpProto::Udp, Some(Protocol(IpProto::Udp.into())); "valid")]
89 #[test_case(IpProto::Reserved, None; "reserved")]
90 fn new_protocol<I: IpExt>(p: IpProto, expected: Option<Protocol<I>>) {
91 assert_eq!(Protocol::new(p.into()), expected);
92 }
93
94 #[ip_test(I)]
95 #[test_case(IpProto::Udp, RawIpSocketProtocol::Proto(Protocol(IpProto::Udp.into())); "valid")]
96 #[test_case(IpProto::Reserved, RawIpSocketProtocol::Raw; "reserved")]
97 fn new_raw_ip_socket_protocol<I: IpExt>(p: IpProto, expected: RawIpSocketProtocol<I>) {
98 assert_eq!(RawIpSocketProtocol::new(p.into()), expected);
99 }
100
101 #[test_case(Ipv4Proto::Icmp, true; "icmpv4")]
102 #[test_case(Ipv4Proto::Other(58), false; "icmpv6")]
103 #[test_case(Ipv4Proto::Proto(IpProto::Udp), false; "udp")]
104 #[test_case(Ipv4Proto::Proto(IpProto::Reserved), false; "reserved")]
105 fn is_icmpv4(proto: Ipv4Proto, expected_result: bool) {
106 assert_eq!(RawIpSocketProtocol::<Ipv4>::new(proto).is_icmp(), expected_result)
107 }
108
109 #[test_case(Ipv6Proto::Icmpv6, true; "icmpv6")]
110 #[test_case(Ipv6Proto::Other(1), false; "icmpv4")]
111 #[test_case(Ipv6Proto::Proto(IpProto::Udp), false; "udp")]
112 #[test_case(Ipv6Proto::Proto(IpProto::Reserved), false; "reserved")]
113 fn is_icmpv6(proto: Ipv6Proto, expected_result: bool) {
114 assert_eq!(RawIpSocketProtocol::<Ipv6>::new(proto).is_icmp(), expected_result)
115 }
116}