1*fcf3ce44SJohn Forte /* 2*fcf3ce44SJohn Forte * CDDL HEADER START 3*fcf3ce44SJohn Forte * 4*fcf3ce44SJohn Forte * The contents of this file are subject to the terms of the 5*fcf3ce44SJohn Forte * Common Development and Distribution License (the "License"). 6*fcf3ce44SJohn Forte * You may not use this file except in compliance with the License. 7*fcf3ce44SJohn Forte * 8*fcf3ce44SJohn Forte * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*fcf3ce44SJohn Forte * or http://www.opensolaris.org/os/licensing. 10*fcf3ce44SJohn Forte * See the License for the specific language governing permissions 11*fcf3ce44SJohn Forte * and limitations under the License. 12*fcf3ce44SJohn Forte * 13*fcf3ce44SJohn Forte * When distributing Covered Code, include this CDDL HEADER in each 14*fcf3ce44SJohn Forte * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*fcf3ce44SJohn Forte * If applicable, add the following below this CDDL HEADER, with the 16*fcf3ce44SJohn Forte * fields enclosed by brackets "[]" replaced with your own identifying 17*fcf3ce44SJohn Forte * information: Portions Copyright [yyyy] [name of copyright owner] 18*fcf3ce44SJohn Forte * 19*fcf3ce44SJohn Forte * CDDL HEADER END 20*fcf3ce44SJohn Forte */ 21*fcf3ce44SJohn Forte 22*fcf3ce44SJohn Forte /* 23*fcf3ce44SJohn Forte * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24*fcf3ce44SJohn Forte * Use is subject to license terms. 25*fcf3ce44SJohn Forte */ 26*fcf3ce44SJohn Forte 27*fcf3ce44SJohn Forte #include <stdio.h> 28*fcf3ce44SJohn Forte #include <stdlib.h> 29*fcf3ce44SJohn Forte #include <string.h> 30*fcf3ce44SJohn Forte #include <strings.h> 31*fcf3ce44SJohn Forte #include <sys/types.h> 32*fcf3ce44SJohn Forte #include <sys/socket.h> 33*fcf3ce44SJohn Forte #include <netinet/in.h> 34*fcf3ce44SJohn Forte #include <arpa/inet.h> 35*fcf3ce44SJohn Forte #include <unistd.h> 36*fcf3ce44SJohn Forte #include <poll.h> 37*fcf3ce44SJohn Forte #include <errno.h> 38*fcf3ce44SJohn Forte 39*fcf3ce44SJohn Forte #include "isns_server.h" 40*fcf3ce44SJohn Forte #include "isns_log.h" 41*fcf3ce44SJohn Forte #include "isns_pdu.h" 42*fcf3ce44SJohn Forte 43*fcf3ce44SJohn Forte #define ISNS_MAX_IOVEC 5 44*fcf3ce44SJohn Forte #define MAX_XID (2^16) 45*fcf3ce44SJohn Forte #define MAX_RCV_RSP_COUNT 10 /* Maximum number of unmatched xid */ 46*fcf3ce44SJohn Forte #define ISNS_RCV_RETRY_MAX 2 47*fcf3ce44SJohn Forte #define IPV4_RSVD_BYTES 10 48*fcf3ce44SJohn Forte 49*fcf3ce44SJohn Forte /* externs */ 50*fcf3ce44SJohn Forte #ifdef DEBUG 51*fcf3ce44SJohn Forte extern void dump_pdu2(isns_pdu_t *); 52*fcf3ce44SJohn Forte #endif 53*fcf3ce44SJohn Forte 54*fcf3ce44SJohn Forte /* 55*fcf3ce44SJohn Forte * local functions. 56*fcf3ce44SJohn Forte */ 57*fcf3ce44SJohn Forte 58*fcf3ce44SJohn Forte size_t 59*fcf3ce44SJohn Forte isns_rcv_pdu( 60*fcf3ce44SJohn Forte int fd, 61*fcf3ce44SJohn Forte isns_pdu_t **pdu, 62*fcf3ce44SJohn Forte size_t *pdu_size, 63*fcf3ce44SJohn Forte int rcv_timeout 64*fcf3ce44SJohn Forte ) 65*fcf3ce44SJohn Forte { 66*fcf3ce44SJohn Forte int poll_cnt; 67*fcf3ce44SJohn Forte struct pollfd fds; 68*fcf3ce44SJohn Forte iovec_t iovec[ISNS_MAX_IOVEC]; 69*fcf3ce44SJohn Forte isns_pdu_t *tmp_pdu_hdr; 70*fcf3ce44SJohn Forte ssize_t bytes_received, total_bytes_received = 0; 71*fcf3ce44SJohn Forte struct msghdr msg; 72*fcf3ce44SJohn Forte uint8_t *tmp_pdu_data; 73*fcf3ce44SJohn Forte 74*fcf3ce44SJohn Forte uint16_t payload_len = 0; 75*fcf3ce44SJohn Forte 76*fcf3ce44SJohn Forte /* initialize to zero */ 77*fcf3ce44SJohn Forte *pdu = NULL; 78*fcf3ce44SJohn Forte *pdu_size = 0; 79*fcf3ce44SJohn Forte 80*fcf3ce44SJohn Forte fds.fd = fd; 81*fcf3ce44SJohn Forte fds.events = (POLLIN | POLLRDNORM); 82*fcf3ce44SJohn Forte fds.revents = 0; 83*fcf3ce44SJohn Forte 84*fcf3ce44SJohn Forte /* Receive the header first */ 85*fcf3ce44SJohn Forte tmp_pdu_hdr = (isns_pdu_t *)malloc(ISNSP_HEADER_SIZE); 86*fcf3ce44SJohn Forte if (tmp_pdu_hdr == NULL) { 87*fcf3ce44SJohn Forte return (0); 88*fcf3ce44SJohn Forte } 89*fcf3ce44SJohn Forte (void) memset((void *)&tmp_pdu_hdr[0], 0, ISNSP_HEADER_SIZE); 90*fcf3ce44SJohn Forte (void) memset((void *)&iovec[0], 0, sizeof (iovec_t)); 91*fcf3ce44SJohn Forte iovec[0].iov_base = (void *)tmp_pdu_hdr; 92*fcf3ce44SJohn Forte iovec[0].iov_len = ISNSP_HEADER_SIZE; 93*fcf3ce44SJohn Forte 94*fcf3ce44SJohn Forte /* Initialization of the message header. */ 95*fcf3ce44SJohn Forte bzero(&msg, sizeof (msg)); 96*fcf3ce44SJohn Forte msg.msg_iov = &iovec[0]; 97*fcf3ce44SJohn Forte /* msg.msg_flags = MSG_WAITALL, */ 98*fcf3ce44SJohn Forte msg.msg_iovlen = 1; 99*fcf3ce44SJohn Forte 100*fcf3ce44SJohn Forte /* Poll and receive the pdu header */ 101*fcf3ce44SJohn Forte poll_cnt = 0; 102*fcf3ce44SJohn Forte do { 103*fcf3ce44SJohn Forte int err = poll(&fds, 1, rcv_timeout * 1000); 104*fcf3ce44SJohn Forte if (err <= 0) { 105*fcf3ce44SJohn Forte poll_cnt ++; 106*fcf3ce44SJohn Forte } else { 107*fcf3ce44SJohn Forte bytes_received = recvmsg(fd, &msg, MSG_WAITALL); 108*fcf3ce44SJohn Forte break; 109*fcf3ce44SJohn Forte } 110*fcf3ce44SJohn Forte } while (poll_cnt < ISNS_RCV_RETRY_MAX); 111*fcf3ce44SJohn Forte 112*fcf3ce44SJohn Forte if (poll_cnt >= ISNS_RCV_RETRY_MAX) { 113*fcf3ce44SJohn Forte free(tmp_pdu_hdr); 114*fcf3ce44SJohn Forte return (0); 115*fcf3ce44SJohn Forte } 116*fcf3ce44SJohn Forte 117*fcf3ce44SJohn Forte if (bytes_received <= 0) { 118*fcf3ce44SJohn Forte free(tmp_pdu_hdr); 119*fcf3ce44SJohn Forte return (0); 120*fcf3ce44SJohn Forte } 121*fcf3ce44SJohn Forte 122*fcf3ce44SJohn Forte total_bytes_received += bytes_received; 123*fcf3ce44SJohn Forte 124*fcf3ce44SJohn Forte payload_len = ntohs(tmp_pdu_hdr->payload_len); 125*fcf3ce44SJohn Forte /* Verify the received payload len is within limit */ 126*fcf3ce44SJohn Forte if (payload_len > ISNSP_MAX_PAYLOAD_SIZE) { 127*fcf3ce44SJohn Forte free(tmp_pdu_hdr); 128*fcf3ce44SJohn Forte return (0); 129*fcf3ce44SJohn Forte } 130*fcf3ce44SJohn Forte 131*fcf3ce44SJohn Forte /* Proceed to receive additional data. */ 132*fcf3ce44SJohn Forte tmp_pdu_data = malloc(payload_len); 133*fcf3ce44SJohn Forte if (tmp_pdu_data == NULL) { 134*fcf3ce44SJohn Forte free(tmp_pdu_hdr); 135*fcf3ce44SJohn Forte return (0); 136*fcf3ce44SJohn Forte } 137*fcf3ce44SJohn Forte (void) memset((void *)&iovec[0], 0, sizeof (iovec_t)); 138*fcf3ce44SJohn Forte iovec[0].iov_base = (void *)tmp_pdu_data; 139*fcf3ce44SJohn Forte iovec[0].iov_len = payload_len; 140*fcf3ce44SJohn Forte 141*fcf3ce44SJohn Forte /* Initialization of the message header. */ 142*fcf3ce44SJohn Forte bzero(&msg, sizeof (msg)); 143*fcf3ce44SJohn Forte msg.msg_iov = &iovec[0]; 144*fcf3ce44SJohn Forte /* msg.msg_flags = MSG_WAITALL, */ 145*fcf3ce44SJohn Forte msg.msg_iovlen = 1; 146*fcf3ce44SJohn Forte 147*fcf3ce44SJohn Forte /* poll and receive the pdu payload */ 148*fcf3ce44SJohn Forte poll_cnt = 0; 149*fcf3ce44SJohn Forte do { 150*fcf3ce44SJohn Forte int err = poll(&fds, 1, rcv_timeout * 1000); 151*fcf3ce44SJohn Forte if (err <= 0) { 152*fcf3ce44SJohn Forte poll_cnt ++; 153*fcf3ce44SJohn Forte } else { 154*fcf3ce44SJohn Forte bytes_received = recvmsg(fd, &msg, MSG_WAITALL); 155*fcf3ce44SJohn Forte break; 156*fcf3ce44SJohn Forte } 157*fcf3ce44SJohn Forte } while (poll_cnt < ISNS_RCV_RETRY_MAX); 158*fcf3ce44SJohn Forte 159*fcf3ce44SJohn Forte if (poll_cnt >= ISNS_RCV_RETRY_MAX) { 160*fcf3ce44SJohn Forte free(tmp_pdu_data); 161*fcf3ce44SJohn Forte free(tmp_pdu_hdr); 162*fcf3ce44SJohn Forte return (0); 163*fcf3ce44SJohn Forte } 164*fcf3ce44SJohn Forte 165*fcf3ce44SJohn Forte if (bytes_received <= 0) { 166*fcf3ce44SJohn Forte free(tmp_pdu_data); 167*fcf3ce44SJohn Forte free(tmp_pdu_hdr); 168*fcf3ce44SJohn Forte return (0); 169*fcf3ce44SJohn Forte } 170*fcf3ce44SJohn Forte 171*fcf3ce44SJohn Forte total_bytes_received += bytes_received; 172*fcf3ce44SJohn Forte 173*fcf3ce44SJohn Forte *pdu_size = ISNSP_HEADER_SIZE + payload_len; 174*fcf3ce44SJohn Forte (*pdu) = (isns_pdu_t *)malloc(*pdu_size); 175*fcf3ce44SJohn Forte if (*pdu == NULL) { 176*fcf3ce44SJohn Forte *pdu_size = 0; 177*fcf3ce44SJohn Forte free(tmp_pdu_data); 178*fcf3ce44SJohn Forte free(tmp_pdu_hdr); 179*fcf3ce44SJohn Forte return (0); 180*fcf3ce44SJohn Forte } 181*fcf3ce44SJohn Forte (*pdu)->version = ntohs(tmp_pdu_hdr->version); 182*fcf3ce44SJohn Forte (*pdu)->func_id = ntohs(tmp_pdu_hdr->func_id); 183*fcf3ce44SJohn Forte (*pdu)->payload_len = payload_len; 184*fcf3ce44SJohn Forte (*pdu)->flags = ntohs(tmp_pdu_hdr->flags); 185*fcf3ce44SJohn Forte (*pdu)->xid = ntohs(tmp_pdu_hdr->xid); 186*fcf3ce44SJohn Forte (*pdu)->seq = ntohs(tmp_pdu_hdr->seq); 187*fcf3ce44SJohn Forte (void) memcpy(&((*pdu)->payload), tmp_pdu_data, payload_len); 188*fcf3ce44SJohn Forte 189*fcf3ce44SJohn Forte free(tmp_pdu_data); 190*fcf3ce44SJohn Forte tmp_pdu_data = NULL; 191*fcf3ce44SJohn Forte free(tmp_pdu_hdr); 192*fcf3ce44SJohn Forte tmp_pdu_hdr = NULL; 193*fcf3ce44SJohn Forte 194*fcf3ce44SJohn Forte return (total_bytes_received); 195*fcf3ce44SJohn Forte } 196*fcf3ce44SJohn Forte 197*fcf3ce44SJohn Forte int 198*fcf3ce44SJohn Forte isns_send_pdu( 199*fcf3ce44SJohn Forte int fd, 200*fcf3ce44SJohn Forte isns_pdu_t *pdu, 201*fcf3ce44SJohn Forte size_t pl 202*fcf3ce44SJohn Forte ) 203*fcf3ce44SJohn Forte { 204*fcf3ce44SJohn Forte uint8_t *payload; 205*fcf3ce44SJohn Forte uint16_t flags; 206*fcf3ce44SJohn Forte uint16_t seq; 207*fcf3ce44SJohn Forte iovec_t iovec[ISNS_MAX_IOVEC]; 208*fcf3ce44SJohn Forte struct msghdr msg = { 0 }; 209*fcf3ce44SJohn Forte 210*fcf3ce44SJohn Forte size_t send_len; 211*fcf3ce44SJohn Forte ssize_t bytes_sent; 212*fcf3ce44SJohn Forte 213*fcf3ce44SJohn Forte 214*fcf3ce44SJohn Forte /* Initialization of the message header. */ 215*fcf3ce44SJohn Forte msg.msg_iov = &iovec[0]; 216*fcf3ce44SJohn Forte /* msg.msg_flags = MSG_WAITALL, */ 217*fcf3ce44SJohn Forte msg.msg_iovlen = 2; 218*fcf3ce44SJohn Forte 219*fcf3ce44SJohn Forte /* 220*fcf3ce44SJohn Forte * Initialize the pdu flags. 221*fcf3ce44SJohn Forte */ 222*fcf3ce44SJohn Forte flags = ISNS_FLAG_SERVER; 223*fcf3ce44SJohn Forte flags |= ISNS_FLAG_FIRST_PDU; 224*fcf3ce44SJohn Forte 225*fcf3ce44SJohn Forte /* 226*fcf3ce44SJohn Forte * Initialize the pdu sequence id. 227*fcf3ce44SJohn Forte */ 228*fcf3ce44SJohn Forte seq = 0; 229*fcf3ce44SJohn Forte 230*fcf3ce44SJohn Forte iovec[0].iov_base = (void *)pdu; 231*fcf3ce44SJohn Forte iovec[0].iov_len = (ISNSP_HEADER_SIZE); 232*fcf3ce44SJohn Forte 233*fcf3ce44SJohn Forte payload = pdu->payload; 234*fcf3ce44SJohn Forte 235*fcf3ce44SJohn Forte #ifdef DEBUG 236*fcf3ce44SJohn Forte pdu->flags = htons(flags); 237*fcf3ce44SJohn Forte pdu->seq = htons(0); 238*fcf3ce44SJohn Forte pdu->payload_len = htons(pl); 239*fcf3ce44SJohn Forte dump_pdu2(pdu); 240*fcf3ce44SJohn Forte #endif 241*fcf3ce44SJohn Forte 242*fcf3ce44SJohn Forte do { 243*fcf3ce44SJohn Forte /* set the payload for sending */ 244*fcf3ce44SJohn Forte iovec[1].iov_base = (void *)payload; 245*fcf3ce44SJohn Forte 246*fcf3ce44SJohn Forte if (pl > ISNSP_MAX_PAYLOAD_SIZE) { 247*fcf3ce44SJohn Forte send_len = ISNSP_MAX_PAYLOAD_SIZE; 248*fcf3ce44SJohn Forte } else { 249*fcf3ce44SJohn Forte send_len = pl; 250*fcf3ce44SJohn Forte /* set the last pdu flag */ 251*fcf3ce44SJohn Forte flags |= ISNS_FLAG_LAST_PDU; 252*fcf3ce44SJohn Forte } 253*fcf3ce44SJohn Forte iovec[1].iov_len = send_len; 254*fcf3ce44SJohn Forte pdu->payload_len = htons(send_len); 255*fcf3ce44SJohn Forte 256*fcf3ce44SJohn Forte /* set the pdu flags */ 257*fcf3ce44SJohn Forte pdu->flags = htons(flags); 258*fcf3ce44SJohn Forte /* set the pdu sequence id */ 259*fcf3ce44SJohn Forte pdu->seq = htons(seq); 260*fcf3ce44SJohn Forte 261*fcf3ce44SJohn Forte /* send the packet */ 262*fcf3ce44SJohn Forte bytes_sent = sendmsg(fd, &msg, 0); 263*fcf3ce44SJohn Forte 264*fcf3ce44SJohn Forte /* get rid of the first pdu flag */ 265*fcf3ce44SJohn Forte flags &= ~(ISNS_FLAG_FIRST_PDU); 266*fcf3ce44SJohn Forte 267*fcf3ce44SJohn Forte /* next part of payload */ 268*fcf3ce44SJohn Forte payload += send_len; 269*fcf3ce44SJohn Forte pl -= send_len; 270*fcf3ce44SJohn Forte 271*fcf3ce44SJohn Forte /* add the length of header for verification */ 272*fcf3ce44SJohn Forte send_len += ISNSP_HEADER_SIZE; 273*fcf3ce44SJohn Forte 274*fcf3ce44SJohn Forte /* increase the sequence id by one */ 275*fcf3ce44SJohn Forte seq ++; 276*fcf3ce44SJohn Forte } while (bytes_sent == send_len && pl > 0); 277*fcf3ce44SJohn Forte 278*fcf3ce44SJohn Forte if (bytes_sent == send_len) { 279*fcf3ce44SJohn Forte return (0); 280*fcf3ce44SJohn Forte } else { 281*fcf3ce44SJohn Forte isnslog(LOG_DEBUG, "isns_send_pdu", "sending pdu failed."); 282*fcf3ce44SJohn Forte return (-1); 283*fcf3ce44SJohn Forte } 284*fcf3ce44SJohn Forte } 285*fcf3ce44SJohn Forte 286*fcf3ce44SJohn Forte #define RSP_PDU_FRAG_SZ (ISNSP_MAX_PDU_SIZE / 10) 287*fcf3ce44SJohn Forte static int 288*fcf3ce44SJohn Forte pdu_reset( 289*fcf3ce44SJohn Forte isns_pdu_t **rsp, 290*fcf3ce44SJohn Forte size_t *sz 291*fcf3ce44SJohn Forte ) 292*fcf3ce44SJohn Forte { 293*fcf3ce44SJohn Forte int ec = 0; 294*fcf3ce44SJohn Forte 295*fcf3ce44SJohn Forte if (*rsp == NULL) { 296*fcf3ce44SJohn Forte *rsp = (isns_pdu_t *)malloc(RSP_PDU_FRAG_SZ); 297*fcf3ce44SJohn Forte if (*rsp != NULL) { 298*fcf3ce44SJohn Forte *sz = RSP_PDU_FRAG_SZ; 299*fcf3ce44SJohn Forte } else { 300*fcf3ce44SJohn Forte ec = ISNS_RSP_INTERNAL_ERROR; 301*fcf3ce44SJohn Forte } 302*fcf3ce44SJohn Forte } 303*fcf3ce44SJohn Forte 304*fcf3ce44SJohn Forte return (ec); 305*fcf3ce44SJohn Forte } 306*fcf3ce44SJohn Forte 307*fcf3ce44SJohn Forte int 308*fcf3ce44SJohn Forte pdu_reset_rsp( 309*fcf3ce44SJohn Forte isns_pdu_t **rsp, 310*fcf3ce44SJohn Forte size_t *pl, 311*fcf3ce44SJohn Forte size_t *sz 312*fcf3ce44SJohn Forte ) 313*fcf3ce44SJohn Forte { 314*fcf3ce44SJohn Forte int ec = pdu_reset(rsp, sz); 315*fcf3ce44SJohn Forte 316*fcf3ce44SJohn Forte if (ec == 0) { 317*fcf3ce44SJohn Forte /* leave space for status code */ 318*fcf3ce44SJohn Forte *pl = 4; 319*fcf3ce44SJohn Forte } 320*fcf3ce44SJohn Forte 321*fcf3ce44SJohn Forte return (ec); 322*fcf3ce44SJohn Forte } 323*fcf3ce44SJohn Forte 324*fcf3ce44SJohn Forte int 325*fcf3ce44SJohn Forte pdu_reset_scn( 326*fcf3ce44SJohn Forte isns_pdu_t **pdu, 327*fcf3ce44SJohn Forte size_t *pl, 328*fcf3ce44SJohn Forte size_t *sz 329*fcf3ce44SJohn Forte ) 330*fcf3ce44SJohn Forte { 331*fcf3ce44SJohn Forte int ec = pdu_reset(pdu, sz); 332*fcf3ce44SJohn Forte 333*fcf3ce44SJohn Forte if (ec == 0) { 334*fcf3ce44SJohn Forte *pl = 0; 335*fcf3ce44SJohn Forte } 336*fcf3ce44SJohn Forte 337*fcf3ce44SJohn Forte return (ec); 338*fcf3ce44SJohn Forte } 339*fcf3ce44SJohn Forte 340*fcf3ce44SJohn Forte int 341*fcf3ce44SJohn Forte pdu_reset_esi( 342*fcf3ce44SJohn Forte isns_pdu_t **pdu, 343*fcf3ce44SJohn Forte size_t *pl, 344*fcf3ce44SJohn Forte size_t *sz 345*fcf3ce44SJohn Forte ) 346*fcf3ce44SJohn Forte { 347*fcf3ce44SJohn Forte return (pdu_reset_scn(pdu, pl, sz)); 348*fcf3ce44SJohn Forte } 349*fcf3ce44SJohn Forte 350*fcf3ce44SJohn Forte int 351*fcf3ce44SJohn Forte pdu_update_code( 352*fcf3ce44SJohn Forte isns_pdu_t *pdu, 353*fcf3ce44SJohn Forte size_t *pl, 354*fcf3ce44SJohn Forte int code 355*fcf3ce44SJohn Forte ) 356*fcf3ce44SJohn Forte { 357*fcf3ce44SJohn Forte isns_resp_t *resp; 358*fcf3ce44SJohn Forte 359*fcf3ce44SJohn Forte resp = (isns_resp_t *)pdu->payload; 360*fcf3ce44SJohn Forte 361*fcf3ce44SJohn Forte /* reset the payload length */ 362*fcf3ce44SJohn Forte if (code != ISNS_RSP_SUCCESSFUL || *pl == 0) { 363*fcf3ce44SJohn Forte *pl = 4; 364*fcf3ce44SJohn Forte } 365*fcf3ce44SJohn Forte 366*fcf3ce44SJohn Forte resp->status = htonl(code); 367*fcf3ce44SJohn Forte 368*fcf3ce44SJohn Forte return (0); 369*fcf3ce44SJohn Forte } 370*fcf3ce44SJohn Forte 371*fcf3ce44SJohn Forte int 372*fcf3ce44SJohn Forte pdu_add_tlv( 373*fcf3ce44SJohn Forte isns_pdu_t **pdu, 374*fcf3ce44SJohn Forte size_t *pl, 375*fcf3ce44SJohn Forte size_t *sz, 376*fcf3ce44SJohn Forte uint32_t attr_id, 377*fcf3ce44SJohn Forte uint32_t attr_len, 378*fcf3ce44SJohn Forte void *attr_data, 379*fcf3ce44SJohn Forte int pflag 380*fcf3ce44SJohn Forte ) 381*fcf3ce44SJohn Forte { 382*fcf3ce44SJohn Forte int ec = 0; 383*fcf3ce44SJohn Forte 384*fcf3ce44SJohn Forte isns_pdu_t *new_pdu; 385*fcf3ce44SJohn Forte size_t new_sz; 386*fcf3ce44SJohn Forte 387*fcf3ce44SJohn Forte isns_tlv_t *attr_tlv; 388*fcf3ce44SJohn Forte uint8_t *payload_ptr; 389*fcf3ce44SJohn Forte uint32_t normalized_attr_len; 390*fcf3ce44SJohn Forte uint64_t attr_tlv_len; 391*fcf3ce44SJohn Forte 392*fcf3ce44SJohn Forte /* The attribute length must be 4-byte aligned. Section 5.1.3. */ 393*fcf3ce44SJohn Forte normalized_attr_len = (attr_len % 4) == 0 ? (attr_len) : 394*fcf3ce44SJohn Forte (attr_len + (4 - (attr_len % 4))); 395*fcf3ce44SJohn Forte attr_tlv_len = ISNS_TLV_ATTR_ID_LEN 396*fcf3ce44SJohn Forte + ISNS_TLV_ATTR_LEN_LEN 397*fcf3ce44SJohn Forte + normalized_attr_len; 398*fcf3ce44SJohn Forte /* Check if we are going to exceed the maximum PDU length. */ 399*fcf3ce44SJohn Forte if ((ISNSP_HEADER_SIZE + *pl + attr_tlv_len) > *sz) { 400*fcf3ce44SJohn Forte new_sz = *sz + RSP_PDU_FRAG_SZ; 401*fcf3ce44SJohn Forte new_pdu = (isns_pdu_t *)realloc(*pdu, new_sz); 402*fcf3ce44SJohn Forte if (new_pdu != NULL) { 403*fcf3ce44SJohn Forte *sz = new_sz; 404*fcf3ce44SJohn Forte *pdu = new_pdu; 405*fcf3ce44SJohn Forte } else { 406*fcf3ce44SJohn Forte ec = ISNS_RSP_INTERNAL_ERROR; 407*fcf3ce44SJohn Forte return (ec); 408*fcf3ce44SJohn Forte } 409*fcf3ce44SJohn Forte } 410*fcf3ce44SJohn Forte 411*fcf3ce44SJohn Forte attr_tlv = (isns_tlv_t *)malloc(attr_tlv_len); 412*fcf3ce44SJohn Forte (void) memset((void *)attr_tlv, 0, attr_tlv_len); 413*fcf3ce44SJohn Forte 414*fcf3ce44SJohn Forte attr_tlv->attr_id = htonl(attr_id); 415*fcf3ce44SJohn Forte 416*fcf3ce44SJohn Forte switch (attr_id) { 417*fcf3ce44SJohn Forte case ISNS_DELIMITER_ATTR_ID: 418*fcf3ce44SJohn Forte break; 419*fcf3ce44SJohn Forte 420*fcf3ce44SJohn Forte case ISNS_PORTAL_IP_ADDR_ATTR_ID: 421*fcf3ce44SJohn Forte case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID: 422*fcf3ce44SJohn Forte /* IPv6 */ 423*fcf3ce44SJohn Forte ASSERT(attr_len == sizeof (in6_addr_t)); 424*fcf3ce44SJohn Forte (void) memcpy(attr_tlv->attr_value, attr_data, 425*fcf3ce44SJohn Forte sizeof (in6_addr_t)); 426*fcf3ce44SJohn Forte break; 427*fcf3ce44SJohn Forte 428*fcf3ce44SJohn Forte case ISNS_EID_ATTR_ID: 429*fcf3ce44SJohn Forte case ISNS_ISCSI_NAME_ATTR_ID: 430*fcf3ce44SJohn Forte case ISNS_ISCSI_ALIAS_ATTR_ID: 431*fcf3ce44SJohn Forte case ISNS_PG_ISCSI_NAME_ATTR_ID: 432*fcf3ce44SJohn Forte (void) memcpy(attr_tlv->attr_value, (char *)attr_data, 433*fcf3ce44SJohn Forte attr_len); 434*fcf3ce44SJohn Forte break; 435*fcf3ce44SJohn Forte 436*fcf3ce44SJohn Forte default: 437*fcf3ce44SJohn Forte if (attr_len == 8) { 438*fcf3ce44SJohn Forte if (pflag == 0) { 439*fcf3ce44SJohn Forte /* 440*fcf3ce44SJohn Forte * In the iSNS protocol, there is only one 441*fcf3ce44SJohn Forte * attribute ISNS_TIMESTAMP_ATTR_ID which has 442*fcf3ce44SJohn Forte * 8 bytes length integer value and when the 443*fcf3ce44SJohn Forte * function "pdu_add_tlv" is called for adding 444*fcf3ce44SJohn Forte * the timestamp attribute, the value of 445*fcf3ce44SJohn Forte * the attribute is always passed in as its 446*fcf3ce44SJohn Forte * address, i.e. the pflag sets to 1. 447*fcf3ce44SJohn Forte * So it is an error when we get to this code 448*fcf3ce44SJohn Forte * path. 449*fcf3ce44SJohn Forte */ 450*fcf3ce44SJohn Forte ec = ISNS_RSP_INTERNAL_ERROR; 451*fcf3ce44SJohn Forte return (ec); 452*fcf3ce44SJohn Forte } else { 453*fcf3ce44SJohn Forte *(uint64_t *)attr_tlv->attr_value = 454*fcf3ce44SJohn Forte *(uint64_t *)attr_data; 455*fcf3ce44SJohn Forte } 456*fcf3ce44SJohn Forte } else if (attr_len == 4) { 457*fcf3ce44SJohn Forte if (pflag == 0) { 458*fcf3ce44SJohn Forte *(uint32_t *)attr_tlv->attr_value = 459*fcf3ce44SJohn Forte htonl((uint32_t)attr_data); 460*fcf3ce44SJohn Forte } else { 461*fcf3ce44SJohn Forte *(uint32_t *)attr_tlv->attr_value = 462*fcf3ce44SJohn Forte *(uint32_t *)attr_data; 463*fcf3ce44SJohn Forte } 464*fcf3ce44SJohn Forte } 465*fcf3ce44SJohn Forte break; 466*fcf3ce44SJohn Forte } 467*fcf3ce44SJohn Forte 468*fcf3ce44SJohn Forte attr_tlv->attr_len = htonl(normalized_attr_len); 469*fcf3ce44SJohn Forte /* 470*fcf3ce44SJohn Forte * Convert the network byte ordered payload length to host byte 471*fcf3ce44SJohn Forte * ordered for local address calculation. 472*fcf3ce44SJohn Forte */ 473*fcf3ce44SJohn Forte payload_ptr = (*pdu)->payload + *pl; 474*fcf3ce44SJohn Forte (void) memcpy(payload_ptr, attr_tlv, attr_tlv_len); 475*fcf3ce44SJohn Forte *pl += attr_tlv_len; 476*fcf3ce44SJohn Forte 477*fcf3ce44SJohn Forte /* 478*fcf3ce44SJohn Forte * The payload length might exceed the maximum length of a 479*fcf3ce44SJohn Forte * payload that isnsp allows, we will split the payload and 480*fcf3ce44SJohn Forte * set the size of each payload before they are sent. 481*fcf3ce44SJohn Forte */ 482*fcf3ce44SJohn Forte 483*fcf3ce44SJohn Forte free(attr_tlv); 484*fcf3ce44SJohn Forte attr_tlv = NULL; 485*fcf3ce44SJohn Forte 486*fcf3ce44SJohn Forte return (ec); 487*fcf3ce44SJohn Forte } 488*fcf3ce44SJohn Forte 489*fcf3ce44SJohn Forte isns_tlv_t * 490*fcf3ce44SJohn Forte pdu_get_source( 491*fcf3ce44SJohn Forte isns_pdu_t *pdu 492*fcf3ce44SJohn Forte ) 493*fcf3ce44SJohn Forte { 494*fcf3ce44SJohn Forte uint8_t *payload = &pdu->payload[0]; 495*fcf3ce44SJohn Forte uint16_t payload_len = pdu->payload_len; 496*fcf3ce44SJohn Forte isns_tlv_t *tlv = NULL; 497*fcf3ce44SJohn Forte 498*fcf3ce44SJohn Forte /* response code */ 499*fcf3ce44SJohn Forte if (pdu->func_id & ISNS_RSP_MASK) { 500*fcf3ce44SJohn Forte if (payload_len < 4) { 501*fcf3ce44SJohn Forte return (NULL); 502*fcf3ce44SJohn Forte } 503*fcf3ce44SJohn Forte payload += 4; 504*fcf3ce44SJohn Forte payload_len -= 4; 505*fcf3ce44SJohn Forte } 506*fcf3ce44SJohn Forte 507*fcf3ce44SJohn Forte if (payload_len > 8) { 508*fcf3ce44SJohn Forte tlv = (isns_tlv_t *)payload; 509*fcf3ce44SJohn Forte tlv->attr_id = ntohl(tlv->attr_id); 510*fcf3ce44SJohn Forte tlv->attr_len = ntohl(tlv->attr_len); 511*fcf3ce44SJohn Forte } 512*fcf3ce44SJohn Forte 513*fcf3ce44SJohn Forte return (tlv); 514*fcf3ce44SJohn Forte } 515*fcf3ce44SJohn Forte 516*fcf3ce44SJohn Forte isns_tlv_t * 517*fcf3ce44SJohn Forte pdu_get_key( 518*fcf3ce44SJohn Forte isns_pdu_t *pdu, 519*fcf3ce44SJohn Forte size_t *key_len 520*fcf3ce44SJohn Forte ) 521*fcf3ce44SJohn Forte { 522*fcf3ce44SJohn Forte uint8_t *payload = &pdu->payload[0]; 523*fcf3ce44SJohn Forte uint16_t payload_len = pdu->payload_len; 524*fcf3ce44SJohn Forte isns_tlv_t *tlv, *key; 525*fcf3ce44SJohn Forte 526*fcf3ce44SJohn Forte /* reset */ 527*fcf3ce44SJohn Forte *key_len = 0; 528*fcf3ce44SJohn Forte 529*fcf3ce44SJohn Forte /* response code */ 530*fcf3ce44SJohn Forte if (pdu->func_id & ISNS_RSP_MASK) { 531*fcf3ce44SJohn Forte if (payload_len <= 4) { 532*fcf3ce44SJohn Forte return (NULL); 533*fcf3ce44SJohn Forte } 534*fcf3ce44SJohn Forte payload += 4; 535*fcf3ce44SJohn Forte payload_len -= 4; 536*fcf3ce44SJohn Forte } 537*fcf3ce44SJohn Forte 538*fcf3ce44SJohn Forte /* skip the soure */ 539*fcf3ce44SJohn Forte if (payload_len >= 8) { 540*fcf3ce44SJohn Forte tlv = (isns_tlv_t *)payload; 541*fcf3ce44SJohn Forte payload += (8 + tlv->attr_len); 542*fcf3ce44SJohn Forte payload_len -= (8 + tlv->attr_len); 543*fcf3ce44SJohn Forte key = (isns_tlv_t *)payload; 544*fcf3ce44SJohn Forte while (payload_len >= 8) { 545*fcf3ce44SJohn Forte tlv = (isns_tlv_t *)payload; 546*fcf3ce44SJohn Forte tlv->attr_id = ntohl(tlv->attr_id); 547*fcf3ce44SJohn Forte tlv->attr_len = ntohl(tlv->attr_len); 548*fcf3ce44SJohn Forte if (tlv->attr_id == ISNS_DELIMITER_ATTR_ID) { 549*fcf3ce44SJohn Forte break; 550*fcf3ce44SJohn Forte } 551*fcf3ce44SJohn Forte *key_len += (8 + tlv->attr_len); 552*fcf3ce44SJohn Forte payload += (8 + tlv->attr_len); 553*fcf3ce44SJohn Forte payload_len -= (8 + tlv->attr_len); 554*fcf3ce44SJohn Forte } 555*fcf3ce44SJohn Forte } 556*fcf3ce44SJohn Forte 557*fcf3ce44SJohn Forte if (*key_len >= 8) { 558*fcf3ce44SJohn Forte return (key); 559*fcf3ce44SJohn Forte } 560*fcf3ce44SJohn Forte 561*fcf3ce44SJohn Forte return (NULL); 562*fcf3ce44SJohn Forte } 563*fcf3ce44SJohn Forte 564*fcf3ce44SJohn Forte isns_tlv_t * 565*fcf3ce44SJohn Forte pdu_get_operand( 566*fcf3ce44SJohn Forte isns_pdu_t *pdu, 567*fcf3ce44SJohn Forte size_t *op_len 568*fcf3ce44SJohn Forte ) 569*fcf3ce44SJohn Forte { 570*fcf3ce44SJohn Forte uint8_t *payload = &pdu->payload[0]; 571*fcf3ce44SJohn Forte uint16_t payload_len = pdu->payload_len; 572*fcf3ce44SJohn Forte isns_tlv_t *tlv, *op = NULL; 573*fcf3ce44SJohn Forte int found_op = 0; 574*fcf3ce44SJohn Forte 575*fcf3ce44SJohn Forte /* reset */ 576*fcf3ce44SJohn Forte *op_len = 0; 577*fcf3ce44SJohn Forte 578*fcf3ce44SJohn Forte /* response code */ 579*fcf3ce44SJohn Forte if (pdu->func_id & ISNS_RSP_MASK) { 580*fcf3ce44SJohn Forte if (payload_len < 4) { 581*fcf3ce44SJohn Forte return (NULL); 582*fcf3ce44SJohn Forte } 583*fcf3ce44SJohn Forte payload += 4; 584*fcf3ce44SJohn Forte payload_len -= 4; 585*fcf3ce44SJohn Forte } 586*fcf3ce44SJohn Forte 587*fcf3ce44SJohn Forte /* tlvs */ 588*fcf3ce44SJohn Forte while (payload_len >= 8) { 589*fcf3ce44SJohn Forte tlv = (isns_tlv_t *)payload; 590*fcf3ce44SJohn Forte if (found_op != 0) { 591*fcf3ce44SJohn Forte tlv->attr_id = ntohl(tlv->attr_id); 592*fcf3ce44SJohn Forte tlv->attr_len = ntohl(tlv->attr_len); 593*fcf3ce44SJohn Forte payload += (8 + tlv->attr_len); 594*fcf3ce44SJohn Forte payload_len -= (8 + tlv->attr_len); 595*fcf3ce44SJohn Forte } else { 596*fcf3ce44SJohn Forte payload += (8 + tlv->attr_len); 597*fcf3ce44SJohn Forte payload_len -= (8 + tlv->attr_len); 598*fcf3ce44SJohn Forte if (tlv->attr_id == ISNS_DELIMITER_ATTR_ID) { 599*fcf3ce44SJohn Forte /* found it */ 600*fcf3ce44SJohn Forte op = (isns_tlv_t *)payload; 601*fcf3ce44SJohn Forte *op_len = payload_len; 602*fcf3ce44SJohn Forte found_op = 1; 603*fcf3ce44SJohn Forte } 604*fcf3ce44SJohn Forte } 605*fcf3ce44SJohn Forte } 606*fcf3ce44SJohn Forte 607*fcf3ce44SJohn Forte if (*op_len >= 8) { 608*fcf3ce44SJohn Forte return (op); 609*fcf3ce44SJohn Forte } 610*fcf3ce44SJohn Forte 611*fcf3ce44SJohn Forte return (NULL); 612*fcf3ce44SJohn Forte } 613