iscsi_client_rs/models/login/
request.rs1use anyhow::{Result, bail};
8use zerocopy::{
9 BigEndian, FromBytes as ZFromBytes, Immutable, IntoBytes, KnownLayout, U16, U32,
10};
11
12use crate::{
13 client::pdu_connection::FromBytes,
14 models::{
15 common::{BasicHeaderSegment, HEADER_LEN, InitiatorTaskTag, SendingData},
16 data_fromat::ZeroCopyType,
17 login::common::{RawLoginFlags, Stage},
18 opcode::{BhsOpcode, Opcode, RawBhsOpcode},
19 },
20};
21
22#[repr(C)]
29#[derive(Debug, Default, PartialEq, ZFromBytes, IntoBytes, KnownLayout, Immutable)]
30pub struct LoginRequest {
31 pub opcode: RawBhsOpcode,
33 pub flags: RawLoginFlags,
35 pub version_max: u8,
37 pub version_min: u8,
39 pub total_ahs_length: u8,
41 pub data_segment_length: [u8; 3],
43 pub isid: [u8; 6],
45 pub tsih: U16<BigEndian>,
47 pub initiator_task_tag: InitiatorTaskTag,
49 pub cid: U16<BigEndian>,
51 reserved1: [u8; 2],
53 pub cmd_sn: U32<BigEndian>,
55 pub exp_stat_sn: U32<BigEndian>,
57 reserved2: [u8; 16],
59}
60
61impl LoginRequest {
62 pub fn to_bhs_bytes(&self, buf: &mut [u8]) -> Result<()> {
64 buf.fill(0);
65 if buf.len() != HEADER_LEN {
66 bail!("buffer length must be {HEADER_LEN}, got {}", buf.len());
67 }
68 buf.copy_from_slice(self.as_bytes());
69 Ok(())
70 }
71
72 pub fn from_bhs_bytes(buf: &mut [u8]) -> Result<&mut Self> {
74 let hdr = <Self as zerocopy::FromBytes>::mut_from_bytes(buf)
75 .map_err(|e| anyhow::anyhow!("failed convert buffer LoginRequest: {e}"))?;
76 if hdr.opcode.opcode_known() != Some(Opcode::LoginReq) {
77 anyhow::bail!(
78 "LoginRequest: invalid opcode 0x{:02x}",
79 hdr.opcode.opcode_raw()
80 );
81 }
82 Ok(hdr)
83 }
84}
85
86#[derive(Debug)]
112pub struct LoginRequestBuilder {
113 pub header: LoginRequest,
114}
115
116impl LoginRequestBuilder {
117 pub fn new(isid: [u8; 6], tsih: u16) -> Self {
119 LoginRequestBuilder {
120 header: LoginRequest {
121 opcode: {
122 let mut tmp = RawBhsOpcode::default();
123 tmp.set_opcode_known(Opcode::LoginReq);
124 tmp.set_i();
125 tmp
126 },
127 isid,
128 tsih: tsih.into(),
129 ..Default::default()
130 },
131 }
132 }
133
134 pub fn transit(mut self) -> Self {
136 self.header.flags.set_transit(true);
137 self
138 }
139
140 pub fn csg(mut self, stage: Stage) -> Self {
142 self.header.flags.set_csg(stage);
143 self
144 }
145
146 pub fn nsg(mut self, stage: Stage) -> Self {
148 self.header.flags.set_nsg(stage);
149 self
150 }
151
152 pub fn versions(mut self, max: u8, min: u8) -> Self {
154 self.header.version_max = max;
155 self.header.version_min = min;
156 self
157 }
158
159 pub fn initiator_task_tag(mut self, tag: u32) -> Self {
161 self.header.initiator_task_tag.set(tag);
162 self
163 }
164
165 pub fn connection_id(mut self, cid: u16) -> Self {
167 self.header.cid.set(cid);
168 self
169 }
170
171 pub fn cmd_sn(mut self, cmd_sn: u32) -> Self {
173 self.header.cmd_sn.set(cmd_sn);
174 self
175 }
176
177 pub fn exp_stat_sn(mut self, exp_stat_sn: u32) -> Self {
179 self.header.exp_stat_sn.set(exp_stat_sn);
180 self
181 }
182
183 pub fn isid(mut self, isid: &[u8; 6]) -> Self {
185 self.header.isid.clone_from_slice(isid);
186 self
187 }
188}
189
190impl SendingData for LoginRequest {
191 fn get_final_bit(&self) -> bool {
192 !self.flags.cont()
193 }
194
195 fn set_final_bit(&mut self) {
196 self.flags.set_cont(false);
197 }
198
199 fn get_continue_bit(&self) -> bool {
200 self.flags.cont()
201 }
202
203 fn set_continue_bit(&mut self) {
204 self.flags.set_cont(true);
205 }
206}
207
208impl FromBytes for LoginRequest {
209 fn from_bhs_bytes(bytes: &mut [u8]) -> Result<&mut Self> {
210 LoginRequest::from_bhs_bytes(bytes)
211 }
212}
213
214impl BasicHeaderSegment for LoginRequest {
215 #[inline]
216 fn to_bhs_bytes(&self, buf: &mut [u8]) -> Result<()> {
217 self.to_bhs_bytes(buf)
218 }
219
220 #[inline]
221 fn get_opcode(&self) -> Result<BhsOpcode> {
222 BhsOpcode::try_from(self.opcode.raw())
223 }
224
225 fn get_initiator_task_tag(&self) -> u32 {
226 self.initiator_task_tag.get()
227 }
228
229 fn get_ahs_length_bytes(&self) -> usize {
230 (self.total_ahs_length as usize) * 4
231 }
232
233 fn set_ahs_length_bytes(&mut self, len: u8) {
234 self.total_ahs_length = len >> 2;
235 }
236
237 fn get_data_length_bytes(&self) -> usize {
238 u32::from_be_bytes([
239 0,
240 self.data_segment_length[0],
241 self.data_segment_length[1],
242 self.data_segment_length[2],
243 ]) as usize
244 }
245
246 fn set_data_length_bytes(&mut self, len: u32) {
247 let be = len.to_be_bytes();
248 self.data_segment_length = [be[1], be[2], be[3]];
249 }
250
251 fn get_header_diggest(&self, _: bool) -> usize {
252 0
253 }
254
255 fn get_data_diggest(&self, _: bool) -> usize {
256 0
257 }
258}
259
260impl ZeroCopyType for LoginRequest {}