4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
39 #include "isns_server.h"
43 #define ISNS_MAX_IOVEC 5
44 #define MAX_XID (2^16)
45 #define MAX_RCV_RSP_COUNT 10 /* Maximum number of unmatched xid */
46 #define ISNS_RCV_RETRY_MAX 2
47 #define IPV4_RSVD_BYTES 10
51 extern void dump_pdu2(isns_pdu_t
*);
68 iovec_t iovec
[ISNS_MAX_IOVEC
];
69 isns_pdu_t
*tmp_pdu_hdr
;
70 ssize_t bytes_received
, total_bytes_received
= 0;
72 uint8_t *tmp_pdu_data
;
74 uint16_t payload_len
= 0;
76 /* initialize to zero */
81 fds
.events
= (POLLIN
| POLLRDNORM
);
84 /* Receive the header first */
85 tmp_pdu_hdr
= (isns_pdu_t
*)malloc(ISNSP_HEADER_SIZE
);
86 if (tmp_pdu_hdr
== NULL
) {
89 (void) memset(&tmp_pdu_hdr
[0], 0, ISNSP_HEADER_SIZE
);
90 (void) memset(&iovec
[0], 0, sizeof (iovec_t
));
91 iovec
[0].iov_base
= (void *)tmp_pdu_hdr
;
92 iovec
[0].iov_len
= ISNSP_HEADER_SIZE
;
94 /* Initialization of the message header. */
95 bzero(&msg
, sizeof (msg
));
96 msg
.msg_iov
= &iovec
[0];
97 /* msg.msg_flags = MSG_WAITALL, */
100 /* Poll and receive the pdu header */
103 int err
= poll(&fds
, 1, rcv_timeout
* 1000);
107 bytes_received
= recvmsg(fd
, &msg
, MSG_WAITALL
);
110 } while (poll_cnt
< ISNS_RCV_RETRY_MAX
);
112 if (poll_cnt
>= ISNS_RCV_RETRY_MAX
) {
117 if (bytes_received
<= 0) {
122 total_bytes_received
+= bytes_received
;
124 payload_len
= ntohs(tmp_pdu_hdr
->payload_len
);
125 /* Verify the received payload len is within limit */
126 if (payload_len
> ISNSP_MAX_PAYLOAD_SIZE
) {
131 /* Proceed to receive additional data. */
132 tmp_pdu_data
= malloc(payload_len
);
133 if (tmp_pdu_data
== NULL
) {
137 (void) memset(&iovec
[0], 0, sizeof (iovec_t
));
138 iovec
[0].iov_base
= (void *)tmp_pdu_data
;
139 iovec
[0].iov_len
= payload_len
;
141 /* Initialization of the message header. */
142 bzero(&msg
, sizeof (msg
));
143 msg
.msg_iov
= &iovec
[0];
144 /* msg.msg_flags = MSG_WAITALL, */
147 /* poll and receive the pdu payload */
150 int err
= poll(&fds
, 1, rcv_timeout
* 1000);
154 bytes_received
= recvmsg(fd
, &msg
, MSG_WAITALL
);
157 } while (poll_cnt
< ISNS_RCV_RETRY_MAX
);
159 if (poll_cnt
>= ISNS_RCV_RETRY_MAX
) {
165 if (bytes_received
<= 0) {
171 total_bytes_received
+= bytes_received
;
173 *pdu_size
= ISNSP_HEADER_SIZE
+ payload_len
;
174 (*pdu
) = (isns_pdu_t
*)malloc(*pdu_size
);
181 (*pdu
)->version
= ntohs(tmp_pdu_hdr
->version
);
182 (*pdu
)->func_id
= ntohs(tmp_pdu_hdr
->func_id
);
183 (*pdu
)->payload_len
= payload_len
;
184 (*pdu
)->flags
= ntohs(tmp_pdu_hdr
->flags
);
185 (*pdu
)->xid
= ntohs(tmp_pdu_hdr
->xid
);
186 (*pdu
)->seq
= ntohs(tmp_pdu_hdr
->seq
);
187 (void) memcpy(&((*pdu
)->payload
), tmp_pdu_data
, payload_len
);
194 return (total_bytes_received
);
207 iovec_t iovec
[ISNS_MAX_IOVEC
];
208 struct msghdr msg
= { 0 };
214 /* Initialization of the message header. */
215 msg
.msg_iov
= &iovec
[0];
216 /* msg.msg_flags = MSG_WAITALL, */
220 * Initialize the pdu flags.
222 flags
= ISNS_FLAG_SERVER
;
223 flags
|= ISNS_FLAG_FIRST_PDU
;
226 * Initialize the pdu sequence id.
230 iovec
[0].iov_base
= (void *)pdu
;
231 iovec
[0].iov_len
= (ISNSP_HEADER_SIZE
);
233 payload
= pdu
->payload
;
236 pdu
->flags
= htons(flags
);
238 pdu
->payload_len
= htons(pl
);
243 /* set the payload for sending */
244 iovec
[1].iov_base
= (void *)payload
;
246 if (pl
> ISNSP_MAX_PAYLOAD_SIZE
) {
247 send_len
= ISNSP_MAX_PAYLOAD_SIZE
;
250 /* set the last pdu flag */
251 flags
|= ISNS_FLAG_LAST_PDU
;
253 iovec
[1].iov_len
= send_len
;
254 pdu
->payload_len
= htons(send_len
);
256 /* set the pdu flags */
257 pdu
->flags
= htons(flags
);
258 /* set the pdu sequence id */
259 pdu
->seq
= htons(seq
);
261 /* send the packet */
262 bytes_sent
= sendmsg(fd
, &msg
, 0);
264 /* get rid of the first pdu flag */
265 flags
&= ~(ISNS_FLAG_FIRST_PDU
);
267 /* next part of payload */
271 /* add the length of header for verification */
272 send_len
+= ISNSP_HEADER_SIZE
;
274 /* increase the sequence id by one */
276 } while (bytes_sent
== send_len
&& pl
> 0);
278 if (bytes_sent
== send_len
) {
281 isnslog(LOG_DEBUG
, "isns_send_pdu", "sending pdu failed.");
286 #define RSP_PDU_FRAG_SZ (ISNSP_MAX_PDU_SIZE / 10)
296 *rsp
= (isns_pdu_t
*)malloc(RSP_PDU_FRAG_SZ
);
298 *sz
= RSP_PDU_FRAG_SZ
;
300 ec
= ISNS_RSP_INTERNAL_ERROR
;
314 int ec
= pdu_reset(rsp
, sz
);
317 /* leave space for status code */
331 int ec
= pdu_reset(pdu
, sz
);
347 return (pdu_reset_scn(pdu
, pl
, sz
));
359 resp
= (isns_resp_t
*)pdu
->payload
;
361 /* reset the payload length */
362 if (code
!= ISNS_RSP_SUCCESSFUL
|| *pl
== 0) {
366 resp
->status
= htonl(code
);
387 isns_tlv_t
*attr_tlv
;
388 uint8_t *payload_ptr
;
389 uint32_t normalized_attr_len
;
390 uint64_t attr_tlv_len
;
392 /* The attribute length must be 4-byte aligned. Section 5.1.3. */
393 normalized_attr_len
= (attr_len
% 4) == 0 ? (attr_len
) :
394 (attr_len
+ (4 - (attr_len
% 4)));
395 attr_tlv_len
= ISNS_TLV_ATTR_ID_LEN
396 + ISNS_TLV_ATTR_LEN_LEN
397 + normalized_attr_len
;
398 /* Check if we are going to exceed the maximum PDU length. */
399 if ((ISNSP_HEADER_SIZE
+ *pl
+ attr_tlv_len
) > *sz
) {
400 new_sz
= *sz
+ RSP_PDU_FRAG_SZ
;
401 new_pdu
= (isns_pdu_t
*)realloc(*pdu
, new_sz
);
402 if (new_pdu
!= NULL
) {
406 ec
= ISNS_RSP_INTERNAL_ERROR
;
411 attr_tlv
= (isns_tlv_t
*)malloc(attr_tlv_len
);
412 (void) memset(attr_tlv
, 0, attr_tlv_len
);
414 attr_tlv
->attr_id
= htonl(attr_id
);
417 case ISNS_DELIMITER_ATTR_ID
:
420 case ISNS_PORTAL_IP_ADDR_ATTR_ID
:
421 case ISNS_PG_PORTAL_IP_ADDR_ATTR_ID
:
423 ASSERT(attr_len
== sizeof (in6_addr_t
));
424 (void) memcpy(attr_tlv
->attr_value
, attr_data
,
425 sizeof (in6_addr_t
));
428 case ISNS_EID_ATTR_ID
:
429 case ISNS_ISCSI_NAME_ATTR_ID
:
430 case ISNS_ISCSI_ALIAS_ATTR_ID
:
431 case ISNS_PG_ISCSI_NAME_ATTR_ID
:
432 (void) memcpy(attr_tlv
->attr_value
, (char *)attr_data
,
440 * In the iSNS protocol, there is only one
441 * attribute ISNS_TIMESTAMP_ATTR_ID which has
442 * 8 bytes length integer value and when the
443 * function "pdu_add_tlv" is called for adding
444 * the timestamp attribute, the value of
445 * the attribute is always passed in as its
446 * address, i.e. the pflag sets to 1.
447 * So it is an error when we get to this code
450 ec
= ISNS_RSP_INTERNAL_ERROR
;
453 *(uint64_t *)attr_tlv
->attr_value
=
454 *(uint64_t *)attr_data
;
456 } else if (attr_len
== 4) {
458 *(uint32_t *)attr_tlv
->attr_value
=
459 htonl((uint32_t)attr_data
);
461 *(uint32_t *)attr_tlv
->attr_value
=
462 *(uint32_t *)attr_data
;
468 attr_tlv
->attr_len
= htonl(normalized_attr_len
);
470 * Convert the network byte ordered payload length to host byte
471 * ordered for local address calculation.
473 payload_ptr
= (*pdu
)->payload
+ *pl
;
474 (void) memcpy(payload_ptr
, attr_tlv
, attr_tlv_len
);
478 * The payload length might exceed the maximum length of a
479 * payload that isnsp allows, we will split the payload and
480 * set the size of each payload before they are sent.
494 uint8_t *payload
= &pdu
->payload
[0];
495 uint16_t payload_len
= pdu
->payload_len
;
496 isns_tlv_t
*tlv
= NULL
;
499 if (pdu
->func_id
& ISNS_RSP_MASK
) {
500 if (payload_len
< 4) {
507 if (payload_len
> 8) {
508 tlv
= (isns_tlv_t
*)payload
;
509 tlv
->attr_id
= ntohl(tlv
->attr_id
);
510 tlv
->attr_len
= ntohl(tlv
->attr_len
);
522 uint8_t *payload
= &pdu
->payload
[0];
523 uint16_t payload_len
= pdu
->payload_len
;
524 isns_tlv_t
*tlv
, *key
;
530 if (pdu
->func_id
& ISNS_RSP_MASK
) {
531 if (payload_len
<= 4) {
539 if (payload_len
>= 8) {
540 tlv
= (isns_tlv_t
*)payload
;
541 payload
+= (8 + tlv
->attr_len
);
542 payload_len
-= (8 + tlv
->attr_len
);
543 key
= (isns_tlv_t
*)payload
;
544 while (payload_len
>= 8) {
545 tlv
= (isns_tlv_t
*)payload
;
546 tlv
->attr_id
= ntohl(tlv
->attr_id
);
547 tlv
->attr_len
= ntohl(tlv
->attr_len
);
548 if (tlv
->attr_id
== ISNS_DELIMITER_ATTR_ID
) {
551 *key_len
+= (8 + tlv
->attr_len
);
552 payload
+= (8 + tlv
->attr_len
);
553 payload_len
-= (8 + tlv
->attr_len
);
570 uint8_t *payload
= &pdu
->payload
[0];
571 uint16_t payload_len
= pdu
->payload_len
;
572 isns_tlv_t
*tlv
, *op
= NULL
;
579 if (pdu
->func_id
& ISNS_RSP_MASK
) {
580 if (payload_len
< 4) {
588 while (payload_len
>= 8) {
589 tlv
= (isns_tlv_t
*)payload
;
591 tlv
->attr_id
= ntohl(tlv
->attr_id
);
592 tlv
->attr_len
= ntohl(tlv
->attr_len
);
593 payload
+= (8 + tlv
->attr_len
);
594 payload_len
-= (8 + tlv
->attr_len
);
596 payload
+= (8 + tlv
->attr_len
);
597 payload_len
-= (8 + tlv
->attr_len
);
598 if (tlv
->attr_id
== ISNS_DELIMITER_ATTR_ID
) {
600 op
= (isns_tlv_t
*)payload
;
601 *op_len
= payload_len
;