iscsi_client_rs/models/login/
response.rs1use anyhow::{Result, bail};
9use zerocopy::{
10 BigEndian, FromBytes as ZFromBytes, Immutable, IntoBytes, KnownLayout, U16, U32,
11};
12
13use crate::{
14 client::pdu_connection::FromBytes,
15 models::{
16 common::{BasicHeaderSegment, HEADER_LEN, InitiatorTaskTag, SendingData},
17 data_fromat::ZeroCopyType,
18 login::{
19 common::RawLoginFlags,
20 status::{RawStatusClass, RawStatusDetail},
21 },
22 opcode::{BhsOpcode, Opcode, RawBhsOpcode},
23 },
24};
25
26#[repr(C)]
28#[derive(Debug, Default, PartialEq, ZFromBytes, IntoBytes, KnownLayout, Immutable)]
29pub struct LoginResponse {
30 pub opcode: RawBhsOpcode, pub flags: RawLoginFlags, pub version_max: u8, pub version_active: u8, pub total_ahs_length: u8, pub data_segment_length: [u8; 3], pub isid: [u8; 6], pub tsih: U16<BigEndian>, pub initiator_task_tag: InitiatorTaskTag, reserved1: [u8; 4], pub stat_sn: U32<BigEndian>, pub exp_cmd_sn: U32<BigEndian>, pub max_cmd_sn: U32<BigEndian>, pub status_class: RawStatusClass, pub status_detail: RawStatusDetail, reserved2: [u8; 10], }
47
48impl LoginResponse {
49 #[inline]
51 pub fn to_bhs_bytes(&self, buf: &mut [u8]) -> Result<()> {
52 if buf.len() != HEADER_LEN {
53 bail!("buffer length must be {HEADER_LEN}, got {}", buf.len());
54 }
55 buf.copy_from_slice(self.as_bytes());
56 Ok(())
57 }
58
59 pub fn from_bhs_bytes(buf: &mut [u8]) -> Result<&mut Self> {
61 let hdr = <Self as zerocopy::FromBytes>::mut_from_bytes(buf)
62 .map_err(|e| anyhow::anyhow!("failed convert buffer LoginResponse: {e}"))?;
63 if hdr.opcode.opcode_known() != Some(Opcode::LoginResp) {
64 anyhow::bail!(
65 "LoginResponse: invalid opcode 0x{:02x}",
66 hdr.opcode.opcode_raw()
67 );
68 }
69 Ok(hdr)
70 }
71}
72
73impl SendingData for LoginResponse {
74 #[inline]
75 fn get_final_bit(&self) -> bool {
76 !self.flags.cont()
77 }
78
79 #[inline]
80 fn set_final_bit(&mut self) {
81 self.flags.set_cont(false)
82 }
83
84 #[inline]
85 fn get_continue_bit(&self) -> bool {
86 self.flags.cont()
87 }
88
89 #[inline]
90 fn set_continue_bit(&mut self) {
91 self.flags.set_cont(true)
92 }
93}
94
95impl FromBytes for LoginResponse {
96 fn from_bhs_bytes(bytes: &mut [u8]) -> Result<&mut Self> {
97 LoginResponse::from_bhs_bytes(bytes)
98 }
99}
100impl BasicHeaderSegment for LoginResponse {
101 #[inline]
102 fn to_bhs_bytes(&self, buf: &mut [u8]) -> Result<()> {
103 self.to_bhs_bytes(buf)
104 }
105
106 #[inline]
107 fn get_opcode(&self) -> Result<BhsOpcode> {
108 BhsOpcode::try_from(self.opcode.raw())
109 }
110
111 #[inline]
112 fn get_initiator_task_tag(&self) -> u32 {
113 self.initiator_task_tag.get()
114 }
115
116 #[inline]
117 fn get_ahs_length_bytes(&self) -> usize {
118 (self.total_ahs_length as usize) * 4
119 }
120
121 #[inline]
122 fn set_ahs_length_bytes(&mut self, len: u8) {
123 self.total_ahs_length = len >> 2;
124 }
125
126 #[inline]
127 fn get_data_length_bytes(&self) -> usize {
128 u32::from_be_bytes([
129 0,
130 self.data_segment_length[0],
131 self.data_segment_length[1],
132 self.data_segment_length[2],
133 ]) as usize
134 }
135
136 #[inline]
137 fn set_data_length_bytes(&mut self, len: u32) {
138 let be = len.to_be_bytes();
139 self.data_segment_length = [be[1], be[2], be[3]];
140 }
141
142 #[inline]
143 fn get_header_diggest(&self, _: bool) -> usize {
144 0
145 }
146
147 #[inline]
148 fn get_data_diggest(&self, _: bool) -> usize {
149 0
150 }
151}
152
153impl ZeroCopyType for LoginResponse {}