diff --git a/kernel/src/net/socket/ip/options.rs b/kernel/src/net/socket/ip/options.rs index 5c3e3751b..d7aea82a7 100644 --- a/kernel/src/net/socket/ip/options.rs +++ b/kernel/src/net/socket/ip/options.rs @@ -17,6 +17,7 @@ pub(super) struct IpOptionSet { tos: u8, ttl: IpTtl, hdrincl: bool, + recverr: bool, } const DEFAULT_TTL: u8 = 64; @@ -28,6 +29,7 @@ impl IpOptionSet { tos: 0, ttl: IpTtl(None), hdrincl: false, + recverr: false, } } @@ -36,6 +38,7 @@ impl IpOptionSet { tos: 0, ttl: IpTtl(None), hdrincl: false, + recverr: false, } } @@ -53,6 +56,10 @@ impl IpOptionSet { let hdrincl = self.hdrincl(); ip_hdrincl.set(hdrincl); }, + ip_recverr: Recverr => { + let recverr = self.recverr(); + ip_recverr.set(recverr); + }, _ => return_errno_with_message!(Errno::ENOPROTOOPT, "the socket option is unknown") }); @@ -81,6 +88,10 @@ impl IpOptionSet { socket.set_hdrincl(*hdrincl)?; self.set_hdrincl(*hdrincl); }, + ip_recverr: Recverr => { + let recverr = ip_recverr.get().unwrap(); + self.set_recverr(*recverr); + }, _ => return_errno_with_message!(Errno::ENOPROTOOPT, "the socket option to be set is unknown") }); @@ -92,6 +103,7 @@ impl_socket_options!( pub struct Tos(i32); pub struct Ttl(IpTtl); pub struct Hdrincl(bool); + pub struct Recverr(bool); ); #[derive(Debug, Clone, Copy)] diff --git a/kernel/src/util/net/options/ip.rs b/kernel/src/util/net/options/ip.rs index c1ac9a439..68dad3b5c 100644 --- a/kernel/src/util/net/options/ip.rs +++ b/kernel/src/util/net/options/ip.rs @@ -5,7 +5,7 @@ use int_to_c_enum::TryFromInt; use super::RawSocketOption; use crate::{ impl_raw_socket_option, - net::socket::ip::options::{Hdrincl, Tos, Ttl}, + net::socket::ip::options::{Hdrincl, Recverr, Tos, Ttl}, prelude::*, util::net::options::SocketOption, }; @@ -72,6 +72,7 @@ pub fn new_ip_option(name: i32) -> Result> { CIpOptionName::TOS => Ok(Box::new(Tos::new())), CIpOptionName::TTL => Ok(Box::new(Ttl::new())), CIpOptionName::HDRINCL => Ok(Box::new(Hdrincl::new())), + CIpOptionName::RECVERR => Ok(Box::new(Recverr::new())), _ => return_errno_with_message!(Errno::ENOPROTOOPT, "unsupported ip level option"), } } @@ -79,3 +80,4 @@ pub fn new_ip_option(name: i32) -> Result> { impl_raw_socket_option!(Ttl); impl_raw_socket_option!(Tos); impl_raw_socket_option!(Hdrincl); +impl_raw_socket_option!(Recverr); diff --git a/test/src/apps/network/sockoption.c b/test/src/apps/network/sockoption.c index 70049bd4f..c123cd98c 100644 --- a/test/src/apps/network/sockoption.c +++ b/test/src/apps/network/sockoption.c @@ -379,3 +379,32 @@ FN_TEST(ip_hdrincl) ENOPROTOOPT); } END_TEST() + +FN_TEST(ip_recverr) +{ + int recverr; + socklen_t recverr_len = sizeof(recverr); + + // 1. Check default value + TEST_RES(getsockopt(sk_unbound, IPPROTO_IP, IP_RECVERR, &recverr, + &recverr_len), + recverr == 0 && recverr_len == 4); + TEST_RES(getsockopt(sk_udp, IPPROTO_IP, IP_RECVERR, &recverr, + &recverr_len), + recverr == 0 && recverr_len == 4); + + // 2. Set and get value + recverr = 100; + TEST_SUCC(setsockopt(sk_unbound, IPPROTO_IP, IP_RECVERR, &recverr, + recverr_len)); + TEST_RES(getsockopt(sk_unbound, IPPROTO_IP, IP_RECVERR, &recverr, + &recverr_len), + recverr == 1 && recverr_len == 4); + recverr = -1; + TEST_SUCC(setsockopt(sk_udp, IPPROTO_IP, IP_RECVERR, &recverr, + recverr_len)); + TEST_RES(getsockopt(sk_udp, IPPROTO_IP, IP_RECVERR, &recverr, + &recverr_len), + recverr == 1 && recverr_len == 4); +} +END_TEST()