1 /*
2    Copyright (C) 2010 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU Lesser General Public License as published by
6    the Free Software Foundation; either version 2.1 of the License, or
7    (at your option) any later version.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public License
15    along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 #ifdef HAVE_SYS_TYPES_H
22 #include <sys/types.h>
23 #endif
24 
25 #ifdef HAVE_ARPA_INET_H
26 #include <arpa/inet.h>
27 #endif
28 
29 #ifdef HAVE_INTTYPES_H
30 #include <inttypes.h>
31 #else
32 #define PRIu64 "llu"
33 #define PRIx32 "x"
34 #endif
35 
36 #if defined(_WIN32)
37 #include <winsock2.h>
38 #include <ws2tcpip.h>
39 #include "win32/win32_compat.h"
40 #else
41 #include <strings.h>
42 #endif
43 
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include "iscsi.h"
48 #include "iscsi-private.h"
49 #include "scsi-lowlevel.h"
50 #include "slist.h"
51 
52 /* This adds 32-bit serial comparision as defined in RFC1982.
53  * It returns 0 for equality, 1 if s1 is greater than s2 and
54  * -1 if s1 is less than s2. According to RFC1982 section 3.2
55  * there are rare cases where the result of the comparision is
56  * undefined e.g. when s1 = 0 and s2=2^31. This cases should
57  * not happen in iSCSI protocol.
58  */
59 int
iscsi_serial32_compare(uint32_t s1,uint32_t s2)60 iscsi_serial32_compare(uint32_t s1, uint32_t s2) {
61 	if (s1 == s2) return 0;
62 	if (s1 < s2 && s2-s1 < (uint32_t)1<<31) return -1;
63 	if (s1 > s2 && s1-s2 < (uint32_t)1<<31) return 1;
64 	if (s1 > s2 && s1-s2 > (uint32_t)1<<31) return -1;
65 	if (s1 < s2 && s2-s1 > (uint32_t)1<<31) return 1;
66 	/* undefined result */
67 	return -1;
68 }
69 
70 uint32_t
iscsi_itt_post_increment(struct iscsi_context * iscsi)71 iscsi_itt_post_increment(struct iscsi_context *iscsi) {
72 	uint32_t old_itt = iscsi->itt;
73 	iscsi->itt++;
74 	/* 0xffffffff is a reserved value */
75 	if (iscsi->itt == 0xffffffff) {
76 		iscsi->itt = 0;
77 	}
78 	return old_itt;
79 }
80 
iscsi_dump_pdu_header(struct iscsi_context * iscsi,unsigned char * data)81 void iscsi_dump_pdu_header(struct iscsi_context *iscsi, unsigned char *data) {
82 	char dump[ISCSI_RAW_HEADER_SIZE*3+1]={0};
83 	int i;
84 	for (i=0;i<ISCSI_RAW_HEADER_SIZE;i++) {
85 		snprintf(&dump[i * 3], 4, " %02x", data[i]);
86 	}
87 	ISCSI_LOG(iscsi, 2, "PDU header:%s", dump);
88 }
89 
90 struct iscsi_pdu*
iscsi_tcp_new_pdu(struct iscsi_context * iscsi,size_t size)91 iscsi_tcp_new_pdu(struct iscsi_context *iscsi, size_t size)
92 {
93 	struct iscsi_pdu *pdu;
94 
95 	pdu = iscsi_szmalloc(iscsi, size);
96 
97 	return pdu;
98 }
99 
100 struct iscsi_pdu *
iscsi_allocate_pdu(struct iscsi_context * iscsi,enum iscsi_opcode opcode,enum iscsi_opcode response_opcode,uint32_t itt,uint32_t flags)101 iscsi_allocate_pdu(struct iscsi_context *iscsi, enum iscsi_opcode opcode,
102 		   enum iscsi_opcode response_opcode, uint32_t itt,
103 		   uint32_t flags)
104 {
105 	struct iscsi_pdu *pdu;
106 
107 	pdu = iscsi->drv->new_pdu(iscsi, sizeof(struct iscsi_pdu));
108 	if (pdu == NULL) {
109 		iscsi_set_error(iscsi, "failed to allocate pdu");
110 		return NULL;
111 	}
112 
113 	pdu->outdata.size = ISCSI_HEADER_SIZE(iscsi->header_digest);
114 	pdu->outdata.data = iscsi_szmalloc(iscsi, pdu->outdata.size);
115 
116 	if (pdu->outdata.data == NULL) {
117 		iscsi_set_error(iscsi, "failed to allocate pdu header");
118 		iscsi_free(iscsi, pdu);
119 		return NULL;
120 	}
121 
122 	/* opcode */
123 	pdu->outdata.data[0] = opcode;
124 	pdu->response_opcode = response_opcode;
125 
126 	/* isid */
127 	if (opcode == ISCSI_PDU_LOGIN_REQUEST) {
128 		memcpy(&pdu->outdata.data[8], &iscsi->isid[0], 6);
129 	}
130 
131 	/* itt */
132 	iscsi_pdu_set_itt(pdu, itt);
133 	pdu->itt = itt;
134 
135 	/* flags */
136 	pdu->flags = flags;
137 
138 	return pdu;
139 }
140 
141 void
iscsi_tcp_free_pdu(struct iscsi_context * iscsi,struct iscsi_pdu * pdu)142 iscsi_tcp_free_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
143 {
144 	if (pdu == NULL) {
145 		iscsi_set_error(iscsi, "trying to free NULL pdu");
146 		return;
147 	}
148 
149 	if (pdu->outdata.size <= iscsi->smalloc_size) {
150 		iscsi_sfree(iscsi, pdu->outdata.data);
151 	} else {
152 		iscsi_free(iscsi, pdu->outdata.data);
153 	}
154 	pdu->outdata.data = NULL;
155 
156 	if (pdu->indata.size <= iscsi->smalloc_size) {
157 		iscsi_sfree(iscsi, pdu->indata.data);
158 	} else {
159 		iscsi_free(iscsi, pdu->indata.data);
160 	}
161 	pdu->indata.data = NULL;
162 
163 	if (iscsi->outqueue_current == pdu) {
164 		iscsi->outqueue_current = NULL;
165 	}
166 
167 	iscsi_sfree(iscsi, pdu);
168 }
169 
170 int
iscsi_add_data(struct iscsi_context * iscsi,struct iscsi_data * data,unsigned char * dptr,int dsize,int pdualignment)171 iscsi_add_data(struct iscsi_context *iscsi, struct iscsi_data *data,
172 	       unsigned char *dptr, int dsize, int pdualignment)
173 {
174 	size_t len, aligned;
175 
176 	if (dsize == 0) {
177 		iscsi_set_error(iscsi, "Trying to append zero size data to "
178 				"iscsi_data");
179 		return -1;
180 	}
181 
182 	len = data->size + dsize;
183 
184 	aligned = len;
185 	if (pdualignment) {
186 		aligned = (aligned+3)&0xfffffffc;
187 	}
188 
189 	if (data->size == 0) {
190 		if (aligned <= iscsi->smalloc_size) {
191 			data->data = iscsi_szmalloc(iscsi, aligned);
192 		} else {
193 			data->data = iscsi_malloc(iscsi, aligned);
194 		}
195 	} else {
196 		if (aligned > iscsi->smalloc_size) {
197 			data->data = iscsi_realloc(iscsi, data->data, aligned);
198 		}
199 	}
200 	if (data->data == NULL) {
201 		iscsi_set_error(iscsi, "failed to allocate buffer for %d "
202 				"bytes", (int) len);
203 		return -1;
204 	}
205 
206 	memcpy(data->data + data->size, dptr, dsize);
207 	data->size += dsize;
208 
209 	if (len != aligned) {
210 		/* zero out any padding at the end */
211 		memset(data->data + len, 0, aligned - len);
212 	}
213 
214 	return 0;
215 }
216 
217 int
iscsi_pdu_add_data(struct iscsi_context * iscsi,struct iscsi_pdu * pdu,unsigned char * dptr,int dsize)218 iscsi_pdu_add_data(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
219 		   unsigned char *dptr, int dsize)
220 {
221 	if (pdu == NULL) {
222 		iscsi_set_error(iscsi, "trying to add data to NULL pdu");
223 		return -1;
224 	}
225 	if (dsize == 0) {
226 		iscsi_set_error(iscsi, "Trying to append zero size data to "
227 				"pdu");
228 		return -1;
229 	}
230 
231 	if (iscsi_add_data(iscsi, &pdu->outdata, dptr, dsize, 1) != 0) {
232 		iscsi_set_error(iscsi, "failed to add data to pdu buffer");
233 		return -1;
234 	}
235 
236 	/* update data segment length */
237 	scsi_set_uint32(&pdu->outdata.data[4], pdu->outdata.size
238 				- ISCSI_HEADER_SIZE(iscsi->header_digest));
239 
240 	return 0;
241 }
242 
243 int
iscsi_get_pdu_data_size(const unsigned char * hdr)244 iscsi_get_pdu_data_size(const unsigned char *hdr)
245 {
246 	int size;
247 
248 	size = scsi_get_uint32(&hdr[4]) & 0x00ffffff;
249 
250 	return size;
251 }
252 
253 int
iscsi_get_pdu_padding_size(const unsigned char * hdr)254 iscsi_get_pdu_padding_size(const unsigned char *hdr)
255 {
256 	int data_size, padded_size;
257 
258 	data_size = scsi_get_uint32(&hdr[4]) & 0x00ffffff;
259 	padded_size = (data_size+3) & 0xfffffffc;
260 
261 	return padded_size - data_size;
262 }
263 
264 enum iscsi_reject_reason {
265 	ISCSI_REJECT_RESERVED                 = 0x01,
266 	ISCSI_REJECT_DATA_DIGEST_ERROR        = 0x02,
267 	ISCSI_REJECT_SNACK_REJECT             = 0x03,
268 	ISCSI_REJECT_PROTOCOL_ERROR           = 0x04,
269 	ISCSI_REJECT_COMMAND_NOT_SUPPORTED    = 0x05,
270 	ISCSI_REJECT_IMMEDIATE_COMMAND_REJECT = 0x06,
271 	ISCSI_REJECT_TASK_IN_PROCESS          = 0x07,
272 	ISCSI_REJECT_INVALID_DATA_ACK         = 0x08,
273 	ISCSI_REJECT_INVALID_PDU_FIELD        = 0x09,
274 	ISCSI_REJECT_LONG_OPERATION_REJECT    = 0x0a,
275 	ISCSI_REJECT_NEGOTIATION_RESET        = 0x0b,
276 	ISCSI_REJECT_WAITING_FOR_LOGOUT       = 0x0c
277 };
278 
iscsi_reject_reason_str(enum iscsi_reject_reason reason)279 static const char *iscsi_reject_reason_str(enum iscsi_reject_reason reason)
280 {
281 	switch (reason) {
282 	case ISCSI_REJECT_RESERVED:
283 	     return "Reserved";
284 	case ISCSI_REJECT_DATA_DIGEST_ERROR:
285 	     return "Data Digest Error";
286 	case ISCSI_REJECT_SNACK_REJECT:
287 	     return "SNACK Reject";
288 	case ISCSI_REJECT_PROTOCOL_ERROR:
289 	     return "Protocol Error";
290 	case ISCSI_REJECT_COMMAND_NOT_SUPPORTED:
291 	     return "Command Not Supported";
292 	case ISCSI_REJECT_IMMEDIATE_COMMAND_REJECT:
293 	     return "Immediate Command Reject";
294 	case ISCSI_REJECT_TASK_IN_PROCESS:
295 	     return "Task In Process";
296 	case ISCSI_REJECT_INVALID_DATA_ACK:
297 	     return "Invalid Data ACK";
298 	case ISCSI_REJECT_INVALID_PDU_FIELD:
299 	     return "Invalid PDU Field";
300 	case ISCSI_REJECT_LONG_OPERATION_REJECT:
301 	     return "Long Operation Reject";
302 	case ISCSI_REJECT_NEGOTIATION_RESET:
303 	     return "Negotiation Reset";
304 	case ISCSI_REJECT_WAITING_FOR_LOGOUT:
305 	     return "Waiting For Logout";
306 	}
307 
308 	return "Unknown";
309 }
310 
iscsi_process_target_nop_in(struct iscsi_context * iscsi,struct iscsi_in_pdu * in)311 int iscsi_process_target_nop_in(struct iscsi_context *iscsi,
312 				struct iscsi_in_pdu *in)
313 {
314 	uint32_t ttt = scsi_get_uint32(&in->hdr[20]);
315 	uint32_t itt = scsi_get_uint32(&in->hdr[16]);
316 	uint32_t lun = scsi_get_uint16(&in->hdr[8]);
317 
318 	ISCSI_LOG(iscsi, (iscsi->nops_in_flight > 1) ? 1 : 6,
319 	          "NOP-In received (pdu->itt %08x, pdu->ttt %08x, pdu->lun %8x, iscsi->maxcmdsn %08x, iscsi->expcmdsn %08x, iscsi->statsn %08x)",
320 	          itt, ttt, lun, iscsi->maxcmdsn, iscsi->expcmdsn, iscsi->statsn);
321 
322 	/* if the server does not want a response */
323 	if (ttt == 0xffffffff) {
324 		return 0;
325 	}
326 
327 	iscsi_send_target_nop_out(iscsi, ttt, lun);
328 
329 	return 0;
330 }
331 
iscsi_reconnect_after_logout(struct iscsi_context * iscsi,int status,void * command_data _U_,void * opaque _U_)332 static void iscsi_reconnect_after_logout(struct iscsi_context *iscsi, int status,
333                         void *command_data _U_, void *opaque _U_)
334 {
335 	if (status) {
336 		ISCSI_LOG(iscsi, 1, "logout failed: %s", iscsi_get_error(iscsi));
337 	}
338 	iscsi->pending_reconnect = 1;
339 }
340 
iscsi_process_reject(struct iscsi_context * iscsi,struct iscsi_in_pdu * in)341 int iscsi_process_reject(struct iscsi_context *iscsi,
342 				struct iscsi_in_pdu *in)
343 {
344 	int size = in->data_pos;
345 	uint32_t itt;
346 	struct iscsi_pdu *pdu;
347 	uint8_t reason = in->hdr[2];
348 
349 	if (size < ISCSI_RAW_HEADER_SIZE) {
350 		iscsi_set_error(iscsi, "size of REJECT payload is too small."
351 				       "Need >= %d bytes but got %d.",
352 				       ISCSI_RAW_HEADER_SIZE, (int)size);
353 		return -1;
354 	}
355 
356 	if (reason == ISCSI_REJECT_WAITING_FOR_LOGOUT) {
357 		ISCSI_LOG(iscsi, 1, "target rejects request with reason: %s",  iscsi_reject_reason_str(reason));
358 		iscsi_logout_async(iscsi, iscsi_reconnect_after_logout, NULL);
359 		return 0;
360 	}
361 
362 	iscsi_set_error(iscsi, "Request was rejected with reason: 0x%02x (%s)", reason, iscsi_reject_reason_str(reason));
363 
364 	itt = scsi_get_uint32(&in->data[16]);
365 
366 	iscsi_dump_pdu_header(iscsi, in->data);
367 
368 	for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) {
369 		if (pdu->itt == itt) {
370 			break;
371 		}
372 	}
373 
374 	if (pdu == NULL) {
375 		iscsi_set_error(iscsi, "Can not match REJECT with"
376 				       "any outstanding pdu with itt:0x%08x",
377 				       itt);
378 		return -1;
379 	}
380 
381 	if (pdu->callback) {
382 		pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL,
383 		              pdu->private_data);
384 	}
385 
386 	ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
387 	iscsi->drv->free_pdu(iscsi, pdu);
388 	return 0;
389 }
390 
iscsi_process_pdu_serials(struct iscsi_context * iscsi,struct iscsi_in_pdu * in)391 static void iscsi_process_pdu_serials(struct iscsi_context *iscsi, struct iscsi_in_pdu *in)
392 {
393 	uint32_t itt = scsi_get_uint32(&in->hdr[16]);
394 	uint32_t statsn = scsi_get_uint32(&in->hdr[24]);
395 	uint32_t maxcmdsn = scsi_get_uint32(&in->hdr[32]);
396 	uint32_t expcmdsn = scsi_get_uint32(&in->hdr[28]);
397 	uint16_t status = scsi_get_uint16(&in->hdr[36]);
398 	uint8_t flags = in->hdr[1];
399 	enum iscsi_opcode opcode = in->hdr[0] & 0x3f;
400 
401 	/* RFC3720 10.13.5 (serials are invalid if status class != 0) */
402 	if (opcode == ISCSI_PDU_LOGIN_RESPONSE && (status >> 8)) {
403 		return;
404 	}
405 
406 	if (iscsi_serial32_compare(maxcmdsn, iscsi->maxcmdsn) > 0) {
407 		iscsi->maxcmdsn = maxcmdsn;
408 	}
409 	if (iscsi_serial32_compare(expcmdsn, iscsi->expcmdsn) > 0) {
410 		iscsi->expcmdsn = expcmdsn;
411 	}
412 
413 	/* RFC3720 10.7.3 (StatSN is invalid if S bit unset in flags) */
414 	if (opcode == ISCSI_PDU_DATA_IN &&
415 	    !(flags & ISCSI_PDU_DATA_CONTAINS_STATUS)) {
416 		return;
417 	}
418 
419 	if (itt == 0xffffffff) {
420 		/* target will not increase statsn if itt == 0xffffffff */
421 		statsn--;
422 	}
423 	if (iscsi_serial32_compare(statsn, iscsi->statsn) > 0) {
424 		iscsi->statsn = statsn;
425 	}
426 }
427 
428 int
iscsi_process_pdu(struct iscsi_context * iscsi,struct iscsi_in_pdu * in)429 iscsi_process_pdu(struct iscsi_context *iscsi, struct iscsi_in_pdu *in)
430 {
431 	uint32_t itt = scsi_get_uint32(&in->hdr[16]);
432 	enum iscsi_opcode opcode = in->hdr[0] & 0x3f;
433 	uint8_t ahslen = in->hdr[4];
434 	struct iscsi_pdu *pdu;
435 
436 	/* verify header checksum */
437 	if (iscsi->header_digest != ISCSI_HEADER_DIGEST_NONE) {
438 		uint32_t crc, crc_rcvd = 0;
439 		crc = crc32c(in->hdr, ISCSI_RAW_HEADER_SIZE);
440 		crc_rcvd |= in->hdr[ISCSI_RAW_HEADER_SIZE+0];
441 		crc_rcvd |= in->hdr[ISCSI_RAW_HEADER_SIZE+1] << 8;
442 		crc_rcvd |= in->hdr[ISCSI_RAW_HEADER_SIZE+2] << 16;
443 		crc_rcvd |= in->hdr[ISCSI_RAW_HEADER_SIZE+3] << 24;
444 		if (crc != crc_rcvd) {
445 			iscsi_set_error(iscsi, "header checksum verification failed: calculated 0x%" PRIx32 " received 0x%" PRIx32, crc, crc_rcvd);
446 			return -1;
447 		}
448 	}
449 
450 	if (ahslen != 0) {
451 		iscsi_set_error(iscsi, "cant handle expanded headers yet");
452 		return -1;
453 	}
454 
455 	/* All target PDUs update the serials */
456 	iscsi_process_pdu_serials(iscsi, in);
457 
458 	if (opcode == ISCSI_PDU_ASYNC_MSG) {
459 		uint8_t event = in->hdr[36];
460 		uint16_t param1 = scsi_get_uint16(&in->hdr[38]);
461 		uint16_t param2 = scsi_get_uint16(&in->hdr[40]);
462 		uint16_t param3 = scsi_get_uint16(&in->hdr[42]);
463 		switch (event) {
464 		case 0x0:
465 			/* Just ignore these ones for now. It could be
466 			 * a UNIT_ATTENTION for some changes on the
467 			 * target but we don't have an API to pass this on
468 			 * to the application yet.
469 			 */
470 			ISCSI_LOG(iscsi, 2, "Ignoring received iSCSI AsyncMsg/"
471 				  "SCSI Async Event");
472 			return 0;
473 		case 0x1:
474 			ISCSI_LOG(iscsi, 2, "target requests logout within %u seconds", param3);
475 			/* this is an ugly workaround for DELL Equallogic FW 7.x bugs:
476 			 *  Bug_71409 - I/O errors during volume move (present before 7.0.7)
477 			 *  Bug_73732 - I/O errors during volume move operation (still present in 7.0.9)
478 			 */
479 			if (getenv("LIBISCSI_DROP_CONN_ON_ASYNC_EVENT1") != NULL) {
480 				ISCSI_LOG(iscsi, 2, "dropping connection to fix errors with broken DELL Equallogic firmware 7.x");
481 				return -1;
482 			}
483 			iscsi_logout_async(iscsi, iscsi_reconnect_after_logout, NULL);
484 			return 0;
485 		case 0x2:
486 			ISCSI_LOG(iscsi, 2, "target will drop this connection. Time2Wait is %u seconds", param2);
487 			iscsi->next_reconnect = time(NULL) + param2;
488 			return 0;
489 		case 0x3:
490 			ISCSI_LOG(iscsi, 2, "target will drop all connections of this session. Time2Wait is %u seconds", param2);
491 			iscsi->next_reconnect = time(NULL) + param2;
492 			return 0;
493 		case 0x4:
494 			ISCSI_LOG(iscsi, 2, "target requests parameter renogitiation.");
495 			iscsi_logout_async(iscsi, iscsi_reconnect_after_logout, NULL);
496 			return 0;
497 		default:
498 			ISCSI_LOG(iscsi, 1, "unhandled async event %u: param1 %u param2 %u param3 %u", event, param1, param2, param3);
499 			return -1;
500 		}
501 	}
502 
503 	if (opcode == ISCSI_PDU_REJECT) {
504 		return iscsi_process_reject(iscsi, in);
505 	}
506 
507 	if (opcode == ISCSI_PDU_NOP_IN && itt == 0xffffffff) {
508 		if (iscsi_process_target_nop_in(iscsi, in) != 0) {
509 			return -1;
510 		}
511 		return 0;
512 	}
513 
514 	for (pdu = iscsi->waitpdu; pdu; pdu = pdu->next) {
515 		enum iscsi_opcode expected_response = pdu->response_opcode;
516 		int is_finished = 1;
517 
518 		if (pdu->itt != itt) {
519 			continue;
520 		}
521 
522 		/* we have a special case with scsi-command opcodes,
523 		 * they are replied to by either a scsi-response
524 		 * or a data-in, or a combination of both.
525 		 */
526 		if (opcode == ISCSI_PDU_DATA_IN
527 		    && expected_response == ISCSI_PDU_SCSI_RESPONSE) {
528 			expected_response = ISCSI_PDU_DATA_IN;
529 		}
530 
531 		/* Another special case is if we get a R2T.
532 		 * In this case we should find the original request and just send an additional
533 		 * DATAOUT segment for this task.
534 		 */
535 		if (opcode == ISCSI_PDU_R2T) {
536 			expected_response = ISCSI_PDU_R2T;
537 		}
538 
539 		if (opcode != expected_response) {
540 			iscsi_set_error(iscsi, "Got wrong opcode back for "
541 					"itt:%d  got:%d expected %d",
542 					itt, opcode, pdu->response_opcode);
543 			return -1;
544 		}
545 		switch (opcode) {
546 		case ISCSI_PDU_LOGIN_RESPONSE:
547 			if (iscsi_process_login_reply(iscsi, pdu, in) != 0) {
548 				ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
549 				iscsi->drv->free_pdu(iscsi, pdu);
550 				iscsi_set_error(iscsi, "iscsi login reply "
551 						"failed");
552 				return -1;
553 			}
554 			break;
555 		case ISCSI_PDU_TEXT_RESPONSE:
556 			if (iscsi_process_text_reply(iscsi, pdu, in) != 0) {
557 				ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
558 				iscsi->drv->free_pdu(iscsi, pdu);
559 				iscsi_set_error(iscsi, "iscsi text reply "
560 						"failed");
561 				return -1;
562 			}
563 			break;
564 		case ISCSI_PDU_LOGOUT_RESPONSE:
565 			if (iscsi_process_logout_reply(iscsi, pdu, in) != 0) {
566 				ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
567 				iscsi->drv->free_pdu(iscsi, pdu);
568 				iscsi_set_error(iscsi, "iscsi logout reply "
569 						"failed");
570 				return -1;
571 			}
572 			break;
573 		case ISCSI_PDU_SCSI_RESPONSE:
574 			if (iscsi_process_scsi_reply(iscsi, pdu, in) != 0) {
575 				ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
576 				iscsi->drv->free_pdu(iscsi, pdu);
577 				iscsi_set_error(iscsi, "iscsi response reply "
578 						"failed");
579 				return -1;
580 			}
581 			break;
582 		case ISCSI_PDU_DATA_IN:
583 			if (iscsi_process_scsi_data_in(iscsi, pdu, in,
584 						       &is_finished) != 0) {
585 				ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
586 				iscsi->drv->free_pdu(iscsi, pdu);
587 				iscsi_set_error(iscsi, "iscsi data in "
588 						"failed");
589 				return -1;
590 			}
591 			break;
592 		case ISCSI_PDU_NOP_IN:
593 			if (iscsi_process_nop_out_reply(iscsi, pdu, in) != 0) {
594 				ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
595 				iscsi->drv->free_pdu(iscsi, pdu);
596 				iscsi_set_error(iscsi, "iscsi nop-in failed");
597 				return -1;
598 			}
599 			break;
600 		case ISCSI_PDU_SCSI_TASK_MANAGEMENT_RESPONSE:
601 			if (iscsi_process_task_mgmt_reply(iscsi, pdu,
602 							  in) != 0) {
603 				ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
604 				iscsi->drv->free_pdu(iscsi, pdu);
605 				iscsi_set_error(iscsi, "iscsi task-mgmt failed");
606 				return -1;
607 			}
608 			break;
609 		case ISCSI_PDU_R2T:
610 			if (iscsi_process_r2t(iscsi, pdu, in) != 0) {
611 				ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
612 				iscsi->drv->free_pdu(iscsi, pdu);
613 				iscsi_set_error(iscsi, "iscsi r2t "
614 						"failed");
615 				return -1;
616 			}
617 			is_finished = 0;
618 			break;
619 		default:
620 			iscsi_set_error(iscsi, "Don't know how to handle "
621 					"opcode 0x%02x", opcode);
622 			return -1;
623 		}
624 
625 		if (is_finished) {
626 			ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
627 			iscsi->drv->free_pdu(iscsi, pdu);
628 		}
629 		return 0;
630 	}
631 
632 	return 0;
633 }
634 
635 void
iscsi_pdu_set_itt(struct iscsi_pdu * pdu,uint32_t itt)636 iscsi_pdu_set_itt(struct iscsi_pdu *pdu, uint32_t itt)
637 {
638 	scsi_set_uint32(&pdu->outdata.data[16], itt);
639 }
640 
641 void
iscsi_pdu_set_ritt(struct iscsi_pdu * pdu,uint32_t ritt)642 iscsi_pdu_set_ritt(struct iscsi_pdu *pdu, uint32_t ritt)
643 {
644 	scsi_set_uint32(&pdu->outdata.data[20], ritt);
645 }
646 
647 void
iscsi_pdu_set_pduflags(struct iscsi_pdu * pdu,unsigned char flags)648 iscsi_pdu_set_pduflags(struct iscsi_pdu *pdu, unsigned char flags)
649 {
650 	pdu->outdata.data[1] = flags;
651 }
652 
653 void
iscsi_pdu_set_immediate(struct iscsi_pdu * pdu)654 iscsi_pdu_set_immediate(struct iscsi_pdu *pdu)
655 {
656 	pdu->outdata.data[0] |= ISCSI_PDU_IMMEDIATE;
657 }
658 
659 void
iscsi_pdu_set_ttt(struct iscsi_pdu * pdu,uint32_t ttt)660 iscsi_pdu_set_ttt(struct iscsi_pdu *pdu, uint32_t ttt)
661 {
662 	scsi_set_uint32(&pdu->outdata.data[20], ttt);
663 }
664 
665 void
iscsi_pdu_set_cmdsn(struct iscsi_pdu * pdu,uint32_t cmdsn)666 iscsi_pdu_set_cmdsn(struct iscsi_pdu *pdu, uint32_t cmdsn)
667 {
668 	scsi_set_uint32(&pdu->outdata.data[24], cmdsn);
669 	pdu->cmdsn = cmdsn;
670 }
671 
672 void
iscsi_pdu_set_rcmdsn(struct iscsi_pdu * pdu,uint32_t rcmdsn)673 iscsi_pdu_set_rcmdsn(struct iscsi_pdu *pdu, uint32_t rcmdsn)
674 {
675 	scsi_set_uint32(&pdu->outdata.data[32], rcmdsn);
676 }
677 
678 void
iscsi_pdu_set_datasn(struct iscsi_pdu * pdu,uint32_t datasn)679 iscsi_pdu_set_datasn(struct iscsi_pdu *pdu, uint32_t datasn)
680 {
681 	scsi_set_uint32(&pdu->outdata.data[36], datasn);
682 }
683 
684 void
iscsi_pdu_set_expstatsn(struct iscsi_pdu * pdu,uint32_t expstatsnsn)685 iscsi_pdu_set_expstatsn(struct iscsi_pdu *pdu, uint32_t expstatsnsn)
686 {
687 	scsi_set_uint32(&pdu->outdata.data[28], expstatsnsn);
688 }
689 
690 void
iscsi_pdu_set_bufferoffset(struct iscsi_pdu * pdu,uint32_t bufferoffset)691 iscsi_pdu_set_bufferoffset(struct iscsi_pdu *pdu, uint32_t bufferoffset)
692 {
693 	scsi_set_uint32(&pdu->outdata.data[40], bufferoffset);
694 }
695 
696 void
iscsi_pdu_set_cdb(struct iscsi_pdu * pdu,struct scsi_task * task)697 iscsi_pdu_set_cdb(struct iscsi_pdu *pdu, struct scsi_task *task)
698 {
699 	memset(&pdu->outdata.data[32], 0, 16);
700 	memcpy(&pdu->outdata.data[32], task->cdb, task->cdb_size);
701 }
702 
703 void
iscsi_pdu_set_lun(struct iscsi_pdu * pdu,uint32_t lun)704 iscsi_pdu_set_lun(struct iscsi_pdu *pdu, uint32_t lun)
705 {
706 	scsi_set_uint16(&pdu->outdata.data[8], lun);
707 }
708 
709 void
iscsi_pdu_set_expxferlen(struct iscsi_pdu * pdu,uint32_t expxferlen)710 iscsi_pdu_set_expxferlen(struct iscsi_pdu *pdu, uint32_t expxferlen)
711 {
712 	pdu->expxferlen = expxferlen;
713 	scsi_set_uint32(&pdu->outdata.data[20], expxferlen);
714 }
715 
716 void
iscsi_timeout_scan(struct iscsi_context * iscsi)717 iscsi_timeout_scan(struct iscsi_context *iscsi)
718 {
719 	struct iscsi_pdu *pdu;
720 	struct iscsi_pdu *next_pdu;
721 	time_t t = time(NULL);
722 
723 	for (pdu = iscsi->outqueue; pdu; pdu = next_pdu) {
724 		next_pdu = pdu->next;
725 
726 		if (pdu->scsi_timeout == 0) {
727 			/* no timeout for this pdu */
728 			continue;
729 		}
730 		if (t < pdu->scsi_timeout) {
731 			/* not expired yet */
732 			continue;
733 		}
734 		ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu);
735 		iscsi_set_error(iscsi, "command timed out");
736 		iscsi_dump_pdu_header(iscsi, pdu->outdata.data);
737 		if (pdu->callback) {
738 			pdu->callback(iscsi, SCSI_STATUS_TIMEOUT,
739 			              NULL, pdu->private_data);
740 		}
741 		iscsi->drv->free_pdu(iscsi, pdu);
742 	}
743 	for (pdu = iscsi->waitpdu; pdu; pdu = next_pdu) {
744 		next_pdu = pdu->next;
745 
746 		if (pdu->scsi_timeout == 0) {
747 			/* no timeout for this pdu */
748 			continue;
749 		}
750 		if (t < pdu->scsi_timeout) {
751 			/* not expired yet */
752 			continue;
753 		}
754 		ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
755 		iscsi_set_error(iscsi, "command timed out");
756 		iscsi_dump_pdu_header(iscsi, pdu->outdata.data);
757 		if (pdu->callback) {
758 			pdu->callback(iscsi, SCSI_STATUS_TIMEOUT,
759 			              NULL, pdu->private_data);
760 		}
761 		iscsi->drv->free_pdu(iscsi, pdu);
762 	}
763 }
764 
765 int
iscsi_queue_pdu(struct iscsi_context * iscsi,struct iscsi_pdu * pdu)766 iscsi_queue_pdu(struct iscsi_context *iscsi, struct iscsi_pdu *pdu)
767 {
768 	return iscsi->drv->queue_pdu(iscsi, pdu);
769 }
770 
771 void
iscsi_cancel_pdus(struct iscsi_context * iscsi)772 iscsi_cancel_pdus(struct iscsi_context *iscsi)
773 {
774 	struct iscsi_pdu *pdu;
775 
776 	while ((pdu = iscsi->outqueue)) {
777 		ISCSI_LIST_REMOVE(&iscsi->outqueue, pdu);
778 		if (iscsi->is_loggedin && pdu->callback) {
779 			/* If an error happened during connect/login,
780 			   we don't want to call any of the callbacks.
781 			*/
782 			pdu->callback(iscsi, SCSI_STATUS_CANCELLED,
783 			              NULL, pdu->private_data);
784 		}
785 		iscsi->drv->free_pdu(iscsi, pdu);
786 	}
787 	while ((pdu = iscsi->waitpdu)) {
788 		ISCSI_LIST_REMOVE(&iscsi->waitpdu, pdu);
789 		if (iscsi->is_loggedin && pdu->callback) {
790 			/* If an error happened during connect/login,
791 			   we don't want to call any of the callbacks.
792 			*/
793 			pdu->callback(iscsi, SCSI_STATUS_CANCELLED,
794 			              NULL, pdu->private_data);
795 		}
796 		iscsi->drv->free_pdu(iscsi, pdu);
797 	}
798 }
799