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