From 073244a0b8b634c0b69e233e97d82de9b8a91808 Mon Sep 17 00:00:00 2001 From: Sam Muhammed Date: Sun, 20 Feb 2022 18:40:11 +0200 Subject: [PATCH] rust/nfs4: Add NFSPROC4_GETDEVINFO op parsers Also add respective response/request unittests test_nfs4_response_getdevinfo() test_nfs4_request_getdevinfo() --- rust/src/nfs/nfs4_records.rs | 110 +++++++++++++++++++++++++++++++++++ rust/src/nfs/types.rs | 1 + 2 files changed, 111 insertions(+) diff --git a/rust/src/nfs/nfs4_records.rs b/rust/src/nfs/nfs4_records.rs index b2c80a3128..0a69c48a7c 100644 --- a/rust/src/nfs/nfs4_records.rs +++ b/rust/src/nfs/nfs4_records.rs @@ -66,6 +66,7 @@ pub enum Nfs4RequestContent<'a> { ReclaimComplete(u32), SecInfoNoName(u32), LayoutGet(Nfs4RequestLayoutGet<'a>), + GetDevInfo(Nfs4RequestGetDevInfo<'a>), } #[derive(Debug,PartialEq)] @@ -135,6 +136,29 @@ fn nfs4_parse_nfsstring(i: &[u8]) -> IResult<&[u8], &[u8]> { Ok((i, data)) } +#[derive(Debug, PartialEq)] +pub struct Nfs4RequestGetDevInfo<'a> { + pub device_id: &'a[u8], + pub layout_type: u32, + pub maxcount: u32, + pub notify_mask: u32, +} + +fn nfs4_req_getdevinfo(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent> { + let (i, device_id) = take(16_usize)(i)?; + let (i, layout_type) = be_u32(i)?; + let (i, maxcount) = be_u32(i)?; + let (i, _) = be_u32(i)?; + let (i, notify_mask) = be_u32(i)?; + let req = Nfs4RequestContent::GetDevInfo(Nfs4RequestGetDevInfo { + device_id, + layout_type, + maxcount, + notify_mask, + }); + Ok((i, req)) +} + #[derive(Debug, PartialEq)] pub struct Nfs4RequestCreateSession<'a> { pub client_id: &'a[u8], @@ -529,6 +553,7 @@ fn parse_request_compound_command(i: &[u8]) -> IResult<&[u8], Nfs4RequestContent NFSPROC4_RECLAIM_COMPLETE => nfs4_req_reclaim_complete(i)?, NFSPROC4_SECINFO_NO_NAME => nfs4_req_secinfo_no_name(i)?, NFSPROC4_LAYOUTGET => nfs4_req_layoutget(i)?, + NFSPROC4_GETDEVINFO => nfs4_req_getdevinfo(i)?, _ => { return Err(Err::Error(make_error(i, ErrorKind::Switch))); } }; Ok((i, cmd_data)) @@ -581,6 +606,7 @@ pub enum Nfs4ResponseContent<'a> { ReclaimComplete(u32), SecInfoNoName(u32), LayoutGet(u32, Option>), + GetDevInfo(u32, Option>), } #[derive(Debug, PartialEq)] @@ -776,6 +802,36 @@ fn nfs4_res_open(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { Ok((i, Nfs4ResponseContent::Open(status, open_data))) } +#[derive(Debug, PartialEq)] +pub struct Nfs4ResponseGetDevInfo<'a> { + pub layout_type: u32, + pub r_netid: &'a[u8], + pub r_addr: &'a[u8], + pub notify_mask: u32, +} + +fn nfs4_parse_res_getdevinfo(i: &[u8]) -> IResult<&[u8], Nfs4ResponseGetDevInfo> { + let (i, layout_type) = be_u32(i)?; + let (i, _) = be_u64(i)?; + let (i, _device_index) = be_u32(i)?; + let (i, _) = be_u64(i)?; + let (i, r_netid) = nfs4_parse_nfsstring(i)?; + let (i, r_addr) = nfs4_parse_nfsstring(i)?; + let (i, notify_mask) = be_u32(i)?; + Ok((i, Nfs4ResponseGetDevInfo { + layout_type, + r_netid, + r_addr, + notify_mask, + })) +} + +fn nfs4_res_getdevinfo(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { + let (i, status) = be_u32(i)?; + let (i, getdevinfo) = cond(status == 0, nfs4_parse_res_getdevinfo)(i)?; + Ok((i, Nfs4ResponseContent::GetDevInfo( status, getdevinfo ))) +} + /*https://datatracker.ietf.org/doc/html/rfc5661#section-13.1*/ // in case of multiple file handles, return handles in a vector #[derive(Debug, PartialEq)] @@ -1065,6 +1121,7 @@ fn nfs4_res_compound_command(i: &[u8]) -> IResult<&[u8], Nfs4ResponseContent> { NFSPROC4_RECLAIM_COMPLETE => nfs4_res_reclaim_complete(i)?, NFSPROC4_SECINFO_NO_NAME => nfs4_res_secinfo_no_name(i)?, NFSPROC4_LAYOUTGET => nfs4_res_layoutget(i)?, + NFSPROC4_GETDEVINFO => nfs4_res_getdevinfo(i)?, _ => { return Err(Err::Error(make_error(i, ErrorKind::Switch))); } }; Ok((i, cmd_data)) @@ -1433,6 +1490,28 @@ mod tests { } } + #[test] + fn test_nfs4_request_getdevinfo() { + let buf: &[u8] = &[ + 0x00, 0x00, 0x00, 0x2f, /*opcode*/ + 0x01, 0x01, 0x00, 0x00, 0x00, 0xf2, 0xfa, 0x80, // getdevinfo + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x3e, 0x20, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, + ]; + + let (_, request) = nfs4_req_getdevinfo(&buf[4..]).unwrap(); + match request { + Nfs4RequestContent::GetDevInfo( getdevifo ) => { + assert_eq!(getdevifo.device_id, &buf[4..20]); + assert_eq!(getdevifo.layout_type, 1); + assert_eq!(getdevifo.maxcount, 81440); + assert_eq!(getdevifo.notify_mask, 6); + } + _ => { panic!("Failure"); } + } + } + #[test] fn test_nfs4_attrs() { #[rustfmt::skip] @@ -1843,4 +1922,35 @@ mod tests { _ => { panic!("Failure"); } } } + + #[test] + fn test_nfs4_response_getdevinfo() { + let buf: &[u8] = &[ + 0x00, 0x00, 0x00, 0x2f, /*opcode*/ + 0x00, 0x00, 0x00, 0x00, /*status*/ + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2c, // getdevinfo + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x03, 0x74, 0x63, 0x70, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x31, 0x39, 0x32, 0x2e, + 0x31, 0x36, 0x38, 0x2e, 0x30, 0x2e, 0x36, 0x31, + 0x2e, 0x38, 0x2e, 0x31, 0x00, 0x00, 0x00, 0x00, + ]; + + let (_, getdevinfo) = nfs4_parse_res_getdevinfo(&buf[8..]).unwrap(); + assert_eq!(getdevinfo.layout_type, 1); + assert_eq!(getdevinfo.r_netid, b"tcp"); + assert_eq!(getdevinfo.r_addr, b"192.168.0.61.8.1"); + + let (_, response) = nfs4_res_getdevinfo(&buf[4..]).unwrap(); + match response { + Nfs4ResponseContent::GetDevInfo(status, getdevinfo_data) => { + assert_eq!(status, 0); + assert_eq!(getdevinfo_data, Some(getdevinfo)) + } + _ => { panic!("Failure"); } + } + + + } } diff --git a/rust/src/nfs/types.rs b/rust/src/nfs/types.rs index d2f4c0707d..feb7b70a2d 100644 --- a/rust/src/nfs/types.rs +++ b/rust/src/nfs/types.rs @@ -275,6 +275,7 @@ pub const NFSPROC4_WRITE: u32 = 38; pub const NFSPROC4_RELEASE_LOCKOWNER: u32 = 39; pub const NFSPROC4_EXCHANGE_ID: u32 = 42; pub const NFSPROC4_CREATE_SESSION: u32 = 43; +pub const NFSPROC4_GETDEVINFO: u32 = 47; pub const NFSPROC4_LAYOUTGET: u32 = 50; pub const NFSPROC4_SECINFO_NO_NAME: u32 = 52; pub const NFSPROC4_SEQUENCE: u32 = 53;