1/*
2 * IMPORTANT:  READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
3 * By downloading, copying, installing or using the software you agree
4 * to this license.  If you do not agree to this license, do not
5 * download, install, copy or use the software.
6 *
7 * Intel License Agreement
8 *
9 * Copyright (c) 2000, Intel Corporation
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 *
16 * -Redistributions of source code must retain the above copyright
17 *  notice, this list of conditions and the following disclaimer.
18 *
19 * -Redistributions in binary form must reproduce the above copyright
20 *  notice, this list of conditions and the following disclaimer in the
21 *  documentation and/or other materials provided with the
22 *  distribution.
23 *
24 * -The name of Intel Corporation may not be used to endorse or
25 *  promote products derived from this software without specific prior
26 *  written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
31 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL INTEL
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
35 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
36 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
37 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
38 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
40 */
41#include "config.h"
42
43#ifdef HAVE_STDLIB_H
44#include <stdlib.h>
45#endif
46
47#ifdef HAVE_NETINET_IN_H
48#include <netinet/in.h>
49#endif
50
51#ifdef HAVE_SYS_UIO_H
52#include <sys/uio.h>
53#endif
54
55#ifdef HAVE_STRING_H
56#include <string.h>
57#endif
58
59#ifdef HAVE_INTTYPES_H
60#include <inttypes.h>
61#endif
62
63#include "iscsiprotocol.h"
64#include "iscsiutil.h"
65#include <compat.h>
66
67
68/*
69 * Task Command
70 */
71
72int
73iscsi_task_cmd_encap(uint8_t *header, iscsi_task_cmd_t * cmd)
74{
75	iscsi_trace(TRACE_ISCSI_ARGS, "Immediate: %d\n", cmd->immediate);
76	iscsi_trace(TRACE_ISCSI_ARGS, "Function:  %u\n", cmd->function);
77	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:       %" PRIu64 "\n", cmd->lun);
78	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:       %#x\n", cmd->tag);
79	iscsi_trace(TRACE_ISCSI_ARGS, "Ref Tag:   %#x\n", cmd->ref_tag);
80	iscsi_trace(TRACE_ISCSI_ARGS, "CmdSN:     %u\n", cmd->CmdSN);
81	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN: %u\n", cmd->ExpStatSN);
82	iscsi_trace(TRACE_ISCSI_ARGS, "RefCmdSN:  %u\n", cmd->RefCmdSN);
83	iscsi_trace(TRACE_ISCSI_ARGS, "ExpDataSN: %u\n", cmd->ExpDataSN);
84
85	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
86
87	header[0] |= ISCSI_TASK_CMD;	/* Opcode */
88	if (cmd->immediate) {
89		header[0] |= 0x40;	/* Immediate bit  */
90	}
91	header[1] = cmd->function & 0x80;	/* Function  */
92	*((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL(cmd->lun);	/* LUN */
93	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag);	/* Tag */
94	*((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(cmd->ref_tag);	/* Reference Tag */
95	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->CmdSN);	/* CmdSN */
96	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpStatSN);	/* ExpStatSN */
97	*((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(cmd->RefCmdSN);	/* RefCmdSN */
98	*((uint32_t *) (void *) (header + 36)) = ISCSI_HTONL(cmd->ExpDataSN);	/* ExpDataSN */
99
100	return 0;
101}
102
103int
104iscsi_task_cmd_decap(uint8_t *header, iscsi_task_cmd_t * cmd)
105{
106	const char	*errmsg;
107	uint8_t		 zeros[16];
108
109	if (ISCSI_OPCODE(header) != ISCSI_TASK_CMD) {
110		iscsi_err(__FILE__, __LINE__, "Opcode");
111		return 1;
112	}
113	cmd->immediate = ((header[0] & 0x40) == 0x40);
114	cmd->function = header[1] & 0x80;
115	cmd->lun = ISCSI_NTOHLL(*((uint64_t *) (void *) (header + 8)));
116	cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));
117	cmd->ref_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20)));
118	cmd->CmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));
119	cmd->ExpStatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));
120	cmd->RefCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32)));
121	cmd->ExpDataSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 36)));
122
123	errmsg = NULL;
124	(void) memset(zeros, 0x0, sizeof(zeros));
125	if ((header[1] & 0x80) != 0x80) {
126		errmsg = "Byte 1 bit 0";
127	} else if (header[2] != 0) {
128		errmsg = "Byte 2";
129	} else if (header[3] != 0) {
130		errmsg = "Byte 3";
131	} else if (memcmp(header + 4, zeros, 4) != 0) {
132		errmsg = "Bytes 4-7";
133	} else if (memcmp(header + 40, zeros, 8) != 0) {
134		errmsg = "Bytes 40-47";
135	}
136	if (errmsg) {
137		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
138		NO_CLEANUP;
139		return 1;
140	}
141
142	iscsi_trace(TRACE_ISCSI_ARGS, "Immediate: %d\n", cmd->immediate);
143	iscsi_trace(TRACE_ISCSI_ARGS, "Function:  %u\n", cmd->function);
144	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:       %" PRIu64 "\n", cmd->lun);
145	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:       %#x\n", cmd->tag);
146	iscsi_trace(TRACE_ISCSI_ARGS, "Ref Tag:   %#x\n", cmd->ref_tag);
147	iscsi_trace(TRACE_ISCSI_ARGS, "CmdSN:     %u\n", cmd->CmdSN);
148	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN: %u\n", cmd->ExpStatSN);
149	iscsi_trace(TRACE_ISCSI_ARGS, "RefCmdSN:  %u\n", cmd->RefCmdSN);
150	iscsi_trace(TRACE_ISCSI_ARGS, "ExpDataSN: %u\n", cmd->ExpDataSN);
151	return 0;
152}
153
154/*
155 * Task Response
156 */
157
158int
159iscsi_task_rsp_encap(uint8_t *header, iscsi_task_rsp_t * rsp)
160{
161	uint32_t        length;
162
163	iscsi_trace(TRACE_ISCSI_ARGS, "Response:  %u\n", rsp->response);
164	iscsi_trace(TRACE_ISCSI_ARGS, "Length:    %u\n", rsp->length);
165	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:       %#x\n", rsp->tag);
166	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:    %u\n", rsp->StatSN);
167	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:  %u\n", rsp->ExpCmdSN);
168	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:  %u\n", rsp->MaxCmdSN);
169
170	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
171
172	header[0] |= ISCSI_TASK_RSP;	/* Opcode */
173	header[1] |= 0x80;	/* Byte 1 bit 0  */
174	header[2] = rsp->response;	/* Response */
175	length = (rsp->length & 0x00ffffff);	/* Length */
176	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(length);
177	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(rsp->tag);
178	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(rsp->StatSN);
179	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(rsp->ExpCmdSN);
180	*((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(rsp->MaxCmdSN);
181	return 0;
182}
183
184int
185iscsi_task_rsp_decap(uint8_t *header, iscsi_task_rsp_t * rsp)
186{
187	const char	*errmsg;
188	uint8_t		 zeros[16];
189
190	if (ISCSI_OPCODE(header) != ISCSI_TASK_RSP) {
191		iscsi_err(__FILE__, __LINE__, "Opcode");
192		return 1;
193	}
194	rsp->response = header[2];
195	rsp->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));
196	rsp->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));
197	rsp->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));
198	rsp->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32)));
199	errmsg = NULL;
200	(void) memset(zeros, 0x0, sizeof(zeros));
201	if ((header[0] & 0x00) != 0x00) {
202		errmsg = "Byte 0 bits 0-1";
203	} else if ((header[1] & 0x80) != 0x80) {
204		errmsg = "Byte 1 bit 0";
205	} else if (header[3] != 0) {
206		errmsg = "Byte 3";
207	} else if (memcmp(header + 4, zeros, 12) != 0) {
208		errmsg = "Bytes 4-15";
209	} else if (memcmp(header + 20, zeros, 4) != 0) {
210		errmsg = "Bytes 20-23";
211	} else if (memcmp(header + 36, zeros, 12) != 0) {
212		errmsg = "Bytes 36-47";
213	}
214	if (errmsg) {
215		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
216		NO_CLEANUP;
217		return 1;
218	}
219	iscsi_trace(TRACE_ISCSI_ARGS, "Response:  %u\n", rsp->response);
220	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:       %#x\n", rsp->tag);
221	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:    %u\n", rsp->StatSN);
222	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:  %u\n", rsp->ExpCmdSN);
223	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:  %u\n", rsp->MaxCmdSN);
224	return 0;
225}
226
227/*
228 * NOP-Out
229 */
230
231int
232iscsi_nop_out_encap(uint8_t *header, iscsi_nop_out_args_t * cmd)
233{
234
235	uint32_t        length;
236
237	iscsi_trace(TRACE_ISCSI_ARGS, "Immediate:    %d\n", cmd->immediate);
238	iscsi_trace(TRACE_ISCSI_ARGS, "Length:       %u\n", cmd->length);
239	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:          %" PRIu64 "\n", cmd->lun);
240	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:          %#x\n", cmd->tag);
241	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag: %#x\n", cmd->transfer_tag);
242	iscsi_trace(TRACE_ISCSI_ARGS, "CmdSN:        %u\n", cmd->CmdSN);
243	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN:    %u\n", cmd->ExpStatSN);
244
245	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
246
247	header[0] = ISCSI_NOP_OUT;	/* Opcode */
248	if (cmd->immediate) {
249		header[0] |= 0x40;	/* Immediate bit */
250	}
251	header[1] |= 0x80;	/* Byte 1 bit 0 and Reserved */
252	length = (cmd->length & 0x00ffffff);	/* Length  */
253	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(length);	/* Length  */
254	*((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL(cmd->lun);	/* LUN */
255	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag);	/* Tag */
256	*((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(cmd->transfer_tag);	/* Target Transfer Tag  */
257	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->CmdSN);	/* CmdSN */
258	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpStatSN);	/* ExpStatSN */
259
260	return 0;
261}
262
263int
264iscsi_nop_out_decap(uint8_t *header, iscsi_nop_out_args_t * cmd)
265{
266	const char	*errmsg;
267	uint8_t		 zeros[16];
268
269	if (ISCSI_OPCODE(header) != ISCSI_NOP_OUT) {
270		iscsi_err(__FILE__, __LINE__, "Opcode");
271		return 1;
272	}
273	cmd->immediate = ((header[0] & 0x40) == 0x40);	/* Immediate bit  */
274	cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* Length */
275	cmd->lun = ISCSI_NTOHLL(*((uint64_t *) (void *) (header + 8)));	/* LUN */
276	cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));	/* Tag */
277	cmd->transfer_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20)));	/* Target Tranfer Tag */
278	cmd->CmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* CmdSN */
279	cmd->ExpStatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpStatSN */
280
281	errmsg = NULL;
282	(void) memset(zeros, 0x0, sizeof(zeros));
283	if (header[1] != 0x80) {
284		errmsg = "Byte 1";
285	} else if (memcmp(header + 2, zeros, 3) != 0) {
286		errmsg = "Bytes 2-4";
287	} else if (memcmp(header + 32, zeros, 16) != 0) {
288		errmsg = "Bytes 32-47";
289	}
290	if (errmsg) {
291		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
292		NO_CLEANUP;
293		return 1;
294	}
295	iscsi_trace(TRACE_ISCSI_ARGS, "Immediate:    %d\n", cmd->immediate);
296	iscsi_trace(TRACE_ISCSI_ARGS, "Length:       %u\n", cmd->length);
297	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:          %" PRIu64 "\n", cmd->lun);
298	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:          %#x\n", cmd->tag);
299	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag: %#x\n", cmd->transfer_tag);
300	iscsi_trace(TRACE_ISCSI_ARGS, "CmdSN:        %u\n", cmd->CmdSN);
301	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN:    %u\n", cmd->ExpStatSN);
302	return 0;
303}
304
305/*
306 * NOP-In
307 */
308
309int
310iscsi_nop_in_encap(uint8_t *header, iscsi_nop_in_args_t * cmd)
311{
312	uint32_t        length;
313
314	iscsi_trace(TRACE_ISCSI_ARGS, "Length:       %u\n", cmd->length);
315	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:          %" PRIu64 "\n", cmd->lun);
316	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:          %#x\n", cmd->tag);
317	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag: %#x\n", cmd->transfer_tag);
318	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:       %u\n", cmd->StatSN);
319	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:     %u\n", cmd->ExpCmdSN);
320	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:     %u\n", cmd->MaxCmdSN);
321
322	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
323
324	header[0] = 0x00 | ISCSI_NOP_IN;	/* Opcode  */
325	header[1] |= 0x80;	/* Reserved */
326	length = (cmd->length & 0x00ffffff);	/* Length */
327	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(length);	/* Length */
328	*((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL(cmd->lun);	/* LUN */
329	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag);	/* Tag */
330	*((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(cmd->transfer_tag);	/* Target Transfer Tag        */
331	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->StatSN);	/* StatSN */
332	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpCmdSN);	/* ExpCmdSN */
333	*((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(cmd->MaxCmdSN);	/* MaxCmdSN */
334
335	return 0;
336}
337
338int
339iscsi_nop_in_decap(uint8_t *header, iscsi_nop_in_args_t * cmd)
340{
341	const char	*errmsg;
342	uint8_t		 zeros[16];
343
344	if (ISCSI_OPCODE(header) != ISCSI_NOP_IN) {
345		iscsi_err(__FILE__, __LINE__, "Opcode");
346		return 1;
347	}
348	cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* Length */
349	cmd->lun = ISCSI_NTOHLL(*((uint64_t *) (void *) (header + 8)));	/* LUN */
350	cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));	/* Tag */
351	cmd->transfer_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20)));	/* Target Transfer Tag */
352	cmd->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* StatSN  */
353	cmd->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpCmdSN */
354	cmd->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32)));	/* MaxCmdSN */
355
356	errmsg = NULL;
357	(void) memset(zeros, 0x0, sizeof(zeros));
358	if ((header[0] & 0xc0) != 0x00) {
359		errmsg = "Byte 0, bits 0-1";
360	} else if (header[1] != 0x80) {
361		errmsg = "Byte 1";
362	} else if (memcmp(header + 2, zeros, 3) != 0) {
363		errmsg = "Bytes 2-4";
364	} else if (memcmp(header + 36, zeros, 12) != 0) {
365		errmsg = "Bytes 36-47";
366	}
367	if (errmsg) {
368		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
369		NO_CLEANUP;
370		return 1;
371	}
372	iscsi_trace(TRACE_ISCSI_ARGS, "Length:       %u\n", cmd->length);
373	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:          %" PRIu64 "\n", cmd->lun);
374	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:          %#x\n", cmd->tag);
375	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag: %#x\n", cmd->transfer_tag);
376	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:       %u\n", cmd->StatSN);
377	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:     %u\n", cmd->ExpCmdSN);
378	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:     %u\n", cmd->MaxCmdSN);
379	return 0;
380}
381
382/*
383 * Text Command
384 */
385
386int
387iscsi_text_cmd_encap(uint8_t *header, iscsi_text_cmd_args_t * cmd)
388{
389	uint32_t        length;
390
391	iscsi_trace(TRACE_ISCSI_ARGS, "Immediate:    %d\n", cmd->immediate);
392	iscsi_trace(TRACE_ISCSI_ARGS, "Final:        %d\n", cmd->final);
393	iscsi_trace(TRACE_ISCSI_ARGS, "Continue:     %d\n", cmd->cont);
394	iscsi_trace(TRACE_ISCSI_ARGS, "Length:       %u\n", cmd->length);
395	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:          %" PRIu64 "\n", cmd->lun);
396	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:          %#x\n", cmd->tag);
397	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag: %#x\n", cmd->transfer_tag);
398	iscsi_trace(TRACE_ISCSI_ARGS, "CmdSN:        %u\n", cmd->CmdSN);
399	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN:    %u\n", cmd->ExpStatSN);
400
401	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
402
403	header[0] |= ISCSI_TEXT_CMD;	/* Opcode */
404	if (cmd->immediate) {
405		header[0] |= 0x40;	/* Immediate bit */
406	}
407	if (cmd->final) {
408		header[1] |= 0x80;	/* Final bit */
409	}
410	if (cmd->cont) {
411		header[1] |= 0x40;	/* Continue bit */
412	}
413	length = (cmd->length & 0x00ffffff);	/* Length */
414	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(length);	/* Length */
415	*((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL(cmd->lun);	/* LUN */
416	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag);	/* Tag */
417	*((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(cmd->transfer_tag);	/* Transfer Tag */
418	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->CmdSN);	/* CmdSN */
419	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpStatSN);	/* ExpStatSN */
420
421	return 0;
422}
423
424int
425iscsi_text_cmd_decap(uint8_t *header, iscsi_text_cmd_args_t * cmd)
426{
427	const char	*errmsg;
428	uint8_t		 zeros[16];
429
430	if (ISCSI_OPCODE(header) != ISCSI_TEXT_CMD) {
431		iscsi_err(__FILE__, __LINE__, "Opcode");
432		return 1;
433	}
434	cmd->immediate = ((header[0] & 0x40) == 0x40);	/* Immediate bit  */
435	cmd->final = ((header[1] & 0x80) == 0x80);	/* Final bit */
436	cmd->cont = ((header[1] & 0x40) == 0x40);	/* Continue bit */
437	cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* Length */
438	cmd->lun = ISCSI_NTOHLL(*((uint64_t *) (void *) (header + 8)));	/* LUN */
439	cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));	/* Tag */
440	cmd->transfer_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20)));	/* Transfer Tag */
441	cmd->CmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* CmdSN */
442	cmd->ExpStatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpStatSN */
443
444	errmsg = NULL;
445	(void) memset(zeros, 0x0, sizeof(zeros));
446	if ((header[1] & 0x00) != 0x00) {
447		errmsg = "Byte 1, bits 2-7";
448	} else if (memcmp(header + 2, zeros, 3) != 0) {
449		errmsg = "Bytes 2-4";
450	} else if (memcmp(header + 8, zeros, 8) != 0) {
451		errmsg = "Bytes 8-15";
452	} else if (memcmp(header + 32, zeros, 16) != 0) {
453		errmsg = "Bytes 32-47";
454	}
455	if (errmsg) {
456		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
457		NO_CLEANUP;
458		return 1;
459	}
460	iscsi_trace(TRACE_ISCSI_ARGS, "Immediate:    %d\n", cmd->immediate);
461	iscsi_trace(TRACE_ISCSI_ARGS, "Final:        %d\n", cmd->final);
462	iscsi_trace(TRACE_ISCSI_ARGS, "Continue:     %d\n", cmd->cont);
463	iscsi_trace(TRACE_ISCSI_ARGS, "Length:       %u\n", cmd->length);
464	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:          %" PRIu64 "\n", cmd->lun);
465	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:          %#x\n", cmd->tag);
466	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag: %#x\n", cmd->transfer_tag);
467	iscsi_trace(TRACE_ISCSI_ARGS, "CmdSN:        %u\n", cmd->CmdSN);
468	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN:    %u\n", cmd->ExpStatSN);
469
470	return 0;
471}
472
473/*
474 * Text Response
475 */
476
477int
478iscsi_text_rsp_encap(uint8_t *header, iscsi_text_rsp_args_t * rsp)
479{
480	uint32_t        length;
481
482	iscsi_trace(TRACE_ISCSI_ARGS, "Final:        %d\n", rsp->final);
483	iscsi_trace(TRACE_ISCSI_ARGS, "Continue:     %d\n", rsp->cont);
484	iscsi_trace(TRACE_ISCSI_ARGS, "Length:       %u\n", rsp->length);
485	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:          %" PRIu64 "\n", rsp->lun);
486	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:          %#x\n", rsp->tag);
487	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag: %#x\n", rsp->transfer_tag);
488	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:       %u\n", rsp->StatSN);
489	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:     %u\n", rsp->ExpCmdSN);
490	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:     %u\n", rsp->MaxCmdSN);
491
492	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
493	header[0] |= 0x00 | ISCSI_TEXT_RSP;	/* Opcode */
494	if (rsp->final) {
495		header[1] |= 0x80;	/* Final bit */
496	}
497	if (rsp->cont) {
498		header[1] |= 0x40;	/* Continue */
499	}
500	length = (rsp->length & 0x00ffffff);	/* Length */
501	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(length);	/* Length */
502	*((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL(rsp->lun);	/* LUN */
503	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(rsp->tag);	/* Tag */
504	*((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(rsp->transfer_tag);	/* Transfer Tag */
505	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(rsp->StatSN);	/* StatSN */
506	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(rsp->ExpCmdSN);	/* ExpCmdSN */
507	*((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(rsp->MaxCmdSN);	/* MaxCmdSN */
508
509	return 0;
510}
511
512int
513iscsi_text_rsp_decap(uint8_t *header, iscsi_text_rsp_args_t * rsp)
514{
515	const char	*errmsg;
516	uint8_t		 zeros[16];
517
518	if (ISCSI_OPCODE(header) != ISCSI_TEXT_RSP) {
519		iscsi_err(__FILE__, __LINE__, "Opcode");
520		return 1;
521	}
522	rsp->final = ((header[1] & 0x80) == 0x80);	/* Final bit  */
523	rsp->cont = ((header[1] & 0x40) == 0x40);	/* Continue bit */
524	rsp->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* Length */
525	rsp->lun = ISCSI_NTOHLL(*((uint64_t *) (void *) (header + 8)));	/* LUN */
526	rsp->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));	/* Tag */
527	rsp->transfer_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20)));	/* Transfer Tag */
528	rsp->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* StatSN */
529	rsp->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpCmdSN */
530	rsp->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32)));	/* MaxCmdSN */
531
532	errmsg = NULL;
533	(void) memset(zeros, 0x0, sizeof(zeros));
534	if ((header[1] & 0x3f) != 0x00) {
535		errmsg = "Byte 1, bits 2-7";
536	} else if (memcmp(header + 2, zeros, 3) != 0) {
537		errmsg = "Bytes 2-4";
538	} else if (memcmp(header + 8, zeros, 8) != 0) {
539		errmsg = "Bytes 8-15";
540	} else if (memcmp(header + 36, zeros, 12) != 0) {
541		errmsg = "Bytes 36-47";
542	}
543	if (errmsg) {
544		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
545		NO_CLEANUP;
546		return 1;
547	}
548	iscsi_trace(TRACE_ISCSI_ARGS, "Final:        %d\n", rsp->final);
549	iscsi_trace(TRACE_ISCSI_ARGS, "Continue:     %d\n", rsp->cont);
550	iscsi_trace(TRACE_ISCSI_ARGS, "Length:       %u\n", rsp->length);
551	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:          %" PRIu64 "\n", rsp->lun);
552	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:          %#x\n", rsp->tag);
553	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag: %#x\n", rsp->transfer_tag);
554	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:       %u\n", rsp->StatSN);
555	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:     %u\n", rsp->ExpCmdSN);
556	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:     %u\n", rsp->MaxCmdSN);
557
558	return 0;
559}
560
561/*
562 * Login Command
563 */
564
565int
566iscsi_login_cmd_encap(uint8_t *header, iscsi_login_cmd_args_t * cmd)
567{
568	uint32_t        length;
569
570	iscsi_trace(TRACE_ISCSI_ARGS, "Transit:           %d\n", cmd->transit);
571	iscsi_trace(TRACE_ISCSI_ARGS, "Continue:          %d\n", cmd->cont);
572	iscsi_trace(TRACE_ISCSI_ARGS, "CSG:               %u\n", cmd->csg);
573	iscsi_trace(TRACE_ISCSI_ARGS, "NSG:               %u\n", cmd->nsg);
574	iscsi_trace(TRACE_ISCSI_ARGS, "Version_min:       %u\n", cmd->version_min);
575	iscsi_trace(TRACE_ISCSI_ARGS, "Version_max:       %u\n", cmd->version_max);
576	iscsi_trace(TRACE_ISCSI_ARGS, "TotalAHSLength:    %u\n", cmd->AHSlength);
577	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength: %u\n", cmd->length);
578	iscsi_trace(TRACE_ISCSI_ARGS, "ISID:              %" PRIu64 "\n", cmd->isid);
579	iscsi_trace(TRACE_ISCSI_ARGS, "TSIH:              %hu\n", cmd->tsih);
580	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:          %#x\n", cmd->tag);
581	iscsi_trace(TRACE_ISCSI_ARGS, "CID:               %hu\n", cmd->cid);
582	iscsi_trace(TRACE_ISCSI_ARGS, "CmdSN:             %u\n", cmd->CmdSN);
583	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN:         %u\n", cmd->ExpStatSN);
584
585	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
586
587	header[0] |= 0x40 | ISCSI_LOGIN_CMD;	/* Opcode  */
588	if (cmd->transit) {
589		header[1] |= 0x80;	/* Transit */
590	}
591	if (cmd->cont) {
592		header[1] |= 0x40;	/* Continue */
593	}
594	header[1] |= ((cmd->csg) << 2) & 0x0c;	/* CSG */
595	header[1] |= (cmd->nsg) & 0x03;	/* NSG */
596	header[2] = cmd->version_max;	/* Version-Max  */
597	header[3] = cmd->version_min;	/* Version-Min  */
598	header[4] = cmd->AHSlength;	/* TotalAHSLength */
599	length = (cmd->length & 0x00ffffff);	/* Length  */
600	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(length);	/* Length  */
601	*((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL(cmd->isid << 16);	/* ISID */
602	*((uint16_t *) (void *) (header + 14)) = ISCSI_HTONS(cmd->tsih);	/* TSIH */
603	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag);	/* Task Tag */
604	*((uint16_t *) (void *) (header + 20)) = ISCSI_HTONS(cmd->cid);	/* CID */
605	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->CmdSN);	/* CmdSN */
606	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpStatSN);	/* ExpStatSN */
607
608	return 0;
609}
610
611int
612iscsi_login_cmd_decap(uint8_t *header, iscsi_login_cmd_args_t * cmd)
613{
614	const char	*errmsg;
615	uint8_t		 zeros[16];
616
617	if (ISCSI_OPCODE(header) != ISCSI_LOGIN_CMD) {
618		iscsi_err(__FILE__, __LINE__, "Opcode");
619		return 1;
620	}
621	cmd->transit = (header[1] & 0x80) ? 1 : 0;	/* Transit */
622	cmd->cont = (header[1] & 0x40) ? 1 : 0;	/* Continue */
623	cmd->csg = (header[1] & 0x0cU) >> 2;	/* CSG */
624	cmd->nsg = header[1] & 0x03;	/* NSG */
625	cmd->version_max = header[2];	/* Version-Max  */
626	cmd->version_min = header[3];	/* Version-Min  */
627	cmd->AHSlength = header[4];	/* TotalAHSLength */
628	cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* Length */
629	cmd->isid = ISCSI_NTOHLL(*((uint64_t *) (void *) (header + 8))) >> 16;	/* ISID */
630	cmd->tsih = ISCSI_NTOHS(*((uint16_t *) (void *) (header + 14)));	/* TSIH */
631	cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));	/* Task Tag */
632	cmd->cid = ISCSI_NTOHS(*((uint16_t *) (void *) (header + 20)));	/* CID */
633	cmd->CmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* CmdSN  */
634	cmd->ExpStatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpStatSN */
635
636	iscsi_trace(TRACE_ISCSI_ARGS, "Transit:           %d\n", cmd->transit);
637	iscsi_trace(TRACE_ISCSI_ARGS, "Continue:          %d\n", cmd->cont);
638	iscsi_trace(TRACE_ISCSI_ARGS, "CSG:               %u\n", cmd->csg);
639	iscsi_trace(TRACE_ISCSI_ARGS, "NSG:               %u\n", cmd->nsg);
640	iscsi_trace(TRACE_ISCSI_ARGS, "Version_min:       %u\n", cmd->version_min);
641	iscsi_trace(TRACE_ISCSI_ARGS, "Version_max:       %u\n", cmd->version_max);
642	iscsi_trace(TRACE_ISCSI_ARGS, "TotalAHSLength:    %u\n", cmd->AHSlength);
643	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength: %u\n", cmd->length);
644	iscsi_trace(TRACE_ISCSI_ARGS, "ISID:              %" PRIu64 "\n", cmd->isid);
645	iscsi_trace(TRACE_ISCSI_ARGS, "TSIH:              %hu\n", cmd->tsih);
646	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:          %#x\n", cmd->tag);
647	iscsi_trace(TRACE_ISCSI_ARGS, "CID:               %hu\n", cmd->cid);
648	iscsi_trace(TRACE_ISCSI_ARGS, "CmdSN:             %u\n", cmd->CmdSN);
649	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN:         %u\n", cmd->ExpStatSN);
650
651	errmsg = NULL;
652	(void) memset(zeros, 0x0, sizeof(zeros));
653	if (((header[1] & 0x30U) >> 4U) != 0x0) {
654		errmsg = "Byte 1, bits 2-3";
655	} else if (memcmp(header + 22, zeros, 2) != 0) {
656		errmsg = "Bytes 22-23";
657	} else if (memcmp(header + 32, zeros, 16) != 0) {
658		errmsg = "Bytes 32-47";
659	}
660	if (errmsg) {
661		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
662		NO_CLEANUP;
663		return 1;
664	}
665	if (cmd->transit) {
666		if (cmd->nsg <= cmd->csg) {
667			return -1;
668		}
669		if ((cmd->nsg != 0) && (cmd->nsg != 1) && (cmd->nsg != 3)) {
670			return -1;
671		}
672	}
673	return 0;
674}
675
676/*
677 * Login Response
678 */
679
680int
681iscsi_login_rsp_encap(uint8_t *header, iscsi_login_rsp_args_t * rsp)
682{
683
684	iscsi_trace(TRACE_ISCSI_ARGS, "Transit:           %d\n", rsp->transit);
685	iscsi_trace(TRACE_ISCSI_ARGS, "Continue:          %d\n", rsp->cont);
686	iscsi_trace(TRACE_ISCSI_ARGS, "CSG:               %u\n", rsp->csg);
687	iscsi_trace(TRACE_ISCSI_ARGS, "NSG:               %u\n", rsp->nsg);
688	iscsi_trace(TRACE_ISCSI_ARGS, "Version_max:       %u\n", rsp->version_max);
689	iscsi_trace(TRACE_ISCSI_ARGS, "Version_active:    %u\n", rsp->version_active);
690	iscsi_trace(TRACE_ISCSI_ARGS, "TotalAHSLength:    %u\n", rsp->AHSlength);
691	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength: %u\n", rsp->length);
692	iscsi_trace(TRACE_ISCSI_ARGS, "ISID:              %" PRIu64 "\n", rsp->isid);
693	iscsi_trace(TRACE_ISCSI_ARGS, "TSIH:              %u\n", rsp->tsih);
694	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:          %#x\n", rsp->tag);
695	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:            %u\n", rsp->StatSN);
696	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:          %u\n", rsp->ExpCmdSN);
697	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:          %u\n", rsp->MaxCmdSN);
698	iscsi_trace(TRACE_ISCSI_ARGS, "Status-Class:      %u\n", rsp->status_class);
699	iscsi_trace(TRACE_ISCSI_ARGS, "Status-Detail:     %u\n", rsp->status_detail);
700
701	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
702
703	header[0] |= 0x00 | ISCSI_LOGIN_RSP;	/* Opcode  */
704	if (rsp->transit) {
705		header[1] |= 0x80;	/* Transit  */
706	}
707	if (rsp->cont) {
708		header[1] |= 0x40;	/* Continue */
709	}
710	header[1] |= ((rsp->csg) << 2) & 0x0c;	/* CSG */
711	if (rsp->transit) {
712		header[1] |= (rsp->nsg) & 0x03;	/* NSG */
713	}
714	header[2] = rsp->version_max;	/* Version-max */
715	header[3] = rsp->version_active;	/* Version-active */
716	header[4] = rsp->AHSlength;	/* TotalAHSLength */
717	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(rsp->length);	/* Length */
718	*((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL(rsp->isid << 16);	/* ISID */
719	*((uint16_t *) (void *) (header + 14)) = ISCSI_HTONS(rsp->tsih);	/* TSIH */
720	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(rsp->tag);	/* Tag  */
721	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(rsp->StatSN);	/* StatRn */
722	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(rsp->ExpCmdSN);	/* ExpCmdSN */
723	*((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(rsp->MaxCmdSN);	/* MaxCmdSN */
724	header[36] = rsp->status_class;	/* Status-Class */
725	header[37] = rsp->status_detail;	/* Status-Detail */
726
727	return 0;
728}
729
730int
731iscsi_login_rsp_decap(uint8_t *header, iscsi_login_rsp_args_t * rsp)
732{
733	const char	*errmsg;
734	uint8_t		 zeros[8];
735
736	if (ISCSI_OPCODE(header) != ISCSI_LOGIN_RSP) {
737		iscsi_err(__FILE__, __LINE__, "Opcode");
738		return 1;
739	}
740	rsp->transit = (header[1] & 0x80U) >> 7;	/* Transit  */
741	rsp->cont = (header[1] & 0x40U) >> 6;	/* Continue */
742	rsp->csg = (header[1] & 0x0cU) >> 2;	/* CSG  */
743	rsp->nsg = header[1] & 0x03;	/* NSG  */
744	rsp->version_max = header[2];	/* Version-max */
745	rsp->version_active = header[3];	/* Version-active */
746	rsp->AHSlength = header[4];	/* TotalAHSLength */
747	rsp->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* Length */
748	rsp->isid = ISCSI_NTOHLL(*((uint64_t *) (void *) (header + 8))) >> 16;	/* ISID */
749	rsp->tsih = ISCSI_NTOHS(*((uint16_t *) (void *) (header + 14)));	/* TSIH */
750
751	rsp->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));	/* Tag */
752	rsp->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* StatSN */
753	rsp->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpCmdSN */
754	rsp->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32)));	/* MaxCmdSN  */
755	rsp->status_class = header[36];	/* Status-Class */
756	rsp->status_detail = header[37];	/* Status-Detail */
757
758	iscsi_trace(TRACE_ISCSI_ARGS, "Transit:           %d\n", rsp->transit);
759	iscsi_trace(TRACE_ISCSI_ARGS, "Continue:          %d\n", rsp->cont);
760	iscsi_trace(TRACE_ISCSI_ARGS, "CSG:               %u\n", rsp->csg);
761	iscsi_trace(TRACE_ISCSI_ARGS, "NSG:               %u\n", rsp->nsg);
762
763	iscsi_trace(TRACE_ISCSI_ARGS, "Version_max:       %u\n", rsp->version_max);
764	iscsi_trace(TRACE_ISCSI_ARGS, "Version_active:    %u\n", rsp->version_active);
765	iscsi_trace(TRACE_ISCSI_ARGS, "TotalAHSLength:    %u\n", rsp->AHSlength);
766	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength: %u\n", rsp->length);
767	iscsi_trace(TRACE_ISCSI_ARGS, "ISID:              %" PRIu64 "\n", rsp->isid);
768	iscsi_trace(TRACE_ISCSI_ARGS, "TSIH:              %u\n", rsp->tsih);
769	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:          %#x\n", rsp->tag);
770	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:            %u\n", rsp->StatSN);
771	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:          %u\n", rsp->ExpCmdSN);
772	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:          %u\n", rsp->MaxCmdSN);
773	iscsi_trace(TRACE_ISCSI_ARGS, "Status-Class:      %u\n", rsp->status_class);
774	iscsi_trace(TRACE_ISCSI_ARGS, "Status-Detail:     %u\n", rsp->status_detail);
775	errmsg = NULL;
776	(void) memset(zeros, 0x0, sizeof(zeros));
777	if (((header[1] & 0x30U) >> 4U) != 0x0) {
778		errmsg = "Byte 1, bits 2-3";
779	} else if (memcmp(header + 20, zeros, 4) != 0) {
780		errmsg = "Bytes 20-23";
781	} else if (memcmp(header + 38, zeros, 2) != 0) {
782		errmsg = "Bytes 38-39";
783	} else if (memcmp(header + 40, zeros, 8) != 0) {
784		errmsg = "Bytes 40-47";
785	}
786	if (errmsg) {
787		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
788		NO_CLEANUP;
789		return 1;
790	}
791	return 0;
792}
793
794/*
795 * Logout Command
796 */
797
798int
799iscsi_logout_cmd_encap(uint8_t *header, iscsi_logout_cmd_args_t * cmd)
800{
801
802	iscsi_trace(TRACE_ISCSI_ARGS, "Immediate: %d\n", cmd->immediate);
803	iscsi_trace(TRACE_ISCSI_ARGS, "Reason:    %u\n", cmd->reason);
804	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:  %#x\n", cmd->tag);
805	iscsi_trace(TRACE_ISCSI_ARGS, "CID:       %hu\n", cmd->cid);
806	iscsi_trace(TRACE_ISCSI_ARGS, "CmdSN:     %u\n", cmd->CmdSN);
807	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN: %u\n", cmd->ExpStatSN);
808
809	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
810
811	header[0] = ISCSI_LOGOUT_CMD;	/* Opcode */
812	if (cmd->immediate) {
813		header[0] |= 0x40;	/* Immediate */
814	}
815	header[1] = cmd->reason | 0x80;	/* Reason  */
816	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag);	/* Tag */
817	*((uint16_t *) (void *) (header + 20)) = ISCSI_HTONS(cmd->cid);	/* CID */
818	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->CmdSN);	/* CmdSN */
819	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpStatSN);	/* ExpStatSN  */
820
821	return 0;
822}
823
824int
825iscsi_logout_cmd_decap(uint8_t *header, iscsi_logout_cmd_args_t * cmd)
826{
827	const char	*errmsg;
828	uint8_t		 zeros[16];
829
830	if (ISCSI_OPCODE(header) != ISCSI_LOGOUT_CMD) {
831		iscsi_err(__FILE__, __LINE__, "Opcode");
832		return 1;
833	}
834	cmd->immediate = (header[0] & 0x40) ? 1 : 0;	/* Immediate */
835	cmd->reason = header[1] & 0x7f;	/* Reason */
836	cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));	/* Tag */
837	cmd->cid = ISCSI_NTOHS(*((uint16_t *) (void *) (header + 20)));	/* CID */
838	cmd->CmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* CmdSN */
839	cmd->ExpStatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpStatSN */
840
841	iscsi_trace(TRACE_ISCSI_ARGS, "Immediate: %d\n", cmd->immediate);
842	iscsi_trace(TRACE_ISCSI_ARGS, "Reason:    %u\n", cmd->reason);
843	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:  %#x\n", cmd->tag);
844
845	iscsi_trace(TRACE_ISCSI_ARGS, "CID:       %hu\n", cmd->cid);
846	iscsi_trace(TRACE_ISCSI_ARGS, "CmdSN:     %u\n", cmd->CmdSN);
847	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN: %u\n", cmd->ExpStatSN);
848	errmsg = NULL;
849	(void) memset(zeros, 0x0, sizeof(zeros));
850	if ((unsigned)(header[0]) >> 0x7U != 0) {
851		errmsg = "Byte 0, bit 0";
852	} else if ((unsigned)(header[1]) >> 7U != 1) {
853		errmsg = "Byte 1, bit 0";
854	} else if (header[2] != 0) {
855		errmsg = "Byte 2";
856	} else if (header[3] != 0) {
857		errmsg = "Byte 3";
858	} else if (memcmp(header + 4, zeros, 12) != 0) {
859		errmsg = "Bytes 4-7";
860	} else if (memcmp(header + 22, zeros, 2) != 0) {
861		errmsg = "Bytes 22-23";
862	} else if (memcmp(header + 32, zeros, 16) != 0) {
863		errmsg = "Bytes 32-47";
864	}
865	if (errmsg) {
866		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
867		NO_CLEANUP;
868		return 1;
869	}
870	return 0;
871}
872
873/*
874 * Logout Response
875 */
876
877int
878iscsi_logout_rsp_encap(uint8_t *header, iscsi_logout_rsp_args_t * rsp)
879{
880
881	iscsi_trace(TRACE_ISCSI_ARGS, "Response:    %u\n", rsp->response);
882	iscsi_trace(TRACE_ISCSI_ARGS, "Length:      %u\n", rsp->length);
883	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:    %#x\n", rsp->tag);
884	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:      %u\n", rsp->StatSN);
885	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:    %u\n", rsp->ExpCmdSN);
886	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:    %u\n", rsp->MaxCmdSN);
887
888	iscsi_trace(TRACE_ISCSI_ARGS, "Time2Wait:   %hu\n", rsp->Time2Wait);
889	iscsi_trace(TRACE_ISCSI_ARGS, "Time2Retain: %hu\n", rsp->Time2Retain);
890
891	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
892
893	header[0] |= 0x00 | ISCSI_LOGOUT_RSP;	/* Opcode  */
894	header[1] |= 0x80;	/* Reserved  */
895	header[2] = rsp->response;	/* Response */
896	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(rsp->length);	/* Length */
897	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(rsp->tag);	/* Tag */
898	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(rsp->StatSN);	/* StatSN */
899	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(rsp->ExpCmdSN);	/* ExpCmdSN */
900	*((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(rsp->MaxCmdSN);	/* MaxCmdSN */
901	*((uint16_t *) (void *) (header + 40)) = ISCSI_HTONS(rsp->Time2Wait);	/* Time2Wait */
902	*((uint16_t *) (void *) (header + 42)) = ISCSI_HTONS(rsp->Time2Retain);	/* Time2Retain */
903
904	return 0;
905}
906
907int
908iscsi_logout_rsp_decap(uint8_t *header, iscsi_logout_rsp_args_t * rsp)
909{
910	const char	*errmsg;
911	uint8_t		 zeros[16];
912
913	if (ISCSI_OPCODE(header) != ISCSI_LOGOUT_RSP) {
914		iscsi_err(__FILE__, __LINE__, "Opcode");
915		return 1;
916	}
917	rsp->response = header[2];	/* Response */
918	rsp->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* Length */
919	rsp->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));	/* Tag */
920	rsp->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* StatSN */
921	rsp->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpCmdSN */
922	rsp->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32)));	/* MaxCmdSN  */
923	rsp->Time2Wait = ISCSI_NTOHS(*((uint16_t *) (void *) (header + 40)));	/* Time2Wait */
924	rsp->Time2Retain = ISCSI_NTOHS(*((uint16_t *) (void *) (header + 42)));	/* Time2Retain */
925
926	errmsg = NULL;
927	(void) memset(zeros, 0x0, sizeof(zeros));
928	if ((header[0] & 0x20) != 0x20) {
929		errmsg = "Byte 0, bits 0-1";
930	} else if ((header[1] & 0x80) != 0x80) {
931		errmsg = "Byte 1, bit 0";
932	} else if (header[3] != 0) {
933		errmsg = "Byte 3";
934	} else if (memcmp(header + 4, zeros, 12) != 0) {
935		errmsg = "Bytes 4-15";
936	} else if (memcmp(header + 20, zeros, 4) != 0) {
937		errmsg = "Bytes 20-23";
938	} else if (memcmp(header + 36, zeros, 4) != 0) {
939		errmsg = "Bytes 36-39";
940	} else if (memcmp(header + 44, zeros, 4) != 0) {
941		errmsg = "Bytes 44-47";
942	}
943	if (errmsg) {
944		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
945		NO_CLEANUP;
946		return 1;
947	}
948	iscsi_trace(TRACE_ISCSI_ARGS, "Response:    %u\n", rsp->response);
949	iscsi_trace(TRACE_ISCSI_ARGS, "Length:      %u\n", rsp->length);
950	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:    %#x\n", rsp->tag);
951	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:      %u\n", rsp->StatSN);
952	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:    %u\n", rsp->ExpCmdSN);
953	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:    %u\n", rsp->MaxCmdSN);
954	iscsi_trace(TRACE_ISCSI_ARGS, "Time2Wait:   %hu\n", rsp->Time2Wait);
955	iscsi_trace(TRACE_ISCSI_ARGS, "Time2Retain: %hu\n", rsp->Time2Retain);
956
957	return 0;
958}
959
960/*
961 * SCSI Command
962 */
963
964int
965iscsi_scsi_cmd_encap(uint8_t *header, iscsi_scsi_cmd_args_t * cmd)
966{
967
968	iscsi_trace(TRACE_ISCSI_ARGS, "Immediate:         %d\n", cmd->immediate);
969	iscsi_trace(TRACE_ISCSI_ARGS, "Final:             %d\n", cmd->final);
970	iscsi_trace(TRACE_ISCSI_ARGS, "Input:             %d\n", cmd->input);
971	iscsi_trace(TRACE_ISCSI_ARGS, "Output:            %d\n", cmd->output);
972	iscsi_trace(TRACE_ISCSI_ARGS, "ATTR:              %d\n", cmd->attr);
973	iscsi_trace(TRACE_ISCSI_ARGS, "TotalAHSLength:    %u\n", cmd->ahs_len);
974	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength: %u\n", cmd->length);
975	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:               %" PRIu64 "\n", cmd->lun);
976	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:          %#x\n", cmd->tag);
977	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Length:   %u\n", cmd->trans_len);
978	iscsi_trace(TRACE_ISCSI_ARGS, "CmdSN:             %u\n", cmd->CmdSN);
979	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN:         %u\n", cmd->ExpStatSN);
980	iscsi_trace(TRACE_ISCSI_ARGS, "CDB:               %#x\n", cmd->cdb[0]);
981
982	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
983
984	header[0] |= ISCSI_SCSI_CMD;	/* Opcode */
985	if (cmd->immediate) {
986		header[0] |= 0x40;	/* Immediate */
987	}
988	if (cmd->final) {
989		header[1] |= 0x80;	/* Final */
990	}
991	if (cmd->input) {
992		header[1] |= 0x40;	/* Input bit */
993	}
994	if (cmd->output) {
995		header[1] |= 0x20;	/* Output bit */
996	}
997	header[1] |= cmd->attr & 0x07;	/* ATTR  */
998	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(cmd->length);	/* DataSegmentLength */
999	header[4] = cmd->ahs_len;	/* TotalAHSLength  */
1000	*((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL(cmd->lun);	/* LUN */
1001	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag);	/* Task Tag  */
1002	*((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(cmd->trans_len);	/* Expected Transfer
1003								 * Length */
1004	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->CmdSN);	/* CmdSN */
1005	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpStatSN);	/* ExpStatSN */
1006	memcpy(header + 32, cmd->cdb, 16);	/* CDB */
1007
1008	return 0;
1009}
1010
1011int
1012iscsi_scsi_cmd_decap(uint8_t *header, iscsi_scsi_cmd_args_t * cmd)
1013{
1014	const char	*errmsg;
1015
1016	if (ISCSI_OPCODE(header) != ISCSI_SCSI_CMD) {
1017		iscsi_err(__FILE__, __LINE__, "Opcode");
1018		return 1;
1019	}
1020	cmd->immediate = (header[0] & 0x40) ? 1 : 0;	/* Immediate */
1021	cmd->final = (header[1] & 0x80) ? 1 : 0;	/* Final */
1022	cmd->input = (header[1] & 0x40) ? 1 : 0;	/* Input */
1023	cmd->output = (header[1] & 0x20) ? 1 : 0;	/* Output */
1024	cmd->attr = header[1] & 0x07;	/* ATTR  */
1025	cmd->ahs_len = header[4];
1026	header[4] = 0x00;
1027	cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* DataSegmentLength */
1028	cmd->lun = ISCSI_NTOHLL(*((uint64_t *) (void *) (header + 8)));	/* LUN */
1029	cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));	/* Task Tag */
1030	cmd->trans_len = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20)));	/* Expected Transfer
1031								 * Length */
1032	cmd->CmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* CmdSN  */
1033	cmd->ExpStatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpStatSN */
1034	cmd->cdb = header + 32;	/* CDB */
1035
1036	errmsg = NULL;
1037	if ((header[1] & 0x18) != 0x0) {
1038		errmsg = "Byte 1, bits 3-4";
1039	} else if (header[2] != 0) {
1040		errmsg = "Byte 2";
1041	} else if (header[3] != 0) {
1042		errmsg = "Byte 3";
1043	}
1044	if (errmsg) {
1045		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
1046		NO_CLEANUP;
1047		return 1;
1048	}
1049	iscsi_trace(TRACE_ISCSI_ARGS, "Immediate:         %d\n", cmd->immediate);
1050	iscsi_trace(TRACE_ISCSI_ARGS, "Final:             %d\n", cmd->final);
1051	iscsi_trace(TRACE_ISCSI_ARGS, "Input:             %d\n", cmd->input);
1052	iscsi_trace(TRACE_ISCSI_ARGS, "Output:            %d\n", cmd->output);
1053	iscsi_trace(TRACE_ISCSI_ARGS, "ATTR:              %d\n", cmd->attr);
1054	iscsi_trace(TRACE_ISCSI_ARGS, "TotalAHSLength:    %u\n", cmd->ahs_len);
1055	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength: %u\n", cmd->length);
1056	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:               %" PRIu64 "\n", cmd->lun);
1057	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:          %#x\n", cmd->tag);
1058	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Length:   %u\n", cmd->trans_len);
1059	iscsi_trace(TRACE_ISCSI_ARGS, "CmdSN:             %u\n", cmd->CmdSN);
1060	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN:         %u\n", cmd->ExpStatSN);
1061	iscsi_trace(TRACE_ISCSI_ARGS, "CDB:               %#x\n", cmd->cdb[0]);
1062
1063	return 0;
1064}
1065
1066/*
1067 * SCSI Response
1068 */
1069
1070int
1071iscsi_scsi_rsp_encap(uint8_t *header, iscsi_scsi_rsp_t * rsp)
1072{
1073
1074	iscsi_trace(TRACE_ISCSI_ARGS, "Bidi Overflow:       %d\n", rsp->bidi_overflow);
1075	iscsi_trace(TRACE_ISCSI_ARGS, "Bidi Underflow:      %d\n", rsp->bidi_underflow);
1076	iscsi_trace(TRACE_ISCSI_ARGS, "Overflow:            %d\n", rsp->overflow);
1077	iscsi_trace(TRACE_ISCSI_ARGS, "Underflow:           %d\n", rsp->underflow);
1078	iscsi_trace(TRACE_ISCSI_ARGS, "iSCSI Response:      %u\n", rsp->response);
1079	iscsi_trace(TRACE_ISCSI_ARGS, "SCSI Status:         %u\n", rsp->status);
1080	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength:   %u\n", rsp->length);
1081	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:            %#x\n", rsp->tag);
1082	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:              %u\n", rsp->StatSN);
1083	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:            %u\n", rsp->ExpCmdSN);
1084	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:            %u\n", rsp->MaxCmdSN);
1085	iscsi_trace(TRACE_ISCSI_ARGS, "ExpDataSN:           %u\n", rsp->ExpDataSN);
1086	iscsi_trace(TRACE_ISCSI_ARGS, "Bidi Residual Count: %u\n", rsp->bidi_res_cnt);
1087	iscsi_trace(TRACE_ISCSI_ARGS, "Residual Count:      %u\n", rsp->basic_res_cnt);
1088
1089	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
1090
1091	header[0] |= 0x00 | ISCSI_SCSI_RSP;	/* Opcode  */
1092	header[1] |= 0x80;	/* Byte 1 bit 7 */
1093	if (rsp->bidi_overflow) {
1094		header[1] |= 0x10;	/* Bidi overflow */
1095	}
1096	if (rsp->bidi_underflow) {
1097		header[1] |= 0x08;	/* Bidi underflow */
1098	}
1099	if (rsp->overflow) {
1100		header[1] |= 0x04;	/* Overflow */
1101	}
1102	if (rsp->underflow) {
1103		header[1] |= 0x02;	/* Underflow  */
1104	}
1105	header[2] = rsp->response;	/* iSCSI Response */
1106	header[3] = rsp->status;/* SCSI Status */
1107	header[4] = rsp->ahs_len;	/* TotalAHSLength  */
1108	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(rsp->length);	/* DataSegmentLength */
1109	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(rsp->tag);	/* Task Tag */
1110	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(rsp->StatSN);	/* StatSN */
1111	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(rsp->ExpCmdSN);	/* ExpCmdSN */
1112	*((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(rsp->MaxCmdSN);	/* MaxCmdSN */
1113	*((uint32_t *) (void *) (header + 36)) = ISCSI_HTONL(rsp->ExpDataSN);	/* ExpDataSN  */
1114	*((uint32_t *) (void *) (header + 40)) = ISCSI_HTONL(rsp->bidi_res_cnt);	/* Bidi Residual Count */
1115	*((uint32_t *) (void *) (header + 44)) = ISCSI_HTONL(rsp->basic_res_cnt);	/* Residual Count */
1116
1117	return 0;
1118}
1119
1120int
1121iscsi_scsi_rsp_decap(uint8_t *header, iscsi_scsi_rsp_t * rsp)
1122{
1123	const char	*errmsg;
1124
1125	if (ISCSI_OPCODE(header) != ISCSI_SCSI_RSP) {
1126		iscsi_err(__FILE__, __LINE__, "Opcode");
1127		return 1;
1128	}
1129	rsp->bidi_overflow = (header[1] & 0x10) ? 1 : 0;	/* Bidi overflow */
1130	rsp->bidi_underflow = (header[1] & 0x08) ? 1 : 0;	/* Bidi underflow */
1131	rsp->overflow = (header[1] & 0x04) ? 1 : 0;	/* Overflow */
1132	rsp->underflow = (header[1] & 0x02) ? 1 : 0;	/* Underflow */
1133
1134	rsp->response = header[2];	/* iSCSI Response */
1135	rsp->status = header[3];/* SCSI Status */
1136	rsp->ahs_len = header[4];	/* TotalAHSLength  */
1137	rsp->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* DataSegmentLength */
1138	rsp->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));	/* Task Tag  */
1139	rsp->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* StatSN  */
1140	rsp->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpCmdSN  */
1141	rsp->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32)));	/* MaxCmdSN  */
1142	rsp->ExpDataSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 36)));	/* ExpDataSN  */
1143	rsp->bidi_res_cnt = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 40)));	/* Bidi Residual Count  */
1144	rsp->basic_res_cnt = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 44)));	/* Residual Count */
1145
1146	errmsg = NULL;
1147	if ((header[0] & 0xc0) != 0x0) {
1148		errmsg = "Byte 0, bits 0-1";
1149	} else if ((header[1] & 0x80) != 0x80) {
1150		errmsg = "Byte 1, bit 0";
1151	} else if (rsp->bidi_res_cnt != 0) {
1152		errmsg = "bidi_res_cnt";
1153	} else if (rsp->bidi_overflow != 0) {
1154		errmsg = "bidi_overflow";
1155	} else if (rsp->bidi_underflow != 0) {
1156		errmsg = "bidi_underflow";
1157	} else if (rsp->overflow != 0) {
1158		errmsg = "overflow";
1159	}
1160	if (errmsg) {
1161		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
1162		NO_CLEANUP;
1163		return 1;
1164	}
1165	iscsi_trace(TRACE_ISCSI_ARGS, "Bidi Overflow:       %d\n", rsp->bidi_overflow);
1166	iscsi_trace(TRACE_ISCSI_ARGS, "Bidi Underflow:      %d\n", rsp->bidi_underflow);
1167	iscsi_trace(TRACE_ISCSI_ARGS, "Overflow:            %d\n", rsp->overflow);
1168	iscsi_trace(TRACE_ISCSI_ARGS, "Underflow:           %d\n", rsp->underflow);
1169	iscsi_trace(TRACE_ISCSI_ARGS, "iSCSI Response:      %u\n", rsp->response);
1170	iscsi_trace(TRACE_ISCSI_ARGS, "SCSI Status:         %u\n", rsp->status);
1171	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength:   %u\n", rsp->length);
1172	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:            %#x\n", rsp->tag);
1173	iscsi_trace(TRACE_ISCSI_ARGS, "Residual Count:      %u\n", rsp->basic_res_cnt);
1174	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:              %u\n", rsp->StatSN);
1175	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:            %u\n", rsp->ExpCmdSN);
1176	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:            %u\n", rsp->MaxCmdSN);
1177	iscsi_trace(TRACE_ISCSI_ARGS, "ExpDataSN:           %u\n", rsp->ExpDataSN);
1178	iscsi_trace(TRACE_ISCSI_ARGS, "Bidi Residual Count: %u\n", rsp->bidi_res_cnt);
1179
1180	return 0;
1181}
1182
1183
1184/*
1185 * Ready To Transfer
1186 */
1187
1188int
1189iscsi_r2t_encap(uint8_t *header, iscsi_r2t_t * cmd)
1190{
1191	uint32_t        length;
1192
1193	iscsi_trace(TRACE_ISCSI_ARGS, "TotalAHSLength:    %u\n", cmd->AHSlength);
1194	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:          %" PRIu64 "\n", cmd->lun);
1195	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:          %#x\n", cmd->tag);
1196	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag: %#x\n", cmd->transfer_tag);
1197	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:       %u\n", cmd->StatSN);
1198	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:     %u\n", cmd->ExpCmdSN);
1199	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:     %u\n", cmd->MaxCmdSN);
1200	iscsi_trace(TRACE_ISCSI_ARGS, "R2TSN:        %u\n", cmd->R2TSN);
1201	iscsi_trace(TRACE_ISCSI_ARGS, "Offset:       %u\n", cmd->offset);
1202	iscsi_trace(TRACE_ISCSI_ARGS, "Length:       %u\n", cmd->length);
1203
1204	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
1205
1206	header[0] |= 0x00 | ISCSI_R2T;	/* Opcode  */
1207	header[1] |= 0x80;
1208	length = (cmd->AHSlength & 0x00ffffff);	/* AHSLength */
1209	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(length);	/* AHSLength */
1210	*((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL(cmd->lun);	/* LUN */
1211	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag);	/* Tag */
1212	*((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(cmd->transfer_tag);	/* Transfer Tag */
1213	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->StatSN);	/* StatSN  */
1214	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpCmdSN);	/* ExpCmdSN */
1215	*((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(cmd->MaxCmdSN);	/* MaxCmdSN */
1216	*((uint32_t *) (void *) (header + 36)) = ISCSI_HTONL(cmd->R2TSN);	/* R2TSN */
1217	*((uint32_t *) (void *) (header + 40)) = ISCSI_HTONL(cmd->offset);	/* Buffer Offset */
1218	*((uint32_t *) (void *) (header + 44)) = ISCSI_HTONL(cmd->length);	/* Transfer Length */
1219
1220	return 0;
1221}
1222
1223int
1224iscsi_r2t_decap(uint8_t *header, iscsi_r2t_t * cmd)
1225{
1226	const char	*errmsg;
1227	uint8_t		 zeros[12];
1228
1229	if (ISCSI_OPCODE(header) != ISCSI_R2T) {
1230		iscsi_err(__FILE__, __LINE__, "Opcode");
1231		return 1;
1232	}
1233	cmd->AHSlength = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* TotalAHSLength */
1234	cmd->lun = ISCSI_NTOHLL(*((uint64_t *) (void *) (header + 8)));	/* LUN */
1235	cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));
1236	cmd->transfer_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20)));
1237	cmd->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));
1238	cmd->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));
1239	cmd->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32)));
1240	cmd->R2TSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 36)));
1241	cmd->offset = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 40)));
1242	cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 44)));
1243
1244	errmsg = NULL;
1245	(void) memset(zeros, 0x0, sizeof(zeros));
1246	if ((header[1] & 0x7f) != 0x0) {
1247		errmsg = "Byte 1, bits 1-7";
1248	} else if (header[2] != 0) {
1249		errmsg = "Byte 2";
1250	} else if (header[3] != 0) {
1251		errmsg = "Byte 3";
1252	} else if (memcmp(header + 4, zeros, 12) != 0) {
1253		errmsg = "Bytes 4-15";
1254	}
1255	if (errmsg) {
1256		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
1257		NO_CLEANUP;
1258		return 1;
1259	}
1260	iscsi_trace(TRACE_ISCSI_ARGS, "AHSLength:    %u\n", cmd->AHSlength);
1261	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:          %" PRIu64 "\n", cmd->lun);
1262	iscsi_trace(TRACE_ISCSI_ARGS, "Tag:          %#x\n", cmd->tag);
1263	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag: %#x\n", cmd->transfer_tag);
1264	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:       %u\n", cmd->StatSN);
1265	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:     %u\n", cmd->ExpCmdSN);
1266	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:     %u\n", cmd->MaxCmdSN);
1267	iscsi_trace(TRACE_ISCSI_ARGS, "R2TSN:        %u\n", cmd->R2TSN);
1268	iscsi_trace(TRACE_ISCSI_ARGS, "Offset:       %u\n", cmd->offset);
1269	iscsi_trace(TRACE_ISCSI_ARGS, "Length:       %u\n", cmd->length);
1270	return 0;
1271}
1272
1273/*
1274 * SCSI Write Data
1275 */
1276
1277int
1278iscsi_write_data_encap(uint8_t *header, iscsi_write_data_t * cmd)
1279{
1280
1281	iscsi_trace(TRACE_ISCSI_ARGS, "Final:              %u\n", cmd->final);
1282	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength:  %u\n", cmd->length);
1283	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:                %" PRIu64 "\n", cmd->lun);
1284	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:           %#x\n", cmd->tag);
1285	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag:       %#x\n", cmd->transfer_tag);
1286	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN:          %u\n", cmd->ExpStatSN);
1287	iscsi_trace(TRACE_ISCSI_ARGS, "DataSN:             %u\n", cmd->DataSN);
1288	iscsi_trace(TRACE_ISCSI_ARGS, "Buffer Offset:      %u\n", cmd->offset);
1289
1290	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
1291	header[0] = 0x00 | ISCSI_WRITE_DATA;	/* Opcode  */
1292	if (cmd->final) {
1293		header[1] |= 0x80;	/* Final */
1294	}
1295	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(cmd->length);	/* Length */
1296	*((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL(cmd->lun);	/* LUN */
1297	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag);	/* Tag */
1298	*((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(cmd->transfer_tag);	/* Transfer Tag */
1299	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpStatSN);	/* ExpStatSN */
1300	*((uint32_t *) (void *) (header + 36)) = ISCSI_HTONL(cmd->DataSN);	/* DataSN */
1301	*((uint32_t *) (void *) (header + 40)) = ISCSI_HTONL(cmd->offset);	/* Buffer Offset */
1302
1303	return 0;
1304}
1305
1306int
1307iscsi_write_data_decap(uint8_t *header, iscsi_write_data_t * cmd)
1308{
1309	const char	*errmsg;
1310	uint8_t		 zeros[16];
1311
1312	if (ISCSI_OPCODE(header) != ISCSI_WRITE_DATA) {
1313		iscsi_err(__FILE__, __LINE__, "Opcode");
1314		return 1;
1315	}
1316	cmd->final = (header[1] & 0x80) ? 1 : 0;	/* Final */
1317	cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* Length */
1318	cmd->lun = ISCSI_NTOHLL(*((uint64_t *) (void *) (header + 8)));	/* LUN */
1319	cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));	/* Tag */
1320	cmd->transfer_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20)));	/* Transfer Tag */
1321	cmd->ExpStatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpStatSN  */
1322	cmd->DataSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 36)));	/* DataSN    */
1323	cmd->offset = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 40)));	/* Buffer Offset */
1324
1325	errmsg = NULL;
1326	(void) memset(zeros, 0x0, sizeof(zeros));
1327	if ((header[1] & 0x7f) != 0x0) {
1328		errmsg = "Byte 1, bits 1-7";
1329	} else if (header[2] != 0) {
1330		errmsg = "Byte 2";
1331	} else if (header[3] != 0) {
1332		errmsg = "Byte 3";
1333	} else if (header[4] != 0) {
1334		errmsg = "Byte 4";
1335	} else if (memcmp(header + 24, zeros, 4) != 0) {
1336		errmsg = "Bytes 24-27";
1337	} else if (memcmp(header + 32, zeros, 4) != 0) {
1338		errmsg = "Bytes 32-35";
1339	} else if (memcmp(header + 44, zeros, 4) != 0) {
1340		errmsg = "Bytes 44-47";
1341	}
1342	if (errmsg) {
1343		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
1344		NO_CLEANUP;
1345		return 1;
1346	}
1347	iscsi_trace(TRACE_ISCSI_ARGS, "Final:              %u\n", cmd->final);
1348	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength:  %u\n", cmd->length);
1349	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:                %" PRIu64 "\n", cmd->lun);
1350	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:           %#x\n", cmd->tag);
1351	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag:       %#x\n", cmd->transfer_tag);
1352	iscsi_trace(TRACE_ISCSI_ARGS, "ExpStatSN:          %u\n", cmd->ExpStatSN);
1353	iscsi_trace(TRACE_ISCSI_ARGS, "DataSN:             %u\n", cmd->DataSN);
1354	iscsi_trace(TRACE_ISCSI_ARGS, "Buffer Offset:      %u\n", cmd->offset);
1355
1356	return 0;
1357}
1358
1359/*
1360 * SCSI Read Data
1361 */
1362
1363int
1364iscsi_read_data_encap(uint8_t *header, iscsi_read_data_t * cmd)
1365{
1366
1367	iscsi_trace(TRACE_ISCSI_ARGS, "Final:             %d\n", cmd->final);
1368	iscsi_trace(TRACE_ISCSI_ARGS, "Acknowledge:       %d\n", cmd->ack);
1369	iscsi_trace(TRACE_ISCSI_ARGS, "Overflow:          %d\n", cmd->overflow);
1370	iscsi_trace(TRACE_ISCSI_ARGS, "Underflow:         %d\n", cmd->underflow);
1371	iscsi_trace(TRACE_ISCSI_ARGS, "S_bit:             %d\n", cmd->S_bit);
1372	iscsi_trace(TRACE_ISCSI_ARGS, "Status:            %u\n", cmd->status);
1373	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength: %u\n", cmd->length);
1374	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:               %" PRIu64 "\n", cmd->lun);
1375	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:          %#x\n", cmd->task_tag);
1376	iscsi_trace(TRACE_ISCSI_ARGS, "Transfer Tag:      %#x\n", cmd->transfer_tag);
1377	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:            %u\n", cmd->StatSN);
1378	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:          %u\n", cmd->ExpCmdSN);
1379	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:          %u\n", cmd->MaxCmdSN);
1380	iscsi_trace(TRACE_ISCSI_ARGS, "DataSN:            %u\n", cmd->DataSN);
1381	iscsi_trace(TRACE_ISCSI_ARGS, "Buffer Offset      %u\n", cmd->offset);
1382	iscsi_trace(TRACE_ISCSI_ARGS, "Residual Count:    %u\n", cmd->res_count);
1383
1384	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
1385
1386	header[0] = 0x00 | ISCSI_READ_DATA;	/* Opcode  */
1387	if (cmd->final) {
1388		header[1] |= 0x80;	/* Final */
1389	}
1390	if (cmd->ack) {
1391		header[1] |= 0x40;	/* ACK */
1392	}
1393	if (cmd->overflow) {
1394		header[1] |= 0x04;	/* Overflow  */
1395	}
1396	if (cmd->underflow) {
1397		header[1] |= 0x02;	/* Underflow */
1398	}
1399	if (cmd->S_bit) {
1400		header[1] |= 0x01;	/* S Bit */
1401	}
1402	if (cmd->S_bit) {
1403		header[3] = cmd->status;	/* Status  */
1404	}
1405	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(cmd->length);	/* Length */
1406	*((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL(cmd->lun);	/* LUN */
1407	*((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->task_tag);	/* Task Tag */
1408	*((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(cmd->transfer_tag);	/* Transfer Tag */
1409	if (cmd->S_bit) {
1410		*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->StatSN);	/* StatSN */
1411	}
1412	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpCmdSN);	/* ExpCmdSN  */
1413	*((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(cmd->MaxCmdSN);	/* MaxCmdSN  */
1414	*((uint32_t *) (void *) (header + 36)) = ISCSI_HTONL(cmd->DataSN);	/* DataSN  */
1415	*((uint32_t *) (void *) (header + 40)) = ISCSI_HTONL(cmd->offset);	/* Buffer Offset */
1416	if (cmd->S_bit) {
1417		*((uint32_t *) (void *) (header + 44)) = ISCSI_HTONL(cmd->res_count);	/* Residual Count  */
1418	}
1419
1420	return 0;
1421}
1422
1423int
1424iscsi_read_data_decap(uint8_t *header, iscsi_read_data_t * cmd)
1425{
1426	const char	*errmsg;
1427	uint8_t		 zeros[16];
1428
1429	if (ISCSI_OPCODE(header) != ISCSI_READ_DATA) {
1430		iscsi_err(__FILE__, __LINE__, "Opcode");
1431		return 1;
1432	}
1433	cmd->final = (header[1] & 0x80) ? 1 : 0;	/* Final */
1434	cmd->ack = (header[1] & 0x40) ? 1 : 0;	/* Acknowledge */
1435	cmd->overflow = (header[1] & 0x04) ? 1 : 0;	/* Overflow  */
1436	cmd->underflow = (header[1] & 0x02) ? 1 : 0;	/* Underflow  */
1437	cmd->S_bit = (header[1] & 0x01) ? 1 : 0;	/* S Bit  */
1438	cmd->status = header[3];/* Status */
1439	cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* Length */
1440	cmd->lun = ISCSI_NTOHLL(*((uint64_t *) (void *) (header + 8)));		/* LUN  */
1441	cmd->task_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16)));	/* Task Tag */
1442	cmd->transfer_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20)));	/* Transfer Tag  */
1443	cmd->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* StatSN  */
1444	cmd->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpCmdSN  */
1445	cmd->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32)));	/* MaxCmdSN  */
1446	cmd->DataSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 36)));	/* DataSN  */
1447	cmd->offset = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 40)));	/* Buffer Offset */
1448	cmd->res_count = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 44)));	/* Residual Count  */
1449	errmsg = NULL;
1450	(void) memset(zeros, 0x0, sizeof(zeros));
1451	if ((header[0] & 0xc0) != 0x0) {
1452		errmsg = "Byte 0, bits 0-1";
1453	} else if ((header[1] & 0x38) != 0x0) {
1454		errmsg = "Byte 1, bits 2-4";
1455	} else if (header[2] != 0) {
1456		errmsg = "Byte 2";
1457	} else if (header[4] != 0) {
1458		errmsg = "Byte 4";
1459	} else if (memcmp(header + 8, zeros, 8) != 0) {
1460		errmsg = "Bytes 8-15";
1461	} else if (!cmd->underflow && memcmp(header + 44, zeros, 4) != 0) {
1462		errmsg = "Bytes 44-47";
1463	}
1464	if (errmsg) {
1465		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
1466		NO_CLEANUP;
1467		return 1;
1468	}
1469	iscsi_trace(TRACE_ISCSI_ARGS, "Final:             %d\n", cmd->final);
1470	iscsi_trace(TRACE_ISCSI_ARGS, "Acknowledge:       %d\n", cmd->ack);
1471	iscsi_trace(TRACE_ISCSI_ARGS, "Overflow:          %d\n", cmd->overflow);
1472	iscsi_trace(TRACE_ISCSI_ARGS, "Underflow:         %d\n", cmd->underflow);
1473	iscsi_trace(TRACE_ISCSI_ARGS, "S_bit:             %d\n", cmd->S_bit);
1474	iscsi_trace(TRACE_ISCSI_ARGS, "Status:            %u\n", cmd->status);
1475	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength: %u\n", cmd->length);
1476	iscsi_trace(TRACE_ISCSI_ARGS, "Task Tag:          %#x\n", cmd->task_tag);
1477	iscsi_trace(TRACE_ISCSI_ARGS, "Residual Count:    %u\n", cmd->res_count);
1478	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:            %u\n", cmd->StatSN);
1479	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:          %u\n", cmd->ExpCmdSN);
1480	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:          %u\n", cmd->MaxCmdSN);
1481	iscsi_trace(TRACE_ISCSI_ARGS, "DataSN:            %u\n", cmd->DataSN);
1482	iscsi_trace(TRACE_ISCSI_ARGS, "Buffer Offset      %u\n", cmd->offset);
1483	return 0;
1484}
1485
1486/*
1487 * Reject
1488 */
1489
1490int
1491iscsi_reject_encap(uint8_t *header, iscsi_reject_t * cmd)
1492{
1493
1494	iscsi_trace(TRACE_ISCSI_ARGS, "Reason:   %u\n", cmd->reason);
1495	iscsi_trace(TRACE_ISCSI_ARGS, "Length:   %u\n", cmd->length);
1496	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:   %u\n", cmd->StatSN);
1497	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN: %u\n", cmd->ExpCmdSN);
1498	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN: %u\n", cmd->MaxCmdSN);
1499	iscsi_trace(TRACE_ISCSI_ARGS, "DataSN:   %u\n", cmd->DataSN);
1500
1501	(void) memset(header, 0x0, ISCSI_HEADER_LEN);
1502
1503	header[0] |= 0x00 | ISCSI_REJECT;	/* Opcode  */
1504	header[1] |= 0x80;
1505	header[2] = cmd->reason;/* Reason */
1506	*((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(cmd->length);	/* Length  */
1507	*((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->StatSN);	/* StatSN */
1508	*((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpCmdSN);	/* ExpCmdSN */
1509	*((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(cmd->MaxCmdSN);	/* MaxCmdSN */
1510	*((uint32_t *) (void *) (header + 36)) = ISCSI_HTONL(cmd->DataSN);	/* DataSN */
1511
1512	return 0;
1513}
1514
1515int
1516iscsi_reject_decap(uint8_t *header, iscsi_reject_t * cmd)
1517{
1518	const char	*errmsg;
1519	uint8_t		 zeros[8];
1520
1521	if (ISCSI_OPCODE(header) != ISCSI_REJECT) {
1522		iscsi_err(__FILE__, __LINE__, "Opcode");
1523		return 1;
1524	}
1525	cmd->reason = header[2];/* Reason */
1526	cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* Length */
1527	cmd->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* StatSN */
1528	cmd->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpCmdSN */
1529	cmd->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32)));	/* MaxCmdSN */
1530	cmd->DataSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 36)));	/* DataSN */
1531
1532	errmsg = NULL;
1533	(void) memset(zeros, 0x0, sizeof(zeros));
1534	if ((header[0] & 0xc0) != 0x0) {
1535		errmsg = "Byte 0, bits 0-1";
1536	} else if ((header[1] & 0x7f) != 0x0) {
1537		errmsg = "Byte 1, bits 0-7";
1538	} else if (header[3] != 0) {
1539		errmsg = "Byte 3";
1540	} else if (header[4] != 0) {
1541		errmsg = "Byte 4";
1542	} else if (memcmp(header + 8, zeros, 8) != 0) {
1543		errmsg = "Bytes 8-15";
1544	} else if (memcmp(header + 20, zeros, 4) != 0) {
1545		errmsg = "Bytes 20-23";
1546	} else if (memcmp(header + 40, zeros, 8) != 0) {
1547		errmsg = "Bytes 40-47";
1548	}
1549	if (errmsg) {
1550		iscsi_err(__FILE__, __LINE__, "%s", errmsg);
1551		NO_CLEANUP;
1552		return 1;
1553	}
1554	iscsi_trace(TRACE_ISCSI_ARGS, "Reason:   %u\n", cmd->reason);
1555	iscsi_trace(TRACE_ISCSI_ARGS, "Length:   %u\n", cmd->length);
1556	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:   %u\n", cmd->StatSN);
1557	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN: %u\n", cmd->ExpCmdSN);
1558	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN: %u\n", cmd->MaxCmdSN);
1559	iscsi_trace(TRACE_ISCSI_ARGS, "DataSN:   %u\n", cmd->DataSN);
1560	return 0;
1561}
1562
1563int
1564iscsi_amsg_decap(uint8_t *header, iscsi_async_msg_t * msg)
1565{
1566
1567	if (ISCSI_OPCODE(header) != ISCSI_ASYNC) {
1568		iscsi_err(__FILE__, __LINE__, "Opcode");
1569		return 1;
1570	}
1571	msg->AHSlength = header[4];	/* TotalAHSLength */
1572	msg->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4)));	/* Length */
1573	msg->lun = ISCSI_NTOHLL(*((uint64_t *) (void *) (header + 8)));		/* LUN  */
1574	msg->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24)));	/* StatSN */
1575	msg->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28)));	/* ExpCmdSN */
1576	msg->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32)));	/* MaxCmdSN  */
1577	msg->AsyncEvent = header[36];	/* Async Event */
1578	msg->AsyncVCode = header[37];	/* Async Vendor Code */
1579
1580	iscsi_trace(TRACE_ISCSI_ARGS, "TotalAHSLength:    %u\n", msg->AHSlength);
1581	iscsi_trace(TRACE_ISCSI_ARGS, "DataSegmentLength: %u\n", msg->length);
1582	iscsi_trace(TRACE_ISCSI_ARGS, "LUN:               %" PRIu64 "\n", msg->lun);
1583	iscsi_trace(TRACE_ISCSI_ARGS, "StatSN:            %u\n", msg->StatSN);
1584	iscsi_trace(TRACE_ISCSI_ARGS, "ExpCmdSN:          %u\n", msg->ExpCmdSN);
1585	iscsi_trace(TRACE_ISCSI_ARGS, "MaxCmdSN:          %u\n", msg->MaxCmdSN);
1586	iscsi_trace(TRACE_ISCSI_ARGS, "AsyncEvent:      %u\n", msg->AsyncEvent);
1587	iscsi_trace(TRACE_ISCSI_ARGS, "AsyncVCode:     %u\n", msg->AsyncVCode);
1588
1589	return 0;
1590}
1591