pdu.c revision 307697
11590Srgrimes/*-
21590Srgrimes * Copyright (c) 2012 The FreeBSD Foundation
31590Srgrimes * All rights reserved.
41590Srgrimes *
51590Srgrimes * This software was developed by Edward Tomasz Napierala under sponsorship
61590Srgrimes * from the FreeBSD Foundation.
71590Srgrimes *
81590Srgrimes * Redistribution and use in source and binary forms, with or without
91590Srgrimes * modification, are permitted provided that the following conditions
101590Srgrimes * are met:
111590Srgrimes * 1. Redistributions of source code must retain the above copyright
121590Srgrimes *    notice, this list of conditions and the following disclaimer.
131590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141590Srgrimes *    notice, this list of conditions and the following disclaimer in the
151590Srgrimes *    documentation and/or other materials provided with the distribution.
161590Srgrimes *
171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271590Srgrimes * SUCH DAMAGE.
281590Srgrimes *
291590Srgrimes */
301590Srgrimes
311590Srgrimes#include <sys/cdefs.h>
321590Srgrimes__FBSDID("$FreeBSD: stable/11/usr.sbin/iscsid/pdu.c 307697 2016-10-21 03:10:05Z araujo $");
331590Srgrimes
341590Srgrimes#include <sys/types.h>
3578201Sdd#include <sys/uio.h>
361590Srgrimes#include <assert.h>
371590Srgrimes#include <errno.h>
381590Srgrimes#include <stdlib.h>
391590Srgrimes#include <string.h>
401590Srgrimes#include <unistd.h>
4178201Sdd
421590Srgrimes#include "iscsid.h"
4399112Sobrien#include "iscsi_proto.h"
4499112Sobrien
451590Srgrimes#ifdef ICL_KERNEL_PROXY
461590Srgrimes#include <sys/ioctl.h>
471590Srgrimes#endif
481590Srgrimes
491590Srgrimesstatic int
50118077Stjrpdu_ahs_length(const struct pdu *pdu)
511590Srgrimes{
5274588Sache
5316438Sache	return (pdu->pdu_bhs->bhs_total_ahs_len * 4);
541590Srgrimes}
551590Srgrimes
561590Srgrimesstatic int
571590Srgrimespdu_data_segment_length(const struct pdu *pdu)
581590Srgrimes{
591590Srgrimes	uint32_t len = 0;
60125856Sdwmalone
611590Srgrimes	len += pdu->pdu_bhs->bhs_data_segment_len[0];
62202197Sed	len <<= 8;
6311547Sdg	len += pdu->pdu_bhs->bhs_data_segment_len[1];
641590Srgrimes	len <<= 8;
651590Srgrimes	len += pdu->pdu_bhs->bhs_data_segment_len[2];
661590Srgrimes
6777291Sdd	return (len);
681590Srgrimes}
691590Srgrimes
701590Srgrimesstatic void
711590Srgrimespdu_set_data_segment_length(struct pdu *pdu, uint32_t len)
721590Srgrimes{
731590Srgrimes
741590Srgrimes	pdu->pdu_bhs->bhs_data_segment_len[2] = len;
751590Srgrimes	pdu->pdu_bhs->bhs_data_segment_len[1] = len >> 8;
761590Srgrimes	pdu->pdu_bhs->bhs_data_segment_len[0] = len >> 16;
771590Srgrimes}
781590Srgrimes
79202197Sedstruct pdu *
8011547Sdgpdu_new(struct connection *conn)
81202197Sed{
8236062Sjb	struct pdu *pdu;
83202197Sed
84202197Sed	pdu = calloc(1, sizeof(*pdu));
8511547Sdg	if (pdu == NULL)
861590Srgrimes		log_err(1, "calloc");
8791536Siedowse
88202197Sed	pdu->pdu_bhs = calloc(1, sizeof(*pdu->pdu_bhs));
89202197Sed	if (pdu->pdu_bhs == NULL)
90202197Sed		log_err(1, "calloc");
9136434Sdanny
9236434Sdanny	pdu->pdu_connection = conn;
9391541Siedowse
9474588Sache	return (pdu);
9591538Siedowse}
9677291Sdd
9777291Sddstruct pdu *
9877291Sddpdu_new_response(struct pdu *request)
9977291Sdd{
1001590Srgrimes
10192920Simp	return (pdu_new(request->pdu_connection));
10292920Simp}
103202197Sed
10492920Simp#ifdef ICL_KERNEL_PROXY
105202197Sed
10692920Simpstatic void
107202197Sedpdu_receive_proxy(struct pdu *pdu)
10892920Simp{
10992920Simp	struct iscsi_daemon_receive *idr;
1101590Srgrimes	size_t len;
11136434Sdanny	int error;
11236434Sdanny
11336434Sdanny	assert(pdu->pdu_connection->conn_conf.isc_iser != 0);
11436434Sdanny
115119023Stjr	pdu->pdu_data = malloc(ISCSI_MAX_DATA_SEGMENT_LENGTH);
116119023Stjr	if (pdu->pdu_data == NULL)
11736434Sdanny		log_err(1, "malloc");
11836434Sdanny
11936434Sdanny	idr = calloc(1, sizeof(*idr));
1201590Srgrimes	if (idr == NULL)
121102944Sdwmalone		log_err(1, "calloc");
1221590Srgrimes
1231590Srgrimes	idr->idr_session_id = pdu->pdu_connection->conn_session_id;
1241590Srgrimes	idr->idr_bhs = pdu->pdu_bhs;
1251590Srgrimes	idr->idr_data_segment_len = ISCSI_MAX_DATA_SEGMENT_LENGTH;
12616438Sache	idr->idr_data_segment = pdu->pdu_data;
12774588Sache
12816438Sache	error = ioctl(pdu->pdu_connection->conn_iscsi_fd, ISCSIDRECEIVE, idr);
1291590Srgrimes	if (error != 0)
13077291Sdd		log_err(1, "ISCSIDRECEIVE");
131118077Stjr
1321590Srgrimes	len = pdu_ahs_length(pdu);
1331590Srgrimes	if (len > 0)
1341590Srgrimes		log_errx(1, "protocol error: non-empty AHS");
1351590Srgrimes
1361590Srgrimes	len = pdu_data_segment_length(pdu);
1371590Srgrimes	assert(len <= ISCSI_MAX_DATA_SEGMENT_LENGTH);
1381590Srgrimes	pdu->pdu_data_len = len;
1391590Srgrimes
140106215Smux	free(idr);
141106215Smux}
142106215Smux
143106215Smuxstatic void
1441590Srgrimespdu_send_proxy(struct pdu *pdu)
1451590Srgrimes{
1461590Srgrimes	struct iscsi_daemon_send *ids;
1471590Srgrimes	int error;
14877291Sdd
14977291Sdd	assert(pdu->pdu_connection->conn_conf.isc_iser != 0);
15077291Sdd
1511590Srgrimes	pdu_set_data_segment_length(pdu, pdu->pdu_data_len);
1521590Srgrimes
1531590Srgrimes	ids = calloc(1, sizeof(*ids));
1541590Srgrimes	if (ids == NULL)
1551590Srgrimes		log_err(1, "calloc");
1561590Srgrimes
1571590Srgrimes	ids->ids_session_id = pdu->pdu_connection->conn_session_id;
158118077Stjr	ids->ids_bhs = pdu->pdu_bhs;
159118077Stjr	ids->ids_data_segment_len = pdu->pdu_data_len;
160118077Stjr	ids->ids_data_segment = pdu->pdu_data;
161118077Stjr
162118077Stjr	error = ioctl(pdu->pdu_connection->conn_iscsi_fd, ISCSIDSEND, ids);
163118077Stjr	if (error != 0)
164118077Stjr		log_err(1, "ISCSIDSEND");
16536434Sdanny
16636434Sdanny	free(ids);
16736434Sdanny}
1681590Srgrimes
1691590Srgrimes#endif /* ICL_KERNEL_PROXY */
1701590Srgrimes
17136434Sdannystatic size_t
17236434Sdannypdu_padding(const struct pdu *pdu)
17336434Sdanny{
17491541Siedowse
17591541Siedowse	if ((pdu->pdu_data_len % 4) != 0)
17691541Siedowse		return (4 - (pdu->pdu_data_len % 4));
1771590Srgrimes
1781590Srgrimes	return (0);
17936434Sdanny}
1801590Srgrimes
1811590Srgrimesstatic void
18236434Sdannypdu_read(const struct connection *conn, char *data, size_t len)
18336434Sdanny{
1841590Srgrimes	ssize_t ret;
1851590Srgrimes
1861590Srgrimes	while (len > 0) {
1871590Srgrimes		ret = read(conn->conn_socket, data, len);
1881590Srgrimes		if (ret < 0) {
1891590Srgrimes			if (timed_out()) {
1901590Srgrimes				fail(conn, "Login Phase timeout");
1911590Srgrimes				log_errx(1, "exiting due to timeout");
1921590Srgrimes			}
1931590Srgrimes			fail(conn, strerror(errno));
1941590Srgrimes			log_err(1, "read");
1951590Srgrimes		} else if (ret == 0) {
1961590Srgrimes			fail(conn, "connection lost");
1971590Srgrimes			log_errx(1, "read: connection lost");
1981590Srgrimes		}
1991590Srgrimes		len -= ret;
2001590Srgrimes		data += ret;
2011590Srgrimes	}
2021590Srgrimes}
2031590Srgrimes
204102944Sdwmalonevoid
2051590Srgrimespdu_receive(struct pdu *pdu)
206202643Sed{
207202197Sed	size_t len, padding;
208202643Sed	char dummy[4];
209202197Sed
21016438Sache#ifdef ICL_KERNEL_PROXY
21116438Sache	if (pdu->pdu_connection->conn_conf.isc_iser != 0)
2121590Srgrimes		return (pdu_receive_proxy(pdu));
213202197Sed#endif
214202197Sed
21511547Sdg	assert(pdu->pdu_connection->conn_conf.isc_iser == 0);
216202197Sed
217202197Sed	pdu_read(pdu->pdu_connection,
2181590Srgrimes	    (char *)pdu->pdu_bhs, sizeof(*pdu->pdu_bhs));
219202197Sed
220202643Sed	len = pdu_ahs_length(pdu);
221202643Sed	if (len > 0)
222202643Sed		log_errx(1, "protocol error: non-empty AHS");
223202643Sed
224202643Sed	len = pdu_data_segment_length(pdu);
225202643Sed	if (len > 0) {
226202197Sed		if (len > ISCSI_MAX_DATA_SEGMENT_LENGTH) {
227202197Sed			log_errx(1, "protocol error: received PDU "
228202197Sed			    "with DataSegmentLength exceeding %d",
229202197Sed			    ISCSI_MAX_DATA_SEGMENT_LENGTH);
2301590Srgrimes		}
231202197Sed
232202197Sed		pdu->pdu_data_len = len;
233202643Sed		pdu->pdu_data = malloc(len);
2341590Srgrimes		if (pdu->pdu_data == NULL)
23585648Sdillon			log_err(1, "malloc");
23678201Sdd
23762871Skris		pdu_read(pdu->pdu_connection,
2381590Srgrimes		    (char *)pdu->pdu_data, pdu->pdu_data_len);
2391590Srgrimes
2401590Srgrimes		padding = pdu_padding(pdu);
24191536Siedowse		if (padding != 0) {
24291536Siedowse			assert(padding < sizeof(dummy));
24391536Siedowse			pdu_read(pdu->pdu_connection,
24491536Siedowse			    (char *)dummy, padding);
245202197Sed		}
24691536Siedowse	}
247202197Sed}
24891536Siedowse
249202197Sedvoid
250202197Sedpdu_send(struct pdu *pdu)
25191536Siedowse{
252202197Sed	ssize_t ret, total_len;
25391536Siedowse	size_t padding;
25491536Siedowse	uint32_t zero = 0;
25591536Siedowse	struct iovec iov[3];
25691536Siedowse	int iovcnt;
25791536Siedowse
258202197Sed#ifdef ICL_KERNEL_PROXY
259202197Sed	if (pdu->pdu_connection->conn_conf.isc_iser != 0)
26091536Siedowse		return (pdu_send_proxy(pdu));
26191536Siedowse#endif
26291536Siedowse
26391536Siedowse	assert(pdu->pdu_connection->conn_conf.isc_iser == 0);
26491536Siedowse
26591536Siedowse	pdu_set_data_segment_length(pdu, pdu->pdu_data_len);
26691536Siedowse	iov[0].iov_base = pdu->pdu_bhs;
26791536Siedowse	iov[0].iov_len = sizeof(*pdu->pdu_bhs);
26891536Siedowse	total_len = iov[0].iov_len;
26991536Siedowse	iovcnt = 1;
27091536Siedowse
27191538Siedowse	if (pdu->pdu_data_len > 0) {
27291536Siedowse		iov[1].iov_base = pdu->pdu_data;
27391536Siedowse		iov[1].iov_len = pdu->pdu_data_len;
27491536Siedowse		total_len += iov[1].iov_len;
275202197Sed		iovcnt = 2;
276202197Sed
27791538Siedowse		padding = pdu_padding(pdu);
27891536Siedowse		if (padding > 0) {
27991536Siedowse			assert(padding < sizeof(zero));
28091536Siedowse			iov[2].iov_base = &zero;
281202197Sed			iov[2].iov_len = padding;
282202197Sed			total_len += iov[2].iov_len;
283202197Sed			iovcnt = 3;
284202197Sed		}
285202197Sed	}
286202197Sed
287202197Sed	ret = writev(pdu->pdu_connection->conn_socket, iov, iovcnt);
28891536Siedowse	if (ret < 0) {
28991536Siedowse		if (timed_out())
29091536Siedowse			log_errx(1, "exiting due to timeout");
29191536Siedowse		log_err(1, "writev");
292202197Sed	}
29391536Siedowse	if (ret != total_len)
29496785Sjmallett		log_errx(1, "short write");
29591536Siedowse}
296202197Sed
297202197Sedvoid
29891536Siedowsepdu_delete(struct pdu *pdu)
29991536Siedowse{
30091536Siedowse
30191536Siedowse	free(pdu->pdu_data);
30291536Siedowse	free(pdu->pdu_bhs);
30391536Siedowse	free(pdu);
304202197Sed}
305202197Sed